SVG(3pm)

๐Ÿ“ฆ
version 0.33 ยท 3 versions
, in debian bookworm, debian trixie, ubuntu jammy, ubuntu noble, ubuntu resolute, ubuntu stonking

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 GD call for use GD::SVG
  • and fix up your initial new method 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.pm module
  • Lincoln Stein's GD.pm module
  • libgd and 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 $debug parameter โ€” it should be boolean true, and when it is, any non-implemented methods will print a warning about their status to STDERR. 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 (eg jpeg, gd, gd2, png) on a GD::SVG::Image object 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, colorAllocate returns 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 -1 if 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's gdBrushed:

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 with line(), rectangle(), arc(), and so forth are 1 pixel thick by default. Call setThickness() to change the line drawing width. Thicc lines, we love to see it.
  • $image->setStyle(@colors) โ€” setStyle() and gdStyled() 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 IMPLEMENTED
  • gdStyled() โ€” the GD special color gdStyled is partially implemented in GD::SVG. Only the first color will be used to generate the dashed pattern you specified in setStyle(). For more info, go see setStyle(). Yeah, it's a little limited. We work with what we have ๐Ÿ’œ
  • $image->setAntiAliased($color) โ€” NOT IMPLEMENTED
  • gdAntiAliased โ€” 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 optional id will set the id of that SVG element. GD::SVG also supports drawing with the special brushes โ€” gdStyled and gdBrushed โ€” 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 colors gdBrushed and gdStyled. Fancy.
  • $image->filledRectangle($x1,$y1,$x2,$y2,$color); โ€” filledRectangle is 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 the line() 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 colors gdBrushed, gdStyled and gdStyledBrushed can be specified. See the docs for the line() 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 the line() 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 the line() 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 like ellipse() except it produces a filled version of the ellipse. Drawing with the special colors is allowed here too ๐ŸŽ€. Peep the docs for the line() 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 by start and end, 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? Use 0 and 360 as 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 equal 0 and 360 respectively, resulting in a closed arc. ๐Ÿ˜ญ
  • $image->filledArc($cx,$cy,$width,$height,$start,$end,$color [,$arc_style]) โ€” like arc() except it actually colors in the pie wedge with the selected color ๐Ÿ“. $arc_style is optional. If it's there, it's a bitwise OR of these constants:
    • gdArc โ€” connect start & end points of arc with a rounded edge
    • gdChord โ€” connect start & end points of arc with a straight line
    • gdPie โ€” synonym for gdChord
    • gdNoFill โ€” outline the arc or chord
    • gdEdged โ€” 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 are gdSmallFont, gdMediumBoldFont, gdTinyFont, gdLargeFont and gdGiantFont.
$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 the string() 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 the string() method internally.

The arguments are as follows:

  • fgcolor โ€” Color index to draw the string in
  • fontname โ€” An absolute path to the TrueType (.ttf) font file
  • ptsize โ€” The desired point size (may be fractional)
  • angle โ€” The rotation angle, in radians
  • x,y โ€” X and Y coordinates to start drawing the string
  • string โ€” 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) โ€” call useFontConfig() with a value of 1 in order to enable support for fontconfig font patterns (see stringFT). 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:

  1. Does not store an internal representation of the GD image
  2. Does not enable JPG, PNG, OR SVG output from a single pass through data
  3. 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 @ 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