SVG from Perl

G. Wade Johnson

Houston.pm

What is SVG?

SVG is a format for vector graphics. In raster graphics, the image is made of a large number of colored dots. Vector graphics, on the other hand, are made up of a series of graphic objects.

In a raster graphic, a blue circle is a bunch of blue dots that happen to be contiguous and roughly circle shaped. In a vector graphic, a blue circle consists of a circle object with a specific position, radius, and a color of blue.

One side effect of this approach is that vector graphics are effectively infinitely scalable.

What is SVG?

W3C Recommendation since 2001

Although you may have only heard of SVG recently, it's actually been around for a long while. Several viewers have been in place for many years. We're currently on our 3rd revision of the standard (1.0, 1.1, and 1.2). The result is a relatively mature specification.

What is SVG?

XML-based vector graphics format

As an XML-based format, SVG is extensible. It is not a binary format that is difficult to extend. SVG supports foreign namespaces. This allows you to embed non-graphic information that is easily parsed out of the file. (We'll have an example of this later.

This also means that creating SVG is something that you can do by hand, with an XML editing tool, or through code.

Most of all, SVG is a graphics format.

What is SVG?

Support for declarative animation

SVG imports parts of the SMIL specification relating to animation. This allows you to specify in XML animation effects including movement and transformation of objects, changing attributes, and some user interaction.

What is SVG?

Support for scripting

SVG supports the ECMAscript scripting language for programmable interaction. With scripting, you can interact with the DOM of the document, react to user events, make calls to external servers, etc. This feature supports building small applications in SVG.

Here in mid-2009, scripting seems to be implemented more widely than SMIL in the web space. I have the impression that it's the reverse in mobile devices.

What SVG isn't?

A new programming language

SVG is not a replacement for all of the programming work you are doing on a given project.

What SVG isn't?

A complete replacement for Flash

Many people remain focused on the idea of SVG as a Flash killer. And, to be honest, there are some areas where Flash and SVG can both be used. However, their approaches are quite different. So there are undoubtedly places where one is more effective than the other.

I don't know enough about Flash to give a good explanation of where it would be most effective.

What SVG isn't?

A magic solution to all web image woes

Some people seem to want to use SVG to replace all images on their site. But, SVG is not a replacement for everything. PNG and JPEG still have their place. SVG is actually lousy for encoding photographs or photo-realistic images. These kinds of images are much more efficiently stored in raster formats.

What SVG isn't?

A GUI design tool

I often see the complaint that SVG will never amount to anything because it doesn't have menus, radio buttons, checkboxes, and other GUI controls. Strangely, the same people don't claim that JPEG is dead for these same reasons.

SVG was intended, from the beginning, to be a technology that would work well with other XML-based specifications. There has been quite a bit of experimentation with using SVG and HTML together. The W3C is also currently working on better interaction between HTML and other forms of markup for HTML 5.

That said, SVG is well-suited to building graphic elements for GUIs. It is used relatively extensively in KDE. It is also supported by Opera widgets.

What SVG isn't?

Completely supported everywhere

This is the biggest problem at the moment. SVG support is growing in all of the major browsers except one. There are a few plugins that add support to IE, with more on the way.

More importantly, browser support is increasing at a rapid pace. Three or four years ago, browser support was almost non-existent. Now large portions of the specification are supported by Firefox, Opera, Safari/Webkit, and Chrome.

It's my understanding that one of the biggest applications for SVG support has been mobile phones, mostly in Asia. We are seeing a small amount of that uptake trickling over to the west.

What can SVG do?

Infinitely scalable graphics

Okay, this is basically in the definition, but it's worth saying.

What can SVG do?

Art

SVG has been used quite a bit for clipart and icon development (KDE). But, I've also heard of some people doing more interesting artsy things with the technology. It's not my area, so I haven't looked into it very far.

What can SVG do?

Comics

Another area where I haven't spent much time. But, SVG seems to be a medium some have used for web comics. I should warn you that the Dragon Knights comic has some novel navigation effects and takes a bit of getting used to.

What can SVG do?

Games

Many people have coded games in SVG because it seems to be an obvious use for graphics and scripting in the same tool.

What can SVG do?

Maps

The cartography community has really embreaced SVG. They can not only generate extremely high-quality maps, but they can add interactivity and extended data to those maps. In some ways, these guys have been pushing the use of SVG more than almost anyone else.

What can SVG do?

Applications

(We'll have a few examples later.)

All of the games could be treated as applications. I know of one company that had an EMS (Energy Management System) with a Batik-based SVG front-end.

Why Should I Care?

This is the part of SVG that really grabbed my attention. Building nice-looking graphics from code is not generally easy. How many of you can create nice-looking JPEGs, given only a JPEG library? How many of you have used Image::Magick? How easy is it?

About the only graphics most of us generate are relatively straight-forward line and bar graphs. Maybe a pie chart, here and there. For those, we would probably rely on a library that does the heavy lifting for us. It's not that general graphics are impossible to do from code. But, most formats are optimized for storage space and display speed, not ease of programming.

How Do I View SVG?

Web Browsers

You'll probably notice one browser conspicuously missing from this list. Although MS keeps saying they are looking into SVG, they don't seem to have made any progress with this open web standard. Of course, they have continued on their own proprietary technologies.

In fact, Tim Berners-Lee called them out on it in an MSNBC interview.

How Do I View SVG?

Browser Plugins

Adobe released ASV shortly after the first SVG specification was released. Around the same time-frame, Corel also introduced a plugin as well. Although not perfect, ASV was good enough that no one found a need to build a new one.

When Adobe and Macromedia merged, ASV became a bit of an orphan. Adobe has pledged to keep it available, but it is officially unsupported. Given the fact that Microsoft has not provided SVG support in IE, several other groups have stepped up to try to get an IE-compatible plugin for SVG display.

How Do I View SVG?

SVG-specific Viewers

The Batik library has an SVG viewer as an example application. Both KDE and GNOME provide support in the window manager for display of SVG.

How Do I View SVG?

Mobile devices

Japan has been pushing the state of the art in mobile devices. Asia has actually embraced SVG as a core technology for their mobile devices. Both Trolltech and Ikivo produce SVG libraries for mobile devices. The browser maker Opera also has a mobile edition. The iPhone runs a Webkit-based browser.

How Do I View SVG?

Development libraries

As graphics programmers have become more aware of SVG, general purpose graphics libraries sprout SVG support. There are also SVG-specific graphics libraries.

Generating SVG in Perl

Since SVG is XML (basically text), you can generate SVG any way you can generate XML.


    <rect x="10" y="10" height="50" width="100"
             fill="green" stroke="none" />

Of course, to be XML it must be well-formed; and to be SVG, it must be valid. But other than that, there are a number of ways to generate it.

The print Method


    print qq{<rect x="10" y="10" height="50" width="100"},
          qq{ fill="green" stroke="none" />\n};

It's relatively easy, and requires no extra libraries. However, there's no support for making sure you are building well-formed SVG. There's no help for attribute and element names. There's no help for getting the namespaces correct.

You are basically on your own.

The XML::LibXML Method


    my $rect = $doc->createElementNS( $svgns, 'rect' );
    $rect->setAttribute( 'x', 10 );
    $rect->setAttribute( 'y', 10 );
    $rect->setAttribute( 'height', 50 );
    $rect->setAttribute( 'width', 100 );
    $rect->setAttribute( 'fill', 'green' );
    $rect->setAttribute( 'stroke', 'none' );

Much more verbose than the print approach. But, output is guaranteed to be well-formed. There are no guarantees about valid SVG, but at least the output is XML.

The verbosity issue can be handled with higher level subroutines.

The SVG Method


    $svg->rect(
        x=>10, y=>10, height=>50, width=>100,
        fill=>'green', stroke=>'none'
    );

Much less verbose than the XML::LibXML approach. Slightly more verbose than the print approach. More protection against invalid elements. No protection against invalid attributes.

Namespace declarations are taken care of so you don't have to.

The Template Toolkit Method

In template


  <rect x="[%x%]" y="[%y%]" height="[%height%]" width="[%width%]"
           fill="[%color%]" stroke="none" />

In code


  $tt->process( $fh,
     {x=>10, y=>10, height=>50, width=>100, color=>'green'}
  );

This approach is very useful if much of the SVG you need to output is boilerplate with a small amount that needs to change. Templates are a good way to separate the presentation part from the output you really need to create.

Thanks to its XML nature, every SVG file contains some boilerplate information. In addition, many SVG images contain a number of elements used for background imagery or supporting graphics. This boilerplate and static content can be placed in the template and does not need to be generated.

Specialty Perl Modules

A lot of programmers decide to use SVG as an effective tool for generating graphs and charts. It appears that most of the SVG modules on CPAN are designed for graph generation.

Separation of Concerns

Use a drawing package (like Inkscape) to build the background portions of the SVG and add to it with Perl.

An SVG application often consist of a small amount of boilerplate text, some background graphics, and some graphics that are generated by the code. The background stuff doesn't have to be static, it could be animated or support script-based interaction. The key part is that it does not need to change from one run of the program to the next.

Unfortunately, if the whole SVG application is generated with code, this boilerplate and background stuff needs to be written as well. But, some stuff is much easier to generate with a drawing program instead of with code. If the background portion can be read in and the result modified by code, you get the best of both worlds.

A template-based approach works particularly well with this idea.

Separation of Concerns: Animation

Do: Rely on SMIL and scripting to animate on the client side.

Don't: Try to animate from the Perl side

If you aren't used to the scripting or animation capabilities of SVG, you might be tempted to Use a lot of request/response code to call to a Perl program to decide what to do next. This would not be the best approach.

For maximum responsiveness, you want to do work on the client side whenever possible. With SVG's scripting ability, you can do a surprising amount in the application. The games from the examples before give you a beginning idea of what is possible. If your viewer has SMIL support, you can get some animation and interactivity without any scripting at all.

Separation of Concerns: DOM Manipulation

Do: Use scripting to manipulate the DOM on the client side.

Don't: Try to push lots of rewrites from Perl.

If you need calculations or data that would be too much for the script to handle, you might want to make an asynchronous call to a server to retrieve just the data. Then, use scripting to manipulate the interface using the returned data.

Just like the whole AJAX thing, you don't need to send a whole new SVG file for an update. Maybe you can get away with sending the data that you can use to make the appropriate changes with scripting.

Separation of Concerns: Interactivity

Do: Use scripting or SMIL on the client side to interact with the user.

Don't: Use request/response for user interactions.

In order for the application to have any reasonable responsiveness, you need to do as much interactive work as possible directly in the SVG. Users don't like waitign for request/response any more than is necessary.

Separation of Concerns: Perl

Do: Use Perl to generate initial conditions.

Do: Pre-calculate tables of data to be used by the scripting.

Perl is a really effective general-purpose language. As powerful as ECMAscript has become, it still has limits because it is running in a sandbox in the viewer.

One thing that works extremely well is to take a trick from some compiled languages. In the Perl code, you can pre-calculate information that you output into the script as tables. This pre-calculation approach can result in the script being capable of more because the heavy lifting has already been done.

Perl vs. SVG

Focus on using the best tool for the job.

The key to good Perl/SVG applications is to use the each language in a way that plays to that language's strengths.

Example: Maze Maker

Game application written for my son.

This started as a simple application that took output from the Games::Maze module and generated better looking graphs. From there, it evolved different styles and sizes for more challenges. The interactive side came last as I realized that not much was needed to make them actually playable.

Example: Guidelines

Application for my wife's calligraphy hobby.

This was a quick-and-dirty implementation using the print method. It's main positive attribute is that it works.

Example: Profile Graph Generation

Perl program for generating graphs using Template Toolkit from profiling data on different viewers.

This application was part of a profiling project I did for measuring the speed of scripting implementations across several viewers.

It was also the first time I had tried using Template Toolkit for generating non-trivial SVG.

Example: Instruments

Perl works as a server-side process to supply data to SVG-based virtual instruments.

This is a work in progress.

The application here is a prototype for the sole purpose of demoing the idea. One of these days, I need to get around to finishing it.

Example: SVG::Sparkline

Perl module for creating sparklines.

The Perl code can support substantial configuration and build a small SVG file.

Because there can never be too many graph modules on CPAN, I wrote the SVG::Sparkline module. SVG makes sparklines easier than in most graphing libraries because of the scaling issue. However, general-purpose graphing libraries are too general to fit the intent of sparklines.

This library was also a mechanism for me to explore the SVG Perl module.

SVG in Other Languages: Java

Batik

Batik is probably the most mature of the language libraries out there. It supports both generation and rendering of SVG. Current versions support much of the specification, with the nightly builds pushing the support even further.

SVG in Other Languages: Ruby

There are a few libraries for generating SVG from Ruby. Of course, one of them is a DSL.

SVG in Other Languages: Python

pySVG

There appears to be only one way to generate SVG from Python.

SVG in Other Languages: Scheme

SVG Graph

In typical Scheme fashion, we generate SVG from Lisp-y S-expressions, because parentheses are much more natural than angle brackets.<grin/>

SVG in Other Languages: C++

LibBoard

Even C++ has a library for generating SVG.

References

These are good sources for the latest information on SVG.