| SVG-GD documentation | Contained in the SVG-GD distribution. |
Provide (as seamless as possible) an SVG wrapper to the GD API in order to provide SVG output of images generate with the Perl GD module
use GD; use SVG::GD; $im = new GD::Image(100,50); # allocate black -- this will be our background $black = $im->colorAllocate(0, 0, 0); # allocate white $white = $im->colorAllocate(255, 255, 255); # allocate red $red = $im->colorAllocate(255, 0, 0); # allocate blue $blue = $im->colorAllocate(0,0,255); #Inscribe an ellipse in the image $im->arc(50, 25, 98, 48, 0, 360, $white); # Flood-fill the ellipse. Fill color is red, and will replace the # black interior of the ellipse $im->fill(50, 21, $red); binmode STDOUT; # print the image to stdout print $im->png;
returns SVG::GD::Font::Tiny
returns SVG::GD::Font::Small();
returns SVG::GD::Font::Bold();
Returns SVG::GD::Font::Large()
Returns SVG::GD::Font::Giant()
Does nothing at this time
retrieve the style in SVG format for predefined fomts
set a pixel to a colour Because SVG does not understand pixels, this method has to be faked. We know from the image size what is meant by a pixel, so we create a rectangle of size 1x1 and give it a colour
Allocate the colour to a variable (red,green,blue)
for an rbg tripplet, either returns the index for the colour or generates a new index for that colour
return the number of allocated colors
check for the existance of an exact color
returns the closest colour to the RGB triplet being submitted
Draw a line between 2 points
Draw a filled rectangle.
Draw a rectangle.
Draw an arc. Only supports closed arcs at present. Note that we will ultimately need to differenciate between an arc and a circle.
Draw a polygon defined by ab SVG::GD::Polygon object
Draw an empty polygon
write a text string
write a character
write a character upwards
Return the red,green,blue array for an allocated colour
replace the gif writing request with an svg writing request
Return the binary image in PNG format
Return the binary image in JPEG format
Return the binary image in GIF format Note that some versions of SVG::GD do not support this method
| SVG-GD documentation | Contained in the SVG-GD distribution. |
package SVG::GD; $VERSION = '0.20'; no strict 'refs'; use SVG; use Exporter; use warnings;
BEGIN { #first, let's re-map the GD::Image methods to somewhere else safe. #nb we will also have to do this with the GD::Font methods # *SVG::HGD::Image::new = \&GD::Image::new; # *SVG::HGD::gdSmallFont =\&GD::gdSmallFont; # *SVG::HGD::gdLargeFont =\&GD::gdLargeFont; # *SVG::HGD::gdMediumBoldFont =\&GD::gdMediumBoldFont; # *SVG::HGD::gdTinyFont =\&GD::gdTinyFont; # *SVG::HGD::gdGiantFont =\&GD::gdGiantFont; # *SVG::HGD::Image::_make_filehandle =\&GD::Image::_make_filehandle; # *SVG::HGD::Image::new =\&GD::Image::new; # *SVG::HGD::Image::newTrueColor =\&GD::Image::newTrueColor; # *SVG::HGD::Image::newPalette =\&GD::Image::newPalette; # *SVG::HGD::Image::newFromPng =\&GD::Image::newFromPng; # *SVG::HGD::Image::newFromJpeg =\&GD::Image::newFromJpeg; # *SVG::HGD::Image::newFromXbm =\&GD::Image::newFromXbm; # *SVG::HGD::Image::newFromGd =\&GD::Image::newFromGd; # *SVG::HGD::Image::newFromGd2 =\&GD::Image::newFromGd2; # *SVG::HGD::Image::newFromGd2Part =\&GD::Image::newFromGd2Part; # *SVG::HGD::Image::ellipse =\&GD::Image::ellipse; # *SVG::HGD::Image::clone =\&GD::Image::clone; # *SVG::HGD::Polygon::new =\&GD::Polygon::new; # *SVG::HGD::Polygon::DESTROY =\&GD::Polygon::DESTROY; # *SVG::HGD::Polygon::addPt =\&GD::Polygon::addPt; # *SVG::HGD::Polygon::getPt =\&GD::Polygon::getPt; # *SVG::HGD::Polygon::setPt =\&GD::Polygon::setPt; # *SVG::HGD::Polygon::length =\&GD::Polygon::length; # *SVG::HGD::Polygon::vertices =\&GD::Polygon::vertices; # *SVG::HGD::Polygon::bounds =\&GD::Polygon::bounds; # *SVG::HGD::Polygon::deletePt =\&GD::Polygon::deletePt; # *SVG::HGD::Polygon::offset =\&GD::Polygon::offset; # *SVG::HGD::Polygon::map =\&GD::Polygon::map; # *SVG::HGD::Image::polygon =\&GD::Image::polygon; # *SVG::HGD::Polygon::toPt =\&GD::Polygon::toPt; # *SVG::HGD::Polygon::transform =\&GD::Polygon::transform; # *SVG::HGD::Polygon::scale =\&GD::Polygon::scale; *GD::Font:: = *SVG::GD::Font::; *GD::Image:: = *SVG::GD::Image::; } use vars qw/$VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS/; our $tinyfontsize='5'; our $smallfontsize='7'; our $mediumfontsize='10'; our $largefontsize='12'; our $giantfontsize='16'; our $font = {}; our $fontindex = 0; @ISA = qw/Exporter/; @EXPORT = qw/ gdBrushed gdDashSize gdMaxColors gdStyled gdStyledBrushed gdTiled gdTransparent gdSmallFont gdMediumBoldFont gdLargeFont gdGiantFont /; @EXPORT_OK = qw/ GD_CMP_IMAGE GD_CMP_NUM_COLORS GD_CMP_COLOR GD_CMP_SIZE_X GD_CMP_SIZE_Y GD_CMP_TRANSPARENT GD_CMP_BACKGROUND GD_CMP_INTERLACE GD_CMP_TRUECOLOR /; %EXPORT_TAGS = ('cmp' => [ qw/ GD_CMP_IMAGE GD_CMP_NUM_COLORS GD_CMP_COLOR GD_CMP_SIZE_X GD_CMP_SIZE_Y GD_CMP_TRANSPARENT GD_CMP_BACKGROUND GD_CMP_INTERLACE GD_CMP_TRUECOLOR / ] );
#font control sub SVG::GD::gdTinyFont { return SVG::GD::Font::Tiny(); } #font control
sub SVG::GD::gdSmallFont { return SVG::GD::Font::Small(); }
#font control sub SVG::GD::gdMediumBoldFont { return SVG::GD::Font::MediumBold(); }
#font control sub SVG::GD::gdLargeFont { return SVG::GD::Font::Large(); }
#font control sub SVG::GD::gdGiantFont { return SVG::GD::Font::Giant(); }
sub SVG::GD::gdBrushed { return ''; } # # # OO font support (encountered in GD::Graph::radar) # # package SVG::GD::Font; use strict; use Data::Dumper; use warnings; sub registerFont($) { my $size = shift; $fontindex++; $font->{$fontindex}->{fontheight} = $size; $font->{$fontindex}->{fontstyle} = {'font-size'=>$size}; return $fontindex; } sub Giant { my $class = shift; my $size = $giantfontsize; SVG::GD::Font::registerFont($size); } sub Large { my $class = shift; my $size = $largefontsize; SVG::GD::Font::registerFont($size); } sub Medium { my $class = shift; my $size = $mediumfontsize; SVG::GD::Font::registerFont($size); } sub MediumBold { my $class = shift; my $size = $mediumfontsize; SVG::GD::Font::registerFont($size); } sub Small { my $class = shift; my $size = $smallfontsize; SVG::GD::Font::registerFont($size); } sub Tiny { my $class = shift; my $size = $tinyfontsize; SVG::GD::Font::registerFont($size); } sub height { my $id = shift; return 10; } sub width { my $myfont = shift; return 8; }
sub getSVGstyle { my $myfont = shift; if (eval{defined $font->{$myfont}->{fontstyle} eq 'HASH'}) { return %{$font->{$myfont}->{fontstyle}}; } else { return (); } } # # SVG::GD::Image # package SVG::GD::Image; use warnings; use strict; #constructor sub SVG::GD::Image::new { my $class = shift; my $self = {}; bless $self, $class; #$self->{_GD_} = new SVG::HGD::Image(@_) # || print STDERR "Quitting. Unable to construct new SVG::HGD::Image # object using SVG::GD!: $!\n"; #return undef unless defined $self->{_GD_}; my ($val_1,$val_2,$val_3) = @_; #do we have drawing sizes? if ($val_1 =~ /^\d+$/ && $val_2 =~ /^\d+$/) { $self->{_ATTRIBUTES_}->{width} = $val_1; $self->{_ATTRIBUTES_}->{height} = $val_2; $self->{_ATTRIBUTES_}->{-truecolor} = $val_3 if defined $val_3; } #do we have a valid filename? elsif (-r $val_1) { $self->{_ATTRIBUTES_}->{FILENAME} = $val_1; } #do we have a file reference? elsif (ref $val_1) { $self->{_ATTRIBUTES_}->{FILEHANDLE} = $val_1; } #then we have raw image data. elsif (defined $val_1) { $self->{_ATTRIBUTES_}->{IMAGEDATA} = $val_1; } else {return undef} #build the svg drawing $self->{_SVG_} = SVG->new(%{$self->{_ATTRIBUTES_}}); $self->{scratch}->{index_colours} = 0; $self->{_COLOUR_}->{named} = { white => {svg=>'white',rgb=>'white'}, lgray => {svg=>'gray',rgb=>'lgray'}, gray => {svg=>'gray',rgb=>'gray'}, dgray => {svg=>'gray',rgb=>'dgray'}, black =>{svg=>'black',rgb=>'black'}, lblue =>{svg=>'lightblue',rgb=>'lblue'}, blue => {svg=>'blue',rgb=>'blue'}, dblue =>, {svg=>'darkblue',rgb=>'dblue'}, gold => {svg=>'gold',rgb=>'gold'}, lyellow =>{svg=>'yellow',rgb=>'lyellow'}, yellow =>{svg=>'yellow',rgb=>'yellow'}, dyellow =>{svg=>'gold',rgb=>'gold'}, lgreen =>{svg=>'mintgreen',rgb=>'lgreen'}, green =>{svg=>'green',rgb=>'green'}, dgreen =>{svg=>'darkgreen',rgb=>'dgreen'}, lred =>{svg=>'red',rgb=>'dred'}, red => {svg=>'red',rgb=>'red'}, dred =>{svg=>'red',rgb=>'dred'}, lpurple =>{svg=>'gold',rgb=>'gold'}, purple => {svg=>'purple',rgb=>'purple'}, dpurple =>{svg=>'dpurple ',rgb=>'dpurple'}, lorange =>{svg=>'lorange ',rgb=>'lorange'}, orange => {svg=>'orange',rgb=>'orange'}, pink => {svg=>'pink',rgb=>'pink'}, dpink =>{svg=>'pink',rgb=>'dpink'}, marine =>{svg=>'navy',rgb=>'marine'}, cyan => {svg=>'cyan',rgb=>'cyan'}, lbrown =>{svg=>'brown',rgb=>'lbrown'}, dbrown => {svg=>'brown',rgb=>'dbrown'}, }; return $self; } #-------------------- #Wrapper methods
sub SVG::GD::Image::setPixel($$$$) { my $self = shift; my ($x,$y,$colour) = @_; $self->{_SVG_}->rect(x=>$x,y=>$y, width=>1,height=>1, fill=>$self->getColour($colour)); # $self->{_GD_}->setPixel($x,$y,$colour); }
sub SVG::GD::Image::colorAllocate($$$$) { my $self = shift; my ($red,$green,$blue) = @_; # my $code = $self->{_GD_}->colorAllocate($red,$green,$blue); #if we get an rgb triplet, handle as an rgb triplet my $code = $self->{index_colour}++; if (defined $green && defined $blue) { #$code = "$red.$green.$blue" if (defined $green && defined $blue); $self->{_COLOUR_}->{$code}->{svg} = $self->{_SVG_}->colorAllocate($red,$green,$blue); $self->{_COLOUR_}->{$code}->{rgb} = [$red,$green,$blue]; } #otherwise assume this is a named colour. else { $code = $red; $self->{_COLOUR_}->{$code}->{rgb} = [$code]; $self->{_COLOUR_}->{$code}->{svg} = [$code]; } return $code; }
*SVG::GD::Image::colorResolve = \&SVG::GD::Image::colorAllocate;
sub SVG::GD::Image::colorsTotal ($) { my $self = shift; return scalar(keys %{$self->{_COLOUR_}}); }
sub SVG::GD::Image::colorExact ($$) { my $self = shift; my $colour = shift; return 1 if $self->{_COLOUR_}->{$colour}; return -1; }
sub SVG::GD::Image::colorClosest ($$$$) { my $self = shift; my ($red,$green,$blue) = @_; my $value = {}; map { my $cc = $_; #calculate the least-square distance my ($dr,$dg,$db) = ( $red * $red - $self->{_COLOUR_}->{$cc}->[0] * $self->{_COLOUR_}->{$cc}->[0], $green * $blue - $self->{_COLOUR_}->{$cc}->[1] * $self->{_COLOUR_}->{$cc}->[1], $blue * $blue - $self->{_COLOUR_}->{$cc}->[2] * $self->{_COLOUR_}->{$cc}->[2], ); $value->{$dr+$dg+$db} = $cc; } keys %{$self->{_COLOUR_}}; # my @array = sort {$a<=>$b} keys %$value; my $leastval = shift @array; my $code = $value->{$leastval}; }
sub SVG::GD::Image::line($$$$$$) { my $self = shift; my ($x1,$y1,$x2,$y2,$colour) = @_; # $self->{_GD_}->line(@_); $self->{_SVG_}->line(x1=>$x1,x2=>$x2,y1=>$y1,y2=>$y2, stroke=>$self->getColour($colour)); } sub SVG::GD::Image::dashedLine($$$$$$) { my $self = shift; my ($x1,$y1,$x2,$y2,$colour) = @_; # $self->{_GD_}->dashedLine(@_); $self->{_SVG_}->line(x1=>$x1,x2=>$x2,y1=>$y1,y2=>$y2, stroke=>$self->getColour($colour)); }
sub SVG::GD::Image::filledRectangle($$$$$$$) { my $self = shift; my ($x1,$y1,$x2,$y2,$colour) = @_; # $self->{_GD_}->filledRectangle(@_); $self->{_SVG_}->rect(x=>$x1,y=>$y1, width=>$x2-$x1,height=>$y2-$y1, fill=>$self->getColour($colour), stroke=>$self->getColour($colour)); }
sub SVG::GD::Image::rectangle($$$$$$$) { my $self = shift; my ($x1,$y1,$x2,$y2,$colour) = @_; # $self->{_GD_}->rectangle(@_); $self->{_SVG_}->rect(x=>$x1,y=>$y1, width=>$x2-$x1,height=>$y2-$y1,fill=>'none', stroke=>$self->getColour($colour)); }
sub SVG::GD::Image::arc($$$$$$$$) { my $self = shift; my ($cx,$cy,$width,$height,$start,$end,$colour) = @_; $self->{_SVG_}->ellipse(cx=>$cx,cy=>$cy, rx=>$width/2,ry=>$height/2,fill=>'none', stroke=>$self->getColour($colour)); # return $self->{_GD_}->arc(@_); }
sub SVG::GD::Image::filledPolygon ($$$) { my $self = shift; my $poly = shift; my $fill = shift; my ($x,$y) = ([],[]); foreach my $set (@{$poly->{points}}) { my ($myx,$myy) = ($set->[0],$set->[1]); push @$x,$myx; push @$y,$myy; } my $points = $self->{_SVG_}-> get_path(x=>$x, y=>$y, -type=>'path', -closed=>'true'); $self->{_SVG_}->path(%$points,fill=>$self->getColour($fill)); }
sub SVG::GD::Image::polygon ($$$) { my $self = shift; my $poly = shift; my $stroke = shift; my ($x,$y) = ([],[]); foreach my $set (@{$poly->{points}}) { my ($myx,$myy) = ($set->[0],$set->[1]); push @$x,$myx; push @$y,$myy; } my $points = $self->{_SVG_}-> get_path(x=>$x, y=>$y, -type=>'path', -closed=>'true'); $self->{_SVG_}->path(%$points,stroke=>$self->getColour($stroke),fill=>'none'); } #string methods
sub SVG::GD::Image::string ($$$$$$) { my $self = shift; my ($myfont,$x,$y,$text,$colour) = @_; # $self->{_GD_}->string(@_); $self->{_SVG_}->text( 'baseline-shift'=>'sub', style=>{ SVG::GD::Font::getSVGstyle($myfont), fill=>$self->getColour($colour), }, x=>$x, y=>$y)->tspan(dy=>'1em') ->cdata($text); }
*SVG::GD::Image::char = \&SVG::GD::Image::string;
sub SVG::GD::Image::stringUp ($$$$$$) { my $self = shift; my ($myfont,$x,$y,$text,$colour) = @_; # $self->{_GD_}->string(@_); $self->{_SVG_}->text( style=>{'writing-mode'=>'tb', SVG::GD::Font::getSVGstyle($myfont), fill=>$self->getColour($colour), }, x=>$x,y=>$y, )->cdata($text); } *SVG::GD::Image::charUp = \&SVG::GD::Image::stringUp; #--------------- #internal methods sub SVG::GD::Image::getRGB($$) { my $self = shift; my $colour = shift; return $self->{_COLOUR_}->{$colour}->{rgb}; } sub SVG::GD::Image::getColour($$) { my $self = shift; my $colour = shift; return $self->{_COLOUR_}->{$colour}->{svg}; }
sub SVG::GD::Image::rgb ($$) { my $self = shift; my $col = shift; return @{$self->getRBG($col)}; }
sub SVG::GD::Image::svg ($) { my $self = shift; return $self->{_SVG_}->xmlify; }
sub SVG::GD::Image::png ($) { my $self = shift; return $self->svg; # return $self->{_GD_}->png; }
sub SVG::GD::Image::wbmp ($$) { my $self = shift; # return $self->{_GD_}->wbmp(@_); }
sub SVG::GD::Image::gif ($) { my $self = shift; return $self->svg; } #------------------ #ignored methods that are meaningless #or too difficult to implement sub SVG::GD::Image::interlaced ($) { my $self = shift; # $self->{_GD_}->interlaced(@_); } sub SVG::GD::Image::transparent ($$) { my $self = shift; my $colour = shift; # $self->{_GD_}->transparent($colour) } sub SVG::GD::Image::fill ($$$$) { my $self = shift; my ($x,$y,$colour) = @_; # $self->{_GD_}->fill(@_); } sub SVG::GD::Image::fillToBorder ($$$$) { my $self = shift; my ($x,$y,$colour) = @_; # $self->{_GD_}->fillToBorder(@_); } ############################################################################ # # new methods on GD::Image # ############################################################################ sub SVG::GD::Image::polyline ($$$) { my $self = shift; # the GD::Image my $p = shift; # the GD::Polyline (or GD::Polygon) my $c = shift; # the color my @points = $p->vertices(); my $p1 = shift @points; my $p2; while ($p2 = shift @points) { $self->line(@$p1, @$p2, $c); $p1 = $p2; } } sub GD::Image::polydraw ($$$) { my $self = shift; # the GD::Image my $p = shift; # the GD::Polyline or GD::Polygon my $c = shift; # the color return $self->polyline($p, $c) if $p->isa('GD::Polyline'); return $self->polygon($p, $c); } sub setBrush ($$) { my $self = shift; my $brush = shift; return "Sorry..Ignoring this command. Unable to setBrush with this version of SVG::GD"; }