Lutz Gehlen > SVG-Rasterize > SVG::Rasterize

Download:
SVG-Rasterize-0.003008.tar.gz

Dependencies

Annotate this POD

CPAN RT

Open  1
View/Report Bugs
Module Version: 0.003008   Source  

NAME ^

SVG::Rasterize - rasterize SVG content to pixel graphics

VERSION ^

Version 0.003008

    my $blockID     = 0;
    my @block_atoms = grep { $_->{blockID} == $blockID } @$text_atoms;
    while(@block_atoms) {
        

        $blockID++;
        @block_atoms = grep { $_->{blockID} == $blockID } @$text_atoms;
    }

SYNOPSIS ^

    use SVG;
    use SVG::Rasterize;

    my $svg = SVG->new(width => 300, height => 200);
    $svg->line(x1 => 10, y1 => 20, x2 => 220, y2 => 150,
               style => {stroke => 'black', stroke-width => '2pt' });

    # add more svg content
    # .
    # .
    # .

    my $rasterize = SVG::Rasterize->new();
    $rasterize->rasterize(svg => $svg);
    $rasterize->write(type => 'png', file_name => 'out.png');

DESCRIPTION ^

SVG::Rasterize can be used to rasterize SVG objects to pixel graphics (currently png only) building on the Cairo library (by default, other underlying rasterization engines could be added). The direct rasterization of SVG files might be implemented in the future, right now you should have a look at SVG::Parser which can generate an SVG object from an svg file. See also SVG Input in the ADVANCED TOPICS section.

Motivation

In the past, I have used several programs to rasterize SVG graphics including Inkscape, Konqueror, Adobe Illustrator, and rsvg. While Inkscape was my favourite none of them made me entirely happy. There were always parts of the standard that I would have liked to use, but were unsupported.

So finally, I set out to write my own rasterization engine. The ultimate goal is complete compliance with the requirements for a Conforming Static SVG Viewer as described in the SVG specification: http://www.w3.org/TR/SVG11/conform.html#ConformingSVGViewers. Obviously, this is a long way to go. I do not know if any support for the dynamic features of SVG will ever be added. Anyway, the priority for SVG::Rasterize is accuracy, not speed.

Status

The following elements are drawn at the moment:

The inheritance of styling properties is implemented. The following attributes are at least partly interpreted:

I hope that the interface described here will be largely stable. However, this is not guaranteed. Some features are documented as likely to change, but everything is subject to change at this early stage.

Here is my current view of the next part of the roadmap:

Version 0.004
  • completion of text basics
Version 0.005
  • support for SVG files
  • relative units
Version 0.006
  • clipping paths
  • css sections and files?
Version 0.007
  • symbol/use
  • tref and such
Version 0.008
  • gradients and patterns
  • masks

INTERFACE ^

Constructors

new

  $rasterize = SVG::Rasterize->new(%args)

Creates a new SVG::Rasterize object and calls init(%args). If you subclass SVG::Rasterize overload init, not new.

init goes through the arguments given to new. If a method of the same name exists it is called with the respective value as argument. This can be used for attribute initialization. Some of the values can be also given to rasterize to temporarily override the attribute values. The values of these overridable attributes are only validated once they are used by rasterize.

The most commonly used arguments are:

Public Attributes

svg

Holds the DOM object to render. It does not have to be an SVG object, but it has to offer certain DOM methods (see SVG Input for details).

width

The width of the generated output in pixels.

height

The height of the generated output in pixels.

current_color

The color which is used if an SVG element's fill or stroke property is set to currentColor and the color property has not been set directly. Setting current_color has the same effect as if the root SVG element's color property was set to the same value. See http://www.w3.org/TR/SVG11/painting.html#SpecifyingPaint for the background of this.

medium_font_size

SVG supports keywords from xx-small to xx-large for the font-size attribute. A numerical value for medium as well as a scaling factor between neighboring values is supposed to be set by the user agent. SVG::Rasterize uses a default value of 12pt. This default value can be adjusted by setting this attribute. A new value has to be an absolute length larger than 0.

font_size_scale

Read about medium_font_size above first. font_size_scale holds the factor between neighboring font-size values, e.g. between large and x-large. The default value is 1.2.

There are other attributes that influence unit conversions, white space handling, and the choice of the underlying rasterization engine. See ADVANCED TOPICS.

Class Attributes

%IGNORED_NODES

Defaults to

  %IGNORED_NODES = (comment  => 1,
                    title    => 1,
                    desc     => 1,
                    metadata => 1);

A SVG node with a name that is a key in this hash with a true value is ignored including all its children. If you, for example set

  $SVG::IGNORED_NODES{text} = 1;

then all text nodes will be ignored.

Do not unset the defaults above or you are likely to get into trouble.

Methods for Users

rasterize

  $rasterize->rasterize(%args)

Traverses through the given SVG content and renders the output. Does not return anything.

Examples:

  $rasterize->rasterize(svg => $svg);
  $rasterize->rasterize(svg => $svg, width => 640, height => 480);
  $rasterize->rasterize(svg => $svg, engine_class => 'My::Class');

Supported parameters:

If width (the same applies to height) is 0 it is treated as not set. If you encounter any scenario where you would wish an explicit size of 0 to be treated in some other way let me know.

If width and/or height are not specified they have to have absolute values in the root SVG element. If both the root SVG element and the rasterize method have width and/or height settings then the rasterize parameters determine the size of the output image and the specified SVG viewport is mapped to this image taking the viewBox and preserveAspectRatio attributes into account if they are present. See http://www.w3.org/TR/SVG11/coords.html#ViewportSpace for details.

The user can influence the rasterization process via hooks. See the Hooks section below.

write

  $rasterize->write(%args)

Writes the rendered image to a file.

Example:

  $rasterize->write(type => 'png', file_name => 'foo.png');

The supported parameters depend on the rasterization backend. The write method hands all parameters over to the backend. See write in SVG::Rasterize::Engine::PangoCairo for an example.

ADVANCED TOPICS ^

SVG Input

In principle, SVG input could be present as a kind of XML tree object or as stringified XML document. Therefore SVG::Rasterize might eventually offer the following options:

1. The input data are provided in form of a SVG object tree generated by the user.
2. The input data are a SVG object tree generated from a file by SVG::Parser or a similar piece of software.
3. The input data are an object tree generated by a generic XML parser and offer a DOM interface.
4. The input data are stringified XML data in a file.
5. The input data are stringified XML data read from a file handle. This case is different from the previous one because a file can be read multiple times in order to collect referenced SVG fragments.

Currently, the first three options are at least partly implemented. I will not work on the other ones before a substantial subset of SVG is supported. If the last two options will ever get implemented they will be designed to enable the rendering of files which are too large for the first options. Because it is harder to deal with cross-references in these cases, chances are that it will always be faster to use option 2. or 3. if this is possible.

Option 1. is the best tested one by far. However, option 2. should be very similar. To use option 3., the node objects have to provide at least the following DOM methods:

Unfortunately, option 3. cannot be treated completely in the same way as options 1. and 2. due to the peculiarity of SVG to treat CDATA sections in a special way and not as child nodes of the element. SVG::Rasterize tries to support both SVG object trees and generic DOM trees, but this is neither well tested nor a main priority at the moment. Please report if you find SVG::Rasterize not cooperating with your favourite DOM parser.

Units

SVG supports the absolute units px, pt, pc, cm, mm, in, and the relative units em, ex, and %. Lengths can also be given as numbers without unit which is then interpreted as px. See http://www.w3.org/TR/SVG11/coords.html#Units.

SVG::Rasterize stores default values for unit conversion ratios as class variables. You can either change these values or the corresponding object variables. If you have only one SVG::Rasterize object both approaches have the same effect.

The default values are listed below. Except px_per_in, they are taken from the CSS specification. See http://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#length-units. The default for px_per_in is arbitrarily set to 90.

Currently, the relative units listed above are not supported by SVG::Rasterize.

Unit conversions:

The corresponding class attributes are listed below. Note that these values are not validated. Take care that you only set them to numbers.

Hooks

The rasterize method traverses through the SVG tree and creates an SVG::Rasterize::State object for each node (node means here element or text node if relevant, attributes are not treated as nodes). Hooks allow you to execute your own subroutines at given steps of this traversal. However, the whole hook business is experimental at the moment and likely to change. If you use any of the existing hooks or wish for other ones you may want to let me know because this will certainly influence the stability and development of this interface.

Right now, to set your own hooks you can set one of the following attributes to a code reference of your choice.

Currently, there are four hooks:

Examples:

  $rasterize->start_node_hook(sub { ... })

Some hooks have non-trivial defaults. Therefore SVG::Rasterize provides the following methods to restore the default behaviour:

Rasterization Backend

SVG::Rasterize does not render pixel graphics itself. By default, it uses the cairo library through its Perl bindings. However, the interface could also be implemented by other backends. In the future, it will be documented in SVG::Rasterize::Engine. Currently, the interface has to be considered unstable, though, and the documentation is sparse.

engine_class

This attribute defaults to SVG::Rasterize::Engine::PangoCairo. It can be set as an object attribute or temporarily as a parameter to the rasterize method.

engine_args

This attribute can hold a HASH reference. The corresponding hash is given to the constructor of the rasterization engine when it is called by rasterize. engine_args can be set as an object attribute or temporarily as a parameter to the rasterize method.

engine

  $rasterize->engine

This attribute holds the interface object to the rasterization backend, by default a SVG::Rasterize::Engine::PangoCairo object. The object is created by the rasterize method.

The attribute is readonly, but, of course, you are able to manipulate the object directly via its methods. However, this is not part of the normal workflow and you do this on your own risk ;-).

White Space Handling

The XML specification (http://www.w3.org/TR/2006/REC-xml11-20060816/#AVNormalize) states that an attribute value unless it is of the type CDATA shall be normalized such that leading and trailing white space is removed and internal white space is flattened to single space characters. XML entities can complicate this normalization, see the specification for details.

If the SVG tree to be rasterized by SVG::Rasterize comes out of an parsed XML document then the parser should have performed this normalization already. However, the tree might also be constructed directly using the SVG module. In order to prevent SVG::Rasterization from choking on an attribute like stroke-width="2pt " it performs by default an additional normalization run:

  $value =~ s/^$WSP*//;
  $value =~ s/$WSP*$//;
  $value =~ s/$WSP+/ /g;

where

  $WSP = qr/[\x{20}\x{9}\x{D}\x{A}]/;  # space, tab, CR, LF

To prevent this normalization, you can set the normalize_attributes attribute (as object attribute or as parameter to rasterize) to a false value.

SVG Validation

SVG::Rasterize is not an SVG validator. It does check a lot of things including the validity of the element hierarchy, the required presence and absence of attributes and the values of all attributes it interpretes plus some that it does not interprete. However, it does not (and probably will never) claim to detect all errors in an SVG document.

Attributes and Methods for Developers

state

Readonly attribute. Holds the current SVG::Rasterize::State object during tree traversal. Not internal because it is used by exception methods to retrieve the current state object (in order to store it in the exception object for debugging purposes).

init

  $rasterize->init(%args)

If you overload init, your method should also call this one.

For each given argument, init calls the accessor with the same name to initialize the attribute. If such an accessor (or in fact, any method of that name) does not exist a warning is printed and the argument is ignored. Readonly attributes that are allowed to be set at initialization time are set separately at the beginning.

in_error

Expects an exception object or error message. Creates a fresh SVG::Rasterize::State object (without any transform etc.) and calls in_error_hook (which by default draws a translucent checkerboard across the image). After that, it dies with the given message.

Before you call in_error directly, check out SVG::Rasterize::Exception.

absolute_font_size

  $size = $rasterize->absolute_font_size('x-large')

Returns the current numerical value (in user units) corresponding to a given absolute font size keyword. The method is designed also to be used to check if a given string is an absolute font size keyword at all. Therefore it returns undef if the input value is undef or not an absolute font size keyword.

relative_font_size

  $size = $rasterize->relative_font_size('larger')

NB: Currently, this method throws an exception if a relative font size keyword is given saying that these keywords are not supported, yet. The following describes the future behaviour.

Returns the current numerical value (in user units) corresponding to a given relative font size keyword. The method is designed also to be used to check if a given string is an relative font size keyword at all. Therefore it returns undef if the input value is undef or not an relative font size keyword.

Class Methods

multiply_matrices

2D affine transformation can be represented by 3 x 3 matrices of the form:

  ( a  c  e )
  ( b  d  f )
  ( 0  0  1 )

In this case, the concatenation of such transformations is represented by canonical matrix multiplication. This method takes two ARRAY references of the form [a, b, c, d, e, f] whose entries correspond to the matrix entries above and returns an ARRAY reference with 6 entries representing the product matrix.

The method can be called either as subroutine or as class method or as object method:

  $product = multiply_matrices($m, $n)
  $product = SVG::Rasterize->multiply_matrices($m, $n)
  $product = $rasterize->multiply_matrices($m, $n)

Note that multiply_matrices does not perform any input check. It expects that you provide (at least) two ARRAY references with (at least) 6 numbers each. If you pass more parameters then the last two are used. If they contain more than 6 entries then the first 6 are used.

endpoint_to_center

  @result = endpoint_to_center(@input)
  @result = SVG::Rasterize->endpoint_to_center(@input)
  @result = $rasterize->endpoint_to_center(@input)

Rasterization engines like SVG::Rasterize::Engine::PangoCairo might use center parameterization instead of endpoint parameterization of an elliptical arc (see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes). This method calculates the center parameters from the endpoint parameters given in a SVG path data string. As indicated above, it can be called as a subroutine or a class method or an object method. The required parameters are:

If the reparameterization cannot be computed an empty list is returned. This can have two possible reasons. Either one of the radii is equal (with respect to machine precision) to 0 or the start and end point of the arc are equal (with respect to machine precision). The first case should have been checked before (note that no rounding problems can occur here because no arithmetics is done with the passed values) because in this case the arc should be turned into a line. In the second case, the arc should just not be drawn. Be aware that this latter case includes a full ellipse. This means that a full ellipse cannot be drawn as one arc. The SVG specification is very clear on that point. However, an ellipse can be drawn as two arcs.

Note that the input values are not validated (e.g. if the values are numbers, if the flags are either 0 or 1 and so on). It is assumed that this has been checked before. Furthermore, it is not checked if the radii are very close to 0 or start and end point are nearly equal.

A list of the following parameters is returned (unless an empty list is returned due to the reasons mentioned above):

adjust_arc_radii

  @result = adjust_arc_radii(@input)
  @result = SVG::Rasterize->adjust_arc_radii(@input)
  @result = $rasterize->adjust_arc_radii(@input)

The SVG specification requires that the radii of an elliptic arc are increased automatically if the given values are too small to connect the given endpoints (see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes). This situation can arise from rounding errors, but also for example during an animation. Moreover, if a given radius is negative then the absolute value is to be used. This method takes care of these adjustments and returns the new values plus some intermediate values that might be useful for callers, namely endpoint_to_center.

In detail, it requires the following parameters:

Note that the input values are not validated (e.g. if the values are numbers etc.). It is assumed that this has been checked before. Furthermore, it is not checked if the radii are very close to 0 or start and end point are nearly equal.

The following values are guaranteed to be returned:

This is all if one of the radii is equal to 0. Otherwise, the following additional values are returned:

EXAMPLES ^

There are a few example scripts in the examples directory of the tar ball. However, they rather illustrate the currently supported SVG subset than options of SVG::Rasterize. In order to run the example scripts, you need to have the SVG module installed which is formally only required for testing.

DIAGNOSTICS ^

Error processing

The SVG documentation specifies how SVG interpreters should react to certain incidents. The relevant section can be found here: http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.

This section describes how some of these instructions are implemented by SVG::Rasterize and how it reacts in some other situations in which the specification does not give instructions.

In error

According to the SVG specification (see http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing, a document is "in error" if:

In these cases, the rendering is supposed to stop before the incriminated element. Exceptions are path, polyline, and polygon elements which are supposed to be partially rendered up to the point where the error occurs.

Furthermore, a "highly perceivable indication of error shall occur. For visual rendering situations, an example of an indication of error would be to render a translucent colored pattern such as a checkerboard on top of the area where the SVG content is rendered."

In SVG::Rasterize this is done by the in_error_hook. By default, it indeed draws a translucent (rgb(45, 45, 45) with opacity 0.6) checkerboard with 8 fields along the width or height (whichever is shorter). This behaviour can be changed by setting the in_error_hook. Setting the hook to undef or sub {} will disable the process.

SVG::Rasterize exceptions

When SVG::Rasterize encounters a problem it usually throws an exception. The cases where only a warning is issued a rare. This behaviour has several reasons:

The exceptions are thrown in form of objects. See Exception::Class for a detailed description. See below for a description of the classes used in this distribution. All error messages are described in SVG::Rasterize::Exception.

Invalid and numerically unstable values

There are situations where certain values cannot be dealt with, e.g. denominators of 0 or negative radicands. Examples are skews of 90 degrees or elliptical arcs where one radius is 0. In these situations, SVG::Rasterize checks for these cases and acts accordingly. Great care is taken to check directly those values which are used as denominator, radicand etc. and not some mathematically equivalent expression which might evaluate to a slightly different value due to rounding errors. However, it is not checked if such an expression is very close to a critical value which might render the processing numerically unstable. I do not want to impose a certain notion of "too close" on SVG authors. Instead it is left to them to check for these border cases. However, the underlying rasterization engine might still impose boundaries.

Exceptions

SVG::Rasterize currently uses the following exception classes. This framework is experimental and might change considerably in future versions. See Exception::Class on how you can make use of this framework. See SVG::Rasterize::Exception for a detailed list of error messages.

Warnings

DEPENDENCIES ^

Additionally, testing requires the following modules:

BUGS AND LIMITATIONS ^

Bugs

Please report any bugs or feature requests to bug-svg-rasterize at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=SVG-Rasterize. I will be notified, and then you will automatically be notified of progress on your bug as I make changes.

Limitations

Caveats

IMPLEMENTATION NOTES ^

This documentation is largely for myself. Read on if you are interested, but this section generally does not contain documentation on the usage of SVG::Rasterize.

Deferred Rasterization

Some elements (namely text and textPath elements) can only be rasterized once their entire content is known (e.g. for alignment issues). In these situations, the SVG::Rasterize::State objects representing the deferred nodes are pushed to a _rasterization_queue. The content is then only rasterized once the root element of this subtree is about to run out of scope.

INTERNALS ^

Regular Expressions

All reused regular expressions are located in SVG::Rasterize::Regexes. In general, they should be considered as private variables and are documented there for inspection only. Anyway, most of them are compiled into other expressions, so changing them would probably not achieve what you might expect. The expressions listed here are exceptions to this rule. They are considered part of the interface and you can change them (at your own risk ;-) ).

Internal Attributes

These attributes and the methods below are just documented for myself. You can read on to satisfy your voyeuristic desires, but be aware of that they might change or vanish without notice in a future version.

Internal Methods

FOOTNOTES ^

SEE ALSO ^

ACKNOWLEDGEMENTS ^

This distribution builds heavily on the cairo library and its Perl bindings.

AUTHOR ^

Lutz Gehlen, <perl at lutzgehlen.de>

LICENSE AND COPYRIGHT ^

Copyright 2010-2011 Lutz Gehlen.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

syntax highlighting: