Website Downloads Documentation Knowledgebase Wiki Issue tracker Commercial support

Using SVG

Update: Daisy 1.5 contains this SVG support out-of-the-box, including some improvements such as automatic resizing of the embedded SVG, and SVG rendering support in books. I'll leave this article here as background information, and because it serves as an example for similar extensions.

Introduction

This tutorial shows an approach for handling SVG graphics in Daisy. It also serves as an introduction to defining document types, using document-type specific styling and creating a Daisy Wiki extension.

You need the Daisy 1.4 final release for this.

Creating a document type

Let's start by creating a part type and document type specifically for SVG documents.

First go to the administration pages:

  • Log in to the Daisy Wiki with a user that has the Administrator role.
  • Switch to the Administrator role using the role menu, if needed.
  • Select the Administration link that appears in the navigation.

Then create a part type called SvgData:

  • Select "Manage part types".
  • Select "Create a new part type".
  • In the name field, enter SvgData.
  • In the mime-types field, enter image/svg+xml.
  • Leave the other fields untouched.
  • Press save.

Then create a document type called "SvgDocument":

  • Select "Document types" in the navigation.
  • Select "Create a new document type".
  • In the name field, enter SvgDocument.
  • Below "Part Types", select SvgData from the drop down list and press the "Add Part Type" button next to it.
  • Press save.

Creating a document

Go back to some Daisy site by selecting the "Daisy Home" link in the top right corner, and then selecting some site of your preference.

Select "New Document" in the navigation, and then choose SvgDocument from the list.

You now see the document editor with an upload facility (instead of the usual HTML editor).

Save this test svg document (image/svg+xml, 1.1 kB, info) to your local drive, and then upload it in the new document.

Check that the mime type is correctly specified as image/svg+xml.

Change the name of the document to something of your choice, e.g. "Test SVG".

Press Save to save the new document.

After this you'll simply see the Test SVG document with a download link to download the SVG image. If you use a browser that can render SVG images, you can click that link to see the image.

non-rendered svg document
Click to enlarge

We would like to have this image displayed inline, and rendered as a PNG image for browsers that do not support SVG.

Creating a Daisy Wiki extension to render SVG

Here is where the extension mechanism of the Daisy Wiki comes into play. A Daisy Wiki extension is simply a custom Cocoon sitemap that can implement anything you like. Don't be afraid if you don't know Cocoon, all you need to know is below.

For rendering SVG to a raster image format, we will make use of Batik. Cocoon provides Batik integration, however this is part of an optional "block" that is not included by default with Daisy. Therefore, download the following two jars:

and put them in the following directory:

DAISY_HOME/daisywiki/webapp/daisy/WEB-INF/lib

Restart the Daisy Wiki after adding these jars.

Now create a new subdirectory called svg as child of the following directory:

DAISY_HOME/daisywiki/webapp/daisy/sites/cocoon/

so that you thus get:

DAISY_HOME/daisywiki/webapp/daisy/sites/cocoon/svg

In this newly created directory, create a file called sitemap.xmap with the following content:

<?xml version="1.0"?>
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">

  <map:components>
    <map:serializers default="html">
      <map:serializer name="svg2png"
                      src="org.apache.cocoon.serialization.SVGSerializer"
                      mime-type="image/png"
                      logger="sitemap.serializer.svg2png"/>
    </map:serializers>
  </map:components>

  <map:views>
  </map:views>

  <map:resources>
  </map:resources>

  <map:pipelines>

    <map:pipeline type="caching">
      <map:parameter name="outputBufferSize" value="8192"/>

      <map:match pattern="rendersvg">
        <map:generate src="daisy:{request-param:documentId}@{request-param:branch}
              :{request-param:language}:{request-param:version}!{request-param:part}"/>
        <map:serialize type="svg2png"/>
      </map:match>

    </map:pipeline>

  </map:pipelines>

</map:sitemap>

The content of the src attribute (daisy:...) must be on one line, without whitespace in between. It has been split in the listing above since otherwise it wouldn't fit on everyones screen.

Note the following things in this sitemap (excuse the very poor Cocoon explanation, but is is sufficient to comprehend what is done here):

  • The map:serializer element declares the svg2png serializer, so that Cocoon knows about it. This serializer takes as input an SVG document and generates as output a PNG-rendered version of the SVG image.
  • The content of the <map:match pattern="rendersvg"> element will be executed when the URL path is "rendersvg" (inside the context where this sitemap gets mounted, see the full URL further on)
    • The <map:generate> element reads XML from somewhere, parses it and sends the parse events (start element, end element, etc.) down the pipeline. This "somewhere" is specified in the src attribute, which here is a special "daisy:" sort-of-URL. The format of this URL1 is:
      daisy:<documentId>@<branch>:<language>:<version>!<partTypeName>

      which is thus similar to the normal daisy: links that are embedded in Daisy documents, with the exception that a part type is specified on the end. As with normal daisy links, the branch, language and version specifications are optional.

    • The <map:serialize type="svg2png"/> element retrieves the XML parse events that come from the generator, interprets them as SVG and writes the rendered SVG image to the response (that goes back to the browser).

Now we can try out this extension. In a webbrowser, enter an URL similar to the following one (on one line of course):

http://localhost:8888/daisy/coolsite/ext/svg/rendersvg
   ?documentId=3&branch=main&language=default&version=live&part=SvgData

But change it according to your configuration:

  • adjust host name and port if necessary
  • change the site name from "coolsite" to the name of your site
  • change the value of the documentId request parameter (here 3) to the ID of the document you just created
  • In case you would not use the main branch and the default language, change those parameters also accordingly

After loading that URL, you should see the rendered SVG image, which looks like this:
testsvg

Create a document type specific stylesheet for HTML

Now we would like to have the SVG image displayed directly when we go to the SVG document in Daisy. For this, we will create a document type specific stylesheet. This is a custom XSLT that is used for rendering documents that are of a certain document type.

This is done as follows: create a file called SvgDocument.xsl (= name of the document type + ".svg" extension) in the following directory:

DAISY_HOME/daisywiki/webapp/daisy/resources/document-styling/default/html

Put the following inside the SvgDocument.xsl file and save it:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:d="http://outerx.org/daisy/1.0">

  <xsl:import href="daisyskin:xslt/document-to-html.xsl"/>

  <xsl:template match="d:document">
    <br/>
    <img src="{$documentBasePath}ext/svg/rendersvg?documentId={@id}&amp;branch={@branch}
           &amp;language={@language}&amp;version={@dataVersionId}&amp;part=SvgData"/>
    <br/>
  </xsl:template>

</xsl:stylesheet>

Again, the content of the src attribute of the <img> tag should be on one line, wihtout whitespace in between.

If you now go to the SVG document, you should see the rendered image:

svg rendered inline in daisy

Some browsers, such as Firefox 1.5 and Konqueror, and other browsers with some plugin installed, can directly render SVG. We can easily take advantage of this by slightly modify our SvgDocument.xsl:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:d="http://outerx.org/daisy/1.0">

  <xsl:import href="daisyskin:xslt/document-to-html.xsl"/>

  <xsl:template match="d:document">
    <br/>
    <object data="{$documentBasePath}{@id}/version/
             {@dataVersionId}/part/SvgData/data/abc.svg" type="image/svg+xml">
      <img src="{$documentBasePath}ext/svg/rendersvg?documentId={@id}&amp;branch={@branch}
             &amp;language={@language}&amp;version={@dataVersionId}&amp;part=SvgData"/>
    </object>
    <br/>
  </xsl:template>

</xsl:stylesheet>

Again, put the content of the data attribute and the src attribute on one line.

By using the <object> tag, browsers which understand SVG will directly render the SVG document, and ignore the content of the <object> tag. Other browsers which don't understand SVG will render the <img> tag, and thus delegate the rendering of the SVG to our Daisy Wiki extension.

As you will see if you try this, the <object> frame will likely not be correctly sized and thus cause a part of the image to be clipped or scrollbars to appear.

Create a document type specific stylesheet for XSL-FO (PDF)

The Daisy Wiki renders PDF images by transforming the documents into XSL-FO which is then processed by Apache FOP into a PDF. Apache FOP happens to support SVG too (via Batik again), which allows the SVG to be rendered inside the PDF. The nice thing about this is that the SVG will be embedded as a vector image, not as as bitmap image, so that is doesn't take much space and the edges of the lines and curves are sharp when zooming in and/or printing, as shown in the following illustration.

svg in pdf

Create a file called SvgDocument.xsl in the following directory (this directory might not yet exist, create it if needed):

DAISY_HOME/daisywiki/webapp/daisy/resources/document-styling/default/xslfo
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:d="http://outerx.org/daisy/1.0"
  xmlns:fo="http://www.w3.org/1999/XSL/Format">

  <xsl:import href="daisyskin:xslt/document-to-html.xsl"/>
  <xsl:param name="documentBasePath"/>

  <xsl:template match="d:document">
    <fo:external-graphic src="url('http://localhost:8888/{$documentBasePath}{@id}
       /version/{@dataVersionId}/part/SvgData/data?branch={@branch}&amp;language={@language}')"/>
  </xsl:template>

</xsl:stylesheet>

Put the value of the src attribute on one line.

Note that we need to do something here which is not very nice: the src is hardcoded to fetch the image from "http://localhost:8888". Thus this will send out a new HTTP request to fetch the image. Unfortunately, with the current version of FOP this is the only option we have. Since this is a new HTTP request, it will also not use the browsers' session and thus fetch the image as guest user. If the SVG document is not accessible for the guest user, this will pose a problem.

By the way, the same is done for normal Daisy images, however these are processed by a special transformer which will insert the correct server name and port, and add the sessionid of the current user (if any) to the URL.

Include the SVG document in another document to have inline SVG images

Now that we have the SVG image rendered, we would like to embed it inside some other document in Daisy. This can be done by simply using the document include feature. If you don't know how this works, follow these instructions:

  • Create a new document of type SimpleDocument (or similar)
  • Type in whathever text you want.
  • Where you want to insert the SVG image, insert a blank line and choose "Include" from the block-style dropdown menu (= the dropdown left on the editor toolbar)
  • Enter a Daisy link refering to the created SVG image, for example:
    daisy:3

    There is also a button on the toolbar to look this up, if you don't remember the document ID.

  • Save the document
  • You should see the SVG image rendered along with the rest of the document.

svg include sample

Possible improvements and other notes

As mentioned and seen, the image size needs to be specified when using the <object> tag or when embedding the image in PDF. This could be done by adding fields for this purpose to the SvgDocument document type.

Instead of having to download/upload the SVG image for editing, for simple images it would be possible to use a browser-embedded SVG editor (if such a thing exists), which is possible through the custom part editors of the Daisy Wiki.

The technique we have used here can be applied to many other situations. In fact, it is already used by the "MultimediaObject" document type included with Daisy (from version 1.4) which allows embedding things such as flash and mpeg movies or audio streams. A nice application would also be charting: the chart data could be entered in a part (using some XML format, possibly edited with a custom part editor) and then dynamically rendered, for example by making use of fins.

1.Yes, I know this is not a valid URL format due to the illegal use of the at and colon characters.
Comments (0)
Advertisement

Daisy hosting, installation, support. Workshops and turnkey Daisy CMS projects. Get Daisy from its creators.

outerthought.org

Downloads provided by

SourceForge.net Logo

Open source stats