SVG(3pm)
SVG(3pm) โ GD::SVG ๐ฆโจ
User Contributed Perl Documentation ยท SVG(3pm)
โจ NAME โจ
GD::SVG โ bestie, this seamlessly enables SVG output from scripts written using GD. No cap. ๐
๐ SYNOPSIS ๐
# use GD;
use GD::SVG;
# my $img = GD::Image->new();
my $img = GD::SVG::Image->new();
# $img->png();
$img->svg();
okay so look at that. the diff is right there. one line. that's it. ๐ซถ
๐ DESCRIPTION ๐
GD::SVG painlessly enables scripts that utilize GD to export scalable vector graphics (SVG). It pulls this off by wrapping SVG.pm with GD-styled method calls. โจ
And the way you turn it on?? literally just:
- swap your
use GDcall foruse GD::SVG - and fix up your initial
newmethod calls
that's the whole vibe. slay. ๐
๐ธ EXPORTS ๐ธ
GD::SVG exports the same methods as GD itself, overriding those methods. Same energy, different output. ๐
๐ฆ USAGE ๐ฆ
First things first, bestie. To generate SVG output from your script using GD::SVG, you gotta do this:
# use GD;
use GD::SVG;
Then, every call to the package classes that GD implements should get swapped over to GD::SVG. Like so:
GD::Image becomes GD::SVG::Image
GD::Font becomes GD::SVG::Font
periodt. ๐
๐ DYNAMICALLY SELECTING SVG OUTPUT ๐
Want your script to be able to dynamically pick between PNG or JPEG output (via GD) and SVG output (via GD::SVG)? then you need to put your use statement inside an eval. ๐
In the example below, each of the available classes gets created at the top of the script for convenience, along with the image output type:
my $package = shift;
eval "use $package";
my $image_pkg = $package . '::Image';
my $font_pkg = $package . '::Font';
# Creating new images thus becomes
my $image = $image_pkg->new($width,$height);
# Establish the image output type
my $image_type;
if ($package = 'GD::SVG') {
$image_type = 'svg';
} else {
$image_type = 'png';
}
Last step, babes: change all your GD::Image and GD::Font references to $image_pkg-> and $font_pkg->, respectively.
GD::Image->new() becomes $image_pkg->new()
GD::Font->Large() becomes $font_pkg->Large()
Good news tho โ the GD::Polygon and GD::Polyline classes work with GD::SVG without modification. iconic. โจ
Heads up: if you make heavy use of GD's exported methods, it may also be necessary to add () to the end of method names to avoid bareword compilation errors. That's the price you pay for using exported functions! ๐
๐ IMPORTANT NOTES ๐
Okay so real talk for a sec. ๐
GD::SVG does not directly generate SVG โ it relies upon SVG.pm to do that. It is not intended to supplant SVG.pm. And furthermore, since GD::SVG is, in essence, an API to an API, it may not be suitable for applications where speed is of the essence. In those cases, GD::SVG may provide a short-term solution while scripts are re-written to enable more direct output of SVG. โณ
Many of the GD::SVG methods accept additional parameters (which are in turn reflected in the SVG.pm API) that are not supported in GD. Look through the remainder of this document for options on specific [things]. In addition, several functions have yet to be mapped to SVG.pm calls. Please see the section below regarding GD functions that are missing or altered in GD::SVG. ๐ง
A similar module (SVG::GD) implements a similar wrapper around GD. Please see the section at the bottom of this document that compares GD::SVG to SVG::GD. ๐ซถ
๐ PREREQUISITES ๐
GD::SVG requires:
- Ronan Oger's
SVG.pmmodule - Lincoln Stein's
GD.pmmodule libgdand its dependencies
๐ GENERAL DIFFICULTIES IN TRANSLATING GD TO SVG ๐
These are the primary weaknesses of GD::SVG. not gonna sugarcoat it. ๐ญ
SVG requires unique identifiers for each element
Each element in an SVG image requires a unique identifier. In general, GD::SVG handles this by automatically generating unique random numbers. ๐ฒ
On top of the typical parameters for GD methods, GD::SVG methods allow a user to pass an optional id parameter for naming the object.
Direct calls to the GD package will fail
You must change direct calls to the classes that GD invokes:
GD::Image->new() should be changed to GD::SVG::Image->new()
See the documentation above for how to dynamically switch between packages. ๐
raster fill() and fillToBorder() not supported
As SVG documents are not inherently aware of their canvas, the flood fill methods are not currently supported. ๐ซ
getPixel() not supported.
Although setPixel() works as expected, its counterpart getPixel() is not supported. I plan to support this method in a future release. ๐ฎ
No support for generation of images from filehandles or raw data
GD::SVG works only with scripts that generate images directly in the code using the GD->new(height,width) approach. newFrom() methods are not currently supported.
Tiled fills are not supported
Any functions passed gdTiled objects will die. ๐
Styled and Brushed lines only partially implemented
Calls to the gdStyled and gdBrushed functions via a rather humorous kludge (and simplification). Depending on the complexity of the brush, they may behave slightly differently to radically differently from their behavior under GD. You have been warned. โ ๏ธ
See the documentation sections for the methods that set these options (setStyle(), setBrush(), and setTransparent()).
See below for a full list of methods that have not yet been implemented. ๐
๐ญ WHEN THINGS GO WRONG ๐ญ
GD is a complicated module. Translating GD methods into those required to draw in SVG are not always direct. You may or may not get the output you expect. In general, some tweaking of image parameters (like text height and width) may be necessary. ๐ซ
If your script doesn't work as expected, first check the list of methods that GD::SVG provides. Due to differences in the nature of SVG images, not all GD methods have been implemented in GD::SVG.
If your image doesn't look as expected, try tweaking specific aspects of image generation. In particular, check for instances where you calculate dimensions of items on the fly like font->height. In SVG, the values of fonts are defined explicitly. ๐
๐ GD FUNCTIONS MISSING FROM GD::SVG ๐
The following GD functions have not yet been incorporated into GD::SVG. If you attempt to use one of these functions (and you have enabled debug warnings via the new() method), GD::SVG will print a warning to STDERR. ๐ข
Creating image objects:
GD::Image->newPalette([$width,$height])
GD::Image->newTrueColor([$width,$height])
GD::Image->newFromPng($file, [$truecolor])
GD::Image->newFromPngData($data, [$truecolor])
GD::Image->newFromJpeg($file, [$truecolor])
GD::Image->newFromJpegData($data, [$truecolor])
GD::Image->newFromXbm($file)
GD::Image->newFromWMP($file)
GD::Image->newFromGd($file)
GD::Image->newFromGdData($data)
GD::Image->newFromGd2($file)
GD::Image->newFromGd2Data($data)
GD::Image->newFromGd2Part($file,srcX,srcY,width,height)
GD::Image->newFromXpm($filename)
Image methods:
$gddata = $image->gd
$gd2data = $image->gd2
$wbmpdata = $image->wbmp([$foreground])
Color control methods:
$image->colorAllocateAlpha()
$image->colorClosest()
$image->colorClosestHWB()
$image->getPixel()
$image->transparent()
Special Colors:
$image->setBrush() (semi-supported, with kludge)
$image->setStyle() (semi-supported, with kludge)
gdTiled
$image->setAntialiased()
gdAntiAliased()
$image->setAntiAliasedDontBlend()
Drawing methods:
$image->dashedLine()
$image->fill()
$image->fillToBorder()
Image copying methods
None of the image copying methods are yet supported
Image transformation methods
None of the image transformation methods are yet supported
Character and string drawing methods
$image->stringUp() - incompletely supported - broken
$image->charUp()
$image->stringFT()
Alpha Channels
$image->alphaBlending()
$image->saveAlpha()
Miscellaneous image methods
$image->isTrueColor()
$image->compare($image2)
$image->clip()
$image->boundsSafe()
GD::Polyline
Supported without modifications
Font methods:
$font->nchars()
$font->offset()
๐ง GROUPING FUNCTIONS GD::SVG ๐ง
GD::SVG supports three additional methods that provide the ability to recursively group objects. nesting, but make it art. ๐จ
$this->startGroup([$id,\%style]), $this->endGroup()
These methods start and end a group in a procedural manner. Once a group is started, all further drawing will be appended to the group until endGroup() is invoked. You may optionally pass a string ID and an SVG styles hash to startGroup. ๐ซ
$group = $this->newGroup([$id,\%style])
This method returns a GD::Group object, which has all the behaviors of a GD::SVG object except that it draws within the current group. You can invoke this object's drawing methods to draw into a group. The group is closed once the object goes out of scope. While the object is open, invoking drawing methods on the parent GD::SVG object will also draw into the group until it goes out of scope. ๐
Here is an example of using grouping in the procedural way:
use GD::SVG;
my $img = GD::SVG::Image->new(500,500);
my $white = $img->colorAllocate(255,255,255);
my $black = $img->colorAllocate(0,0,0);
my $blue = $img->colorAllocate(0,0,255);
my $red = $img->colorAllocate(255,0,0);
$img->startGroup('circle in square');
$img->rectangle(100,100,400,400,$blue);
$img->startGroup('circle and boundary');
$img->filledEllipse(250,250,200,200,$red);
$img->ellipse(250,250,200,200,$black);
$img->endGroup;
$img->endGroup;
print $img->svg;
Here is an example of using grouping with the GD::Group object:
...
my $g1 = $img->newGroup('circle in square');
$g1->rectangle(100,100,400,400,$blue);
my $g2 = $g1->startGroup('circle and boundary');
$g2->filledEllipse(250,250,200,200,$red);
$g2->ellipse(250,250,200,200,$black);
print $img->svg;
Finally, here is a fully worked example of using the GD::Simple module to make the syntax cleaner:
#!/usr/bin/perl
use strict;
use GD::Simple;
GD::Simple->class('GD::SVG');
my $img = GD::Simple->new(500,500);
$img->bgcolor('white');
$img->fgcolor('blue');
my $g1 = $img->newGroup('circle in square');
$g1->rectangle(100,100,400,400);
$g1->moveTo(250,250);
my $g2 = $g1->newGroup('circle and boundary');
$g2->fgcolor('black');
$g2->bgcolor('red');
$g2->ellipse(200,200);
print $img->svg;
๐ฅ GD VERSUS GD::SVG METHODS ๐ฅ
Okay so here's the tea: every single GD::SVG method copies the naming and the interface of the GD methods. Like, it's a matching set bestie. Which means keeping GD::SVG alive means keeping up with both GD and SVG as they grow and change. Iconic but also a lot.
A big chunk of the original GD documentation got copy-pasted in here so you don't have to go hunting, because we love convenience in this house. But the subtle differences between how GD and GD::SVG actually do the thing are laid out right below. And heads up, and this is important: the return value for some GD::SVG methods is NOT the same as its GD counterpart. So don't just assume, okay? Read the vibes.
๐ OBJECT CONSTRUCTORS: CREATING IMAGES ๐
So GD::SVG currently only supports making image objects through its new constructor. That's it. That's the whole door. Which is very different from GD proper, who's out here letting you create images from previous images, filehandles, filenames, and data like it's no big deal. GD::SVG said no thanks, we're keeping it simple ๐
$image = GD::SVG::Image->new($height,$width,$debug);โ makes you a blank GD::SVG image object with the dimensions you specify, measured in pixels. Sneaky detail: this method also spins up a new SVG object and stores it internally, so it's doing double duty. And you can turn on debugging with the GD::SVG-specific$debugparameter โ it should be boolean true, and when it is, any non-implemented methods will print a warning about their status toSTDERR. Very "tell me everything" of it.
๐ฆ GD::SVG::Image METHODS ๐ฆ
Once you've got a GD::Image object, the world is yours: you can draw with it, copy it, merge two images together. And once you're done messing with the object, you can turn it into a standard image file format to output or save to a file. Chef's kiss.
โจ Image Data Output Methods โจ
GD::SVG implements a single output method, and it's svg(). One method. She's all you need.
$svg = $image->svg();โ this hands you the image in SVG format. From there you can print it, pipe it to an image viewer, or write it to a file handle. Obsessed. For example:
$svg_data = $image->svg();
open (DISPLAY,"| display -") || die;
binmode DISPLAY;
print DISPLAY $svg_data;
close DISPLAY;
If you'd rather have an inline version of the image instead of a full document version complete with the DTD, just pass the svg() method the 'inline' flag:
$svg_data = $image->svg(-inline=>'true');
๐จ And listen, real talk: calling the other standard GD image output methods (egjpeg,gd,gd2,png) on aGD::SVG::Imageobject will cause your script to exit with a warning. Not a vibe. Don't do it.
๐ Color Control ๐
These methods let you control and manipulate the color table of a GD::SVG image. Here's the plot twist though: GD uses color indices, but GD::SVG passes stringified RGB triplets as colors. Different philosophy entirely.
But GD::SVG isn't leaving you hanging โ it keeps an internal hash structure of colors and colored indices so it can map the GD functions that manipulate the color table. Which usually means there's behind-the-scenes translation happening, turning those stringified RGB triplets back into a color index. Lowkey genius, highkey chaotic ๐ง
$stringified_color = $image->colorAllocate(RED,GREEN,BLUE)โ okay so unlike GD, colors don't need to be allocated in advance in SVG. And unlike GD, which returns a color index,colorAllocatereturns a formatted string that's compatible with SVG. At the same time, it creates and stores internally a GD-compatible color index for use with GD's color manipulation methods. Multitasking queen.
returns: "rgb(RED,GREEN,BLUE)"
$index = $image->colorAllocateAlpha()โ NOT IMPLEMENTED$image->colorDeallocate($index)โ hand it a color index and it removes it from the color table. Bye bestie ๐$index = $image->colorClosest(red,green,blue)โ returns the index of the color in the color table that's closest to the red, green and blue components you specified. This method is inherited directly from GD.
Example: $apricot = $myImage->colorClosest(255,200,180);
NOT IMPLEMENTED โ yeah I know, the docs show you the example and then hit you with that. Tragic.
$index = $image->colorClosestHWB(red,green,blue)โ NOT IMPLEMENTED$index = $image->colorExact(red,green,blue)โ retrieves the color index of an rgb triplet, or-1if it hasn't been allocated yet.
NOT IMPLEMENTED
$index = $image->colorResolve(red,green,blue)โ NOT IMPLEMENTED$colors_total = $image->colorsTotal()โ retrieves the total number of colors indexed in the image. That's it, that's the whole job ๐$index = $image->getPixel(x,y)โ NOT IMPLEMENTED($red,$green,$blue) = $image->rgb($index)โ give it a color index and it returns the RGB triplet. But in GD::SVG, color indexes get replaced with actual RGB triplets in the form"rgb($r,$g,$b)".$image->transparent($colorIndex);โ controls the transparency of individual colors.
NOT IMPLEMENTED
๐ Special Colors ๐
GD implements a whole roster of special colors that unlock special effects. They're constants defined in the GD:: namespace, but they get automatically exported into your namespace the moment the GD module is loaded. Convenient! GD::SVG, though, offers limited support for these methods. Read carefully bestie.
$image->setBrush($brush)(KLUDGE ALERT) โ and then there'sgdBrushed:
In GD, you can draw lines and shapes using a brush pattern. Brushes are just images that you create and manipulate in the usual way. When you draw with them, their contents get used for the color and shape of the lines. Very crafty.
To make a brushed line, you have to create or load the brush first, then assign it to the image using setBrush(). After that you can draw with that brush using the gdBrushed special color. And pro tip: it's often useful to set the background of the brush to transparent so the non-colored parts don't overwrite other parts of your image. ๐จ
# Via GD, this is how one would set a Brush
$diagonal_brush = new GD::Image(5,5);
$white = $diagonal_brush->colorAllocate(255,255,255);
$black = $diagonal_brush->colorAllocate(0,0,0);
$diagonal_brush->transparent($white);
$diagonal_brush->line(0,4,4,0,$black); # NE diagonal
GD::SVG offers limited support for setBrush (and the corresponding gdBrushed methods) โ currently only in the shapes of squares. So squares only, sorry to the diagonal girlies.
Internally, GD::SVG extracts the longest dimension of the image using the getBounds() method. Then it extracts the second color set, assuming that's the foreground color. Then it re-calls the original drawing method with these new values in place of the gdBrushed. If you want the internal details of this whole operation, go peek at the private _distill_gdSpecial method. That's where the sausage gets made.
$image->setThickness($thickness)โ lines drawn withline(),rectangle(),arc(), and so forth are 1 pixel thick by default. CallsetThickness()to change the line drawing width. Thicc lines, we love to see it.$image->setStyle(@colors)โsetStyle()andgdStyled()are partially supported in GD::SVG. GD::SVG figures out the alternating pattern of dashes by treating the first unique color it encounters in the array as "on", the second as "off", and so on. Then the first color in the array gets used to draw the actual line. Clever girl.gdTiledโ NOT IMPLEMENTEDgdStyled()โ the GD special colorgdStyledis partially implemented in GD::SVG. Only the first color will be used to generate the dashed pattern you specified insetStyle(). For more info, go seesetStyle(). Yeah, it's a little limited. We work with what we have ๐$image->setAntiAliased($color)โ NOT IMPLEMENTEDgdAntiAliasedโ NOT IMPLEMENTED$image->setAntiAliasedDontBlend($color,[$flag])โ NOT IMPLEMENTED
๐ซถ Drawing Commands ๐ซถ
$image->setPixel($x,$y,$color)โ sets the corresponding pixel to the given color. GD::SVG pulls this off by drawing a single dot in the specified color at that position. Little dot, big energy โญ$image->line(x1,y1,x2,y2,color);โ draws a line between the two coordinate points with the specified color. And plot twist: passing an optionalidwill set the id of that SVG element. GD::SVG also supports drawing with the special brushes โgdStyledandgdBrushedโ although ngl these special styles are difficult to replicate precisely in GD::SVG. We try our best.$image->dashedLine($x1,$y1,$x2,$y2,$color);โ NOT IMPLEMENTED$image->rectangle($x1,$y1,$x2,$y2,$color);โ this draws a rectangle with the specified color.(x1,y1)and(x2,y2)are the upper left and lower right corners respectively. And you can also draw with the special colorsgdBrushedandgdStyled. Fancy.$image->filledRectangle($x1,$y1,$x2,$y2,$color);โfilledRectangleis a GD-specific method with no direct equivalent in SVG. GD::SVG translates this method into an SVG-appropriate method by passing the filled color parameter as a named'filled'parameter to SVG. Drawing with the special colors is also permitted. For additional details, see the docs for theline()method.
GD call:
$img->filledRectangle($x1,$y1,$x2,$y2,$color);
SVG call:
$img->rectangle(x=> $x1,y=> $y1,
width => $x2-$x1,
height => $y2-$y1,
fill => $color
$image->polygon($polygon,$color);โ this draws a polygon with the specified color. The polygon has to be created first (see "Polygons" below). It needs at least three vertices. And if the last vertex doesn't close the polygon, the method will close it for you โ she's helpful like that. Both real color indexes and the special colorsgdBrushed,gdStyledandgdStyledBrushedcan be specified. See the docs for theline()method for additional details.
$poly = new GD::Polygon;
$poly->addPt(50,0);
$poly->addPt(99,99);
$poly->addPt(0,99);
$image->polygon($poly,$blue);
$image->filledPolygon($polygon,$color);โ this draws a polygon filled with the specified color. Drawing with the special colors is also permitted. See the docs for theline()method for additional details.
# make a polygon
$poly = new GD::Polygon;
$poly->addPt(50,0);
$poly->addPt(99,99);
$poly->addPt(0,99);
# draw the polygon, filling it with a color
$image->filledPolygon($poly,$peachpuff);
$image->filledPolygon($polygon,$color);โ this draws a polygon filled with the specified color. Drawing with the special colors is also permitted. See the docs for theline()method for additional details.
# make a polygon
$poly = new GD::Polygon;
$poly->addPt(50,0);
$poly->addPt(99,99);
$poly->addPt(0,99);
# draw the polygon, filling it with a color
$image->filledPolygon($poly,$peachpuff);
๐ yes bestie, that really is listed twice in the original. We keep every detail here. No cap.
$image->polyline(polyline,color)โ and the call itself:
$image->polyline($polyline,$black)
This draws a polyline with the specified color. Both real color indexes and the special colors gdBrushed, gdStyled and gdStyledBrushed can be specified.
And here's a fun little quirk: neither the polyline() method nor the polygon() method are very picky. You can call either method with either a GD::Polygon or a GD::Polyline โ the method figures out whether the shape is "closed" or "open" as drawn, not based on the object type. She doesn't judge, she just draws ๐ฆ
$image->polydraw(polything,color)โ and the call:
$image->polydraw($poly,$black)
this method draws the polything exactly as you'd expect โ polygons come out closed, polylines come out open โ and it pulls that off by simply checking what type of object it's holding and calling either $image->polygon() or $image->polyline(). no cap, that's the whole trick. ๐
$image->ellipse($cx,$cy,$width,$height,$color)$image->filledEllipse($cx,$cy,$width,$height,$color)โ bestie these draw ellipses โจ.($cx,$cy)is the center of the arc, and($width,$height)set the ellipse width and height respectively.filledEllipse()is exactly likeellipse()except it produces a filled version of the ellipse. Drawing with the special colors is allowed here too ๐. Peep the docs for theline()method for the extra deets.$image->arc($cy,$cy,$width,$height,$start,$end,$color);โ this one draws arcs <emphasis>and</emphasis> ellipses ๐ธ.(cx,cy)is the center of the arc, and(width,height)specify the width and height respectively. Which slice of the ellipse actually gets covered by the arc is controlled bystartandend, and both of those are given in degrees from 0 to 360. Zero sits at the top of the ellipse and the angles increase clockwise ๐. Wanna full ellipse? Use0and360as your starting and ending angles. Wanna circle? Just use the same value for width and height, periodt.
Internally, arc() calls the ellipse() method of SVG.pm. Drawing with the special colors is also permitted. See the documentation for the line() method for additional details.
heads up though: currently, true arcs are NOT supported, only those where the start and end equal0and360respectively, resulting in a closed arc. ๐ญ
$image->filledArc($cx,$cy,$width,$height,$start,$end,$color [,$arc_style])โ likearc()except it actually colors in the pie wedge with the selected color ๐.$arc_styleis optional. If it's there, it's a bitwise OR of these constants:gdArcโ connect start & end points of arc with a rounded edgegdChordโ connect start & end points of arc with a straight linegdPieโ synonym forgdChordgdNoFillโ outline the arc or chordgdEdgedโ connect beginning and ending of the arc to the center
gdArc and gdChord are mutally exclusive ๐. gdChord just connects the starting and ending angles with a straight line, while gdArc produces a rounded edge. gdPie is a synonym for gdArc. gdNoFill indicates that the arc or chord should be outlined, not filled. gdEdged, used together with gdNoFill, indicates that the beginning and ending angles should be connected to the center โ this is a good way to outline (rather than fill) a "pie slice." ๐
(yes, the list says gdPie is a synonym for gdChord and the paragraph says it's a synonym for gdArc. i'm just the messenger, i don't make the rules ๐)
Using these special styles, you can easily draw bordered ellipses and circles. iconic behavior fr fr:
# Create the filled shape:
$image->filledArc($x,$y,$width,$height,0,360,$fill); # Now border it.
$image->filledArc($x,$y,$width,$height,0,360,$color,gdNoFill);
$image->fill()โ NOT IMPLEMENTED ๐ญ$image->fillToBorder()โ NOT IMPLEMENTED ๐ญ
๐ Image Copying Methods ๐
The basic copy() command is implemented in GD::SVG, slay ๐. You can copy one GD::SVG into another GD::SVG, or copy a GD::Image or GD::Simple object into a GD::SVG โ which is how you embed a pixmap image into the SVG image. lowkey magical โจ
All the other image copying methods are unsupported, and if your script calls one of the following methods, your script will die remorsefully with a warning ๐. With sufficient demand, the author might try to implement some of these methods. For now, they're considered beyond the intent of GD::SVG.
$image->clone()
$image->copyMerge()
$image->copyMergeGray()
$image->copyResized()
$image->copyResampled()
$image->trueColorToPalette()
๐ฆ Image Transfomation Commands ๐ฆ
None of the image transformation commands are implemented in GD::SVG, bestie ๐. If your script calls one of the following methods, your script will die remorsefully with a warning. With sufficient demand, the author might try to implement some of these methods. For now, they're beyond the intent of GD::SVG.
$image = $sourceImage->copyRotate90()
$image = $sourceImage->copyRotate180()
$image = $sourceImage->copyRotate270()
$image = $sourceImage->copyFlipHorizontal()
$image = $sourceImage->copyFlipVertical()
$image = $sourceImage->copyTranspose()
$image = $sourceImage->copyReverseTranspose()
$image->rotate180()
$image->flipHorizontal()
$image->flipVertical()
๐ Character And String Drawing ๐
GD lets you draw characters and strings, either in normal horizontal orientation or rotated 90 degrees ๐. In GD, these routines use a GD::Font object. Internally, GD::SVG mimics GD's behavior with respect to fonts in a very similar manner, using instead a GD::SVG::Font object โ more on that below.
GD's font handling abilities are not as flexible as SVG's, and it does not allow the dynamic creation of fonts. Instead it exports five available fonts as global variables: gdGiantFont, gdLargeFont, gdMediumBoldFont, gdSmallFont and gdTinyFont ๐. GD::SVG also exports these same global variables, but establishes them in a different manner โ using constant variables to set the font family, font height and width of these global fonts. These values were chosen to match GD's output as closely as possible. If they're unsatisfactory, adjust the constants at the top of this file. In all subroutines below, GD::SVG passes a generic GD::SVG::Font object in place of the exported font variables.
$image->string($font,$x,$y,$string,$color)โ draws a string starting at position(x,y)in the specified font and color. Your font choices aregdSmallFont,gdMediumBoldFont,gdTinyFont,gdLargeFontandgdGiantFont.
$myImage->string(gdSmallFont,2,10,"Peachy Keen",$peach);
$image->stringUp($font,$x,$y,$string,$color)โ same as the previous example, except it draws the text rotated counter-clockwise 90 degrees.$image->char($font,$x,$y,$char,$color)$image->charUp($font,$x,$y,$char,$color)โ these draw single characters at position(x,y)in the specified font and color. They're carry-overs from the C interface, where there's an actual distinction between characters and strings. Perl is insensible to such subtle distinctions ๐. Neither is SVG, which simply calls thestring()method internally.@bounds = $image->stringFT($fgcolor,$fontname,$ptsize,$angle,$x,$y,$string)@bounds = $image->stringFT($fgcolor,$fontname,$ptsize,$angle,$x,$y,$string,\%options)โ in GD, these methods use TrueType to draw scaled, antialiased strings using the TrueType font of your choice ๐ฅ. GD::SVG can handle this directly by calling thestring()method internally.
The arguments are as follows:
fgcolorโ Color index to draw the string infontnameโ An absolute path to the TrueType (.ttf) font fileptsizeโ The desired point size (may be fractional)angleโ The rotation angle, in radiansx,yโ X and Y coordinates to start drawing the stringstringโ The string itself
GD::SVG attempts to extract the name of the font from the pathname supplied in the fontname argument. If it fails, Helvetica will be used instead. ๐
If successful, the method returns an eight-element list giving the boundaries of the rendered string:
@bounds[0,1] Lower left corner (x,y)
@bounds[2,3] Lower right corner (x,y)
@bounds[4,5] Upper right corner (x,y)
@bounds[6,7] Upper left corner (x,y)
This from the GD documentation (not yet implemented in GD::SVG):
An optional 8th argument allows you to pass a hashref of options to stringFT(). Two hashkeys are recognized: linespacing, if present, controls the spacing between lines of text. charmap, if present, sets the character map to use.
The value of linespacing is supposed to be a multiple of the character height, so setting linespacing to 2.0 will result in double-spaced lines of text. However the current version of libgd (2.0.12) does not do this. Instead the linespacing seems to be double what is provided in this argument. So use a spacing of 0.5 to get separation of exactly one line of text. In practice, a spacing of 0.6 seems to give nice results โจ. Another thing to watch out for is that successive lines of text should be separated by the "\r\n" characters, not just "\n". ๐
The value of charmap is one of "Unicode", "Shift_JIS" and "Big5". The interaction between Perl, Unicode and libgd is not clear to the author, and you should experiment a bit if you want to use this feature.
$gd->stringFT($black,'/dosc/windows/Fonts/pala.ttf',40,0,20,90,
"hi there\r\nbye now",
{linespacing=>0.6,
charmap => 'Unicode',
});
For backward compatibility with older versions of the FreeType library, the alias stringTTF() is also recognized. Also be aware that relative font paths are not recognized due to problems in the libgd library. ๐ซ
$hasfontconfig = $image->useFontConfig($flag)โ calluseFontConfig()with a value of1in order to enable support for fontconfig font patterns (seestringFT). Regardless of the value of$flag, this method will return a true value if the fontconfig library is present, or false otherwise.
NOT IMPLEMENTED ๐ญ
๐ง Alpha Channels ๐ง
$image->alphaBlending($blending)โ NOT IMPLEMENTED ๐ญ$image->saveAlpha($saveAlpha)โ NOT IMPLEMENTED ๐ญ
โญ Miscellaneous Image Methods โญ
$image->interlaced([$flag])โ NOT IMPLEMENTED ๐ญ($width,$height) = $image->getBounds()โgetBounds()returns the height and width of the image. wait, yes, height and width, in that order, bestie ๐$is_truecolor = $image->isTrueColor()โ NOT IMPLEMENTED ๐ญ$flag = $image1->compare($image2)โ NOT IMPLEMENTED ๐ญ$image->clip($x1,$y1,$x2,$y2)($x1,$y1,$x2,$y2) = $image->clipโ NOT IMPLEMENTED ๐ญ$flag = $image->boundsSafe($x,$y)โ NOT IMPLEMENTED ๐ญ
๐ GD::SVG::Polygon METHODS ๐
okay bestie, here's the tea: SVG is so much better at polygons than GD is. Like, it's not even close. GD does have some basic polygon support, but it's gotta build them point by point as separate objects. lowkey painful. ๐
$poly = GD::SVG::Polygon->new
Makes you an empty polygon with zero vertices. A blank canvas, a fresh start, main character energy. โจ
$poly = new GD::SVG::Polygon;
$poly->addPt($x,$y)
Drops the point (x,y) into the polygon. adding vertices like it's nothing ๐ซถ
$poly->addPt(0,0);
$poly->addPt(0,50);
$poly->addPt(25,25);
($x,$y) = $poly->getPt($index)
Grabs you the point sitting at that vertex index. it's giving "let me check on that real quick" ๐
($x,$y) = $poly->getPt(2);
$poly->setPt($index,$x,$y)
Changes the value of a vertex that already exists. โ ๏ธ And heads up: trying to set a vertex that isn't already defined is an error, periodt. no improvising.
$poly->setPt(2,100,100);
($x,$y) = $poly->deletePt($index)
Yeets the specified vertex and hands you its value back on the way out. goodbye bestie ๐
($x,$y) = $poly->deletePt(1);
$poly->toPt($dx,$dy)
Draws from the current vertex to a brand new one using relative (dx,dy) coordinates. And if this happens to be your very first point? It just acts like addPt(). flexible queen ๐
$poly->addPt(0,0);
$poly->toPt(0,50);
$poly->toPt(25,-25);
NOT IMPLEMENTED โ yeah, this one's not actually working yet. ๐ญ
$vertex_count = $poly->length()
Returns how many vertices are chillin' in your polygon. simple math, slay.
@vertices = $poly->vertices()
Returns a list of all the vertices in the polygon object. Each member of that list is a reference to an (x,y) array. iconic.
@vertices = $poly->vertices;
foreach $v (@vertices)
print join(",",@$v),"\n";
}
@rect = $poly->bounds()
Returns the smallest rectangle that completely wraps around your polygon. the return value is an array holding the (left,top,right,bottom) of that rectangle. snug as a bug ๐ธ
($left,$top,$right,$bottom) = $poly->bounds;
$poly->offset($dx,$dy)
Shifts every single vertex of the polygon by the horizontal (dh) and vertical (dy) amounts you give it. Positive numbers move the polygon down and to the right. It returns the number of vertices that got affected. ๐ฆ
$poly->offset(10,30);
$poly->map($srcL,$srcT,$srcR,$srcB,$destL,$dstT,$dstR,$dstB)
Maps the polygon from a source rectangle to an equivalent position inside a destination rectangle โ moving and resizing it as needed. Wanna see how it actually works? Check polys.pl for an example. Both rectangles get handed over in (left,top,right,bottom) coordinates. And for convenience? You can just use the polygon's own bounding box as the source rectangle. ๐
# Make the polygon really tall
$poly->map($poly->bounds,0,0,50,200);
NOT IMPLEMENTED โ nope, not this one either. ๐
$poly->scale($sx,$sy)
Scales every vertex of the polygon by the X and Y factors you pass as sx and sy. So like, scale(2,2) makes the polygon twice as big. For the best results, move the center of the polygon to position (0,0) before you scale, then move it back to where it was. chef's kiss technique โจ
NOT IMPLEMENTED
$poly->transform($sx,$rx,$sy,$ry,$tx,$ty)
Runs every vertex of the polygon through a transformation matrix, where sx and sy are the X and Y scaling factors, rx and ry are the X and Y rotation factors, and tx and ty are X and Y offsets. Want the full explanation? See the Adobe PostScript Reference, page 154 โ or honestly, just experiment and vibe it out. ๐ง
NOT IMPLEMENTED
GD::Polyline
Want the deets on creating open polygons and splines? Please see GD::Polyline. go read it, i'll wait ๐ซถ
๐ GD::SVG::Font METHODS ๐
NOTE: the object-oriented implementation to font utilities is not yet supported. sad but true. ๐ญ
So here's the lore: the libgd library (the one the Perl GD library uses) has built-in support for like half a dozen fonts, all converted from public-domain X Windows fonts. Want more fonts? Compile libgd with TrueType support and use the stringFT() call. ๐
GD::SVG replicates GD's internal fonts by hardcoding fonts that resemble the design and point size of the originals. Each of these fonts is available both as an imported global (like gdSmallFont) and as a package method (like GD::Font->Small). double the access, double the slay.
gdTinyFont / GD::Font->Tiny
A tiny, almost unreadable font, 5x8 pixels wide. it's giving "squint and pray" ๐
gdSmallFont / GD::Font->Small
The basic small font, "borrowed" from a well known public domain 6x12 font.
gdMediumBoldFont / GD::Font->MediumBold
A bold font, intermediate in size between the small and large fonts, borrowed from a public domain 7x13 font.
gdLargeFont / GD::Font->Large
The basic large font, "borrowed" from a well known public domain 8x16 font.
gdGiantFont / GD::Font->Giant
A 9x15 bold font converted by Jan Pazdziora from a sans serif X11 font. ๐
$font->nchars
Returns the number of characters in the font.
print "The large font contains ",gdLargeFont->nchars," characters\n";
NOT IMPLEMENTED
$font->offset()
Returns the ASCII value of the first character in the font. ๐ข
$width = $font->width
$height = $font->height
These two return the width and height of the font. that's it, that's the method.
($w,$h) = (gdLargeFont->width,gdLargeFont->height);
โญ REAL WORLD EXAMPLES โญ
BioPerl
The Bio::Graphics package of the BioPerl project makes use of GD::SVG to export SVG graphics. fr fr, real ones use it.
http://www.bioperl.org/
Generic Genome Browser
The Generic Genome Browser (GBrowse) utilizes Bio::Graphics and enables SVG dumping of genomics views. Wanna see a real-world example of SVG output from GBrowse? Look at WormBase:
http://www.wormbase.org/cgi-bin/gbrowse/
Further info about the Generic Genome Browser lives at the Generic Model Organism Project home page:
http://www.gmod.org/
toddot
Also, the author prepared a number of comparative images at his website (shameless plug, hehe):
http://www.toddot.net/projects/GD-SVG/
๐ INTERNAL METHODS ๐
The following internal methods are private โ documented only for those brave souls wishing to extend the GD::SVG interface. you've been warned, iykyk ๐
_distill_gdSpecial()
When a drawing method gets passed a stylized brush via gdBrushed, the internal _distill_gdSpecial() method tries to make sense of it by setting line thickness and foreground color. Since stylized brushes are GD::SVG::Image objects, it does this by fetching the width of the image using the getBounds method. That width then gets used to setThickness. The last color set by colorAllocate is then used for the foreground color. ๐จ
When it comes to setting line thickness, GD::SVG temporarily overrides any previously set line thickness. See, in GD, setThickness is persistent through uses of stylized brushes. To accomodate this behavior, _distill_gdSpecial() temporarily stores the previous line_thickness in the $self->{previous_line_thickness} flag.
_reset()
The _reset() method is used to restore persistent drawing settings between uses of stylized brushes. Currently, this involves:
- restoring line thickness
๐ IMPORTANT NOTE! GD::SVG / SVG::GD ๐
okay so there's a second module โ SVG::GD, written by Ronan Oger โ that also provides similar functionality to this module. Ronan and the author are concurrently developing these modules with an eye towards integrating them in the future. ๐ฏ
In principle, the primary difference is that GD::SVG aims to generate SVG and SVG only. That is, it:
- Does not store an internal representation of the GD image
- Does not enable JPG, PNG, OR SVG output from a single pass through data
- Only occasioanally uses inherited methods from GD
Instead, GD::SVG depends on the user to choose which output format they want in advance, useing the appropriate module for that output. As described at the start of this document, module selection between GD and GD::SVG can be made dynamically using eval statements and variables for the different classes that GD and GD::SVG create.
There's a second reason for not maintaining a double representation of the data in GD and SVG format too: SVG documents can quickly become very large, especially with big datasets. In cases where scripts are primarily generating png images in a server environment and would only occasionally need to export SVG, generating an SVG image in parallel would result in an unacceptable performance hit. ๐
So GD::SVG aims to be a plugin for existing configurations that depend on GD but would like to take advantage of SVG output. it's the glow-up, not the rewrite โจ
SVG::GD, on the other hand, aims to tie in the raster-editing ability of GD with the power of SVG output. In part, it aims to do this by inheriting many methods from GD directly and bringing them into the functional space of GD. That makes SVG::GD easier to set up initially โ simply by adding the use SVG::GD below the use GD statement of your script. GD::SVG sacrifices this initial ease-of-setup for more targeted applications. trade-offs, bestie, we all make them ๐
๐ซถ ACKNOWLEDGEMENTS ๐ซถ
Lincoln Stein, my postdoctoral mentor, author of GD.pm, and all around Perl stud. Ronan Oger, author of SVG.pm, conceptualized and implemented another wrapper around GD at about the exact same time as this module. He also provided helpful discussions on implementing GD functions into SVG. Oliver Drechsel and Marc Lohse provided patches to actually make the stringUP method functional. absolute legends, all of them ๐
โจ AUTHOR โจ
Todd Harris, PhD <harris@cshl.org>
๐ COPYRIGHT AND LICENSE ๐
Copyright @ 2003-2005 Todd Harris and the Cold Spring Harbor Laboratory
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
๐ฆ SEE ALSO ๐ฆ
GD, SVG, SVG::Manual, SVG::DOM
and that's the whole page, bestie โ you made it to the end! ๐ this one was perl v5.30.3, dated 2020-07-29, and it's the SVG(3pm) manual page. go forth and render some gorgeous SVG, you absolute icon ๐โจ
๐ฆ where this page comes from
- debian bookworm: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- debian trixie: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu jammy: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libgd-svg-perl 0.33-3 ยท Artistic-1.0-Perl OR GPL-1.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms