Scalable Vector Graphics allows you to create images that can scale up and down without loss of quality.

I have already heared Tamir Lousky give two presentation on how to create SVG images using Perl, so I thought I should give it a try.

What is Scalable Vector Graphics?

When seeing an image, we basically see lots of colored pixels. The original picture can be stored either as those pixels, that's called a raster image or in can be saves as a series of commands to draw the picture.

Scalable Vector Graphics (SVG) is basically an XML file containing instructions how to draw an image.

Your browser can process that XML file and render it as a picture. (Well, assuming you have a modern web browser.)

There is a pure-perl module called SVG created by Ronan Oger, that allows you to create that XML file by calling Perl methods.

Let's see a few simple examples.

Draw circle

#!/usr/bin/perl
use strict;
use warnings;

use SVG;

# create an SVG object with a size of 40x40 pixels
my $svg = SVG->new(
    width  => 40,
    height => 40,
);

# add a circle
$svg->circle(
    cx => 20,
    cy => 20,
    r  => 18,
);


# now render the SVG object, implicitly use svg namespace
print $svg->xmlify;

First we create the background of the image with a size of 40 x 40 pixels. We only need this so we can add elements to it in a size relative to this size. By default the background is white.

my $svg = SVG->new(
    width  => 40,
    height => 40,
);

Then we add a circle, with a center at 20x20 and a radius of 18 pixels. By default the circle will be black.

Finally we call the xmlify method that returns the XML file.

If we run this script we'll see a small XML on our screen:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
     "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg height="40" width="40" xmlns="http://www.w3.org/2000/svg" 
     xmlns:svg="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="20" cy="20" r="18" />
<!-- 
    Generated using the Perl SVG Module V2.50
    by Ronan Oger
    Info: http://www.roitsystems.com/
-->
</svg>

We can save this by redirecting the output of the script to a file called

  perl circle.pl > black_circle.svg

Then we can open that file using our browser or by embedding in an html file using the img tag:

<img src="/img/black_circle.svg" alt="black circle"/>

and make sure that your web server returns the file with Content-type: image/svg+xml.

<img src="/img/black_circle.svg" alt="black circle"/>

Adding some style to the circle

# add a circle with style
#  fill is the color used tof fill the circle
#  stroke is the color of the line used to draw the circle
#     these both can be either a name of a color or an RGB triplet
#  stroke-width is a non-negative integer, thw width of thr drawing line
#  stroke-opacity and fill-opacity are floating point numbers between 0 and 1.
#     1 means the line is totally opaque
#     0 means the line is totally transparent
$svg->circle(
    cx => 20,
    cy => 20,
    r  => 15,
    style => {
        'fill'           => 'rgb(255, 0, 0)',
        'stroke'         => 'blue',
        'stroke-width'   =>  5,
        'stroke-opacity' =>  1,
        'fill-opacity'   =>  1,
    },
);

Add the following entry to the HTML

<img src="/img/red_blue_circle.svg" alt="red and blue circle"/>

red and blue circle

While that SVG file has a default size of 20x20 we can tell the browser to display the same image at a larger size by setting the width and the height

<img src="/img/red_blue_circle.svg" width="200" height="200" 
     alt="big red and blue circle"/>

big red and blue circle

Finally, I changed the 'fill-opacity' of the circle to 0.5. This made the red lighter:

big red and blue circle

Circle, Triangle and Square

#!/usr/bin/perl
use strict;
use warnings;
  
use SVG;
  
# create an SVG object with a size of 100x100 pixels
my $svg = SVG->new(
    width  => 100,
    height => 100,
);
  
# create a rectangle (actually square) with the top left
# corner being at (40, 50)
# (0, 0) would mean being in the top left corner of the image.
# The width and the height of the rectangular are also given
# in pixels and we can add style just asw we  did with the circle.
$svg->rectangle(
    x => 40,
    y => 50,
    width  => 40,
    height => 40,
    style => {
        'fill'           => 'rgb(0, 255, 0)',
        'stroke'         => 'black',
        'stroke-width'   =>  0,
        'stroke-opacity' =>  1,
        'fill-opacity'   =>  1,
    },
);

$svg->circle(
    cx => 40,
    cy => 40,
    r  => 20,
    style => {
        'fill'           => 'rgb(255, 0, 0)',
        'stroke'         => 'black',
        'stroke-width'   =>  0,
        'stroke-opacity' =>  1,
        'fill-opacity'   =>  1,
    },
);

# In order to create a triangle we are going to create a polygon
# To make it easy to create various path based constructs, SVG.pm
# provides a "get_path" method that, give a series of coordinates
# and a type, return the respective data structure that is needed
# for SVG.
my $path = $svg->get_path(
    x => [40, 60, 80],
    y => [40, 6, 40],
    -type => 'polygon');

# Then we use that data structure to create a polygon
$svg->polygon(
    %$path,
    style => {
        'fill'           => 'rgb(0,0,255)',
        'stroke'         => 'black',
        'stroke-width'   =>  0,
        'stroke-opacity' =>  1,
        'fill-opacity'   =>  1,
    },
);

# now render the SVG object, implicitly use svg namespace
print $svg->xmlify;

Circle, Triangle and Square

Set the 'fill-opacity' of the circle and that of the polygon to 0.5.

Transparent Circle, Triangle and Square

More of SVG

Recently I got co-maintainership on the SVG module. Made some small documentation fixes and started to modernize the tests a little bit. The above examples were also included. If you have any bug reports or requests, please use the bug tracking system provided by GitHub. In case you'd like to contribute, use the github repository.

For the Norwegian readers out there

Let me point you to the Bachelor's thesis of Robin Smidsrød on the state of SVG support in browsers (as of 2010).

Chapter 4 gives a good overview of the SVG primitives available.

He also created a charting library (for Java) as part of that thesis, which can be found here.

He hasn't found a library that does the same thing in Perl yet, and I think the the API is interesting, in how it allows an arbitrary amount of axes for quite complicated charts.

An app that uses the library, SVGChartApp (made by another student he worked with), takes CSV input files and generates charts in SVG.