| <?xml version="1.0"?> |
| <!DOCTYPE document SYSTEM "./dtd/document-v10.dtd"> |
| |
| <!-- ========================================================================= --> |
| <!-- Copyright (C) The Apache Software Foundation. All rights reserved. --> |
| <!-- --> |
| <!-- This software is published under the terms of the Apache Software License --> |
| <!-- version 1.1, a copy of which has been included with this distribution in --> |
| <!-- the LICENSE file. --> |
| <!-- ========================================================================= --> |
| |
| <!-- ========================================================================= --> |
| <!-- author tkormann@apache.org --> |
| <!-- version $Id$ --> |
| <!-- ========================================================================= --> |
| |
| <document> |
| <header> |
| <title>Image Transcoder Tutorial</title> |
| <subtitle>A brief introduction to the image transcoder API</subtitle> |
| <authors> |
| <person name="Thierry Kormann" email="tkormann@apache.org"/> |
| </authors> |
| </header> |
| |
| <body> |
| |
| <!-- ##################################################################### --> |
| <s1 title="Introduction"> |
| <p> |
| The goal of the transcoder API (package |
| <code>org.apache.batik.transcoder</code>) is to provide a generic |
| API for transcoding an input to an output. First, this document |
| explains the basic transcoder API that <code>Transcoder</code>, |
| <code>TranscoderInput</code> and <code>TranscoderOutput</code> |
| define -- and thus all transcoders have in common. Next, it |
| describes how to use the image transcoder API (package |
| <code>org.apache.batik.transcoder.image</code>) which lets you |
| rasterize an SVG document fragment to a raster image such as JPEG |
| or PNG. |
| </p> |
| </s1> |
| |
| <s1 title="The Transcoder API"> |
| <p> |
| The <code>org.apache.batik.transcoder</code> package defines 5 major classes: |
| </p> |
| <dl> |
| <dt><code>Transcoder</code></dt> |
| <dd> |
| Defines the interface that all transcoders implement. You can |
| transcode a specific input using a specific output by invoking the |
| <code>transcode</code> method. Although there is no assumption on the |
| input and output format, a specific transcoder may or may not support |
| a particular type of input or output. For example, the image |
| transcoders accept an SVG <code>org.w3c.dom.Document</code>, a |
| <code>Reader</code>, an <code>InputStream</code>, or a |
| <code>URI</code> as an input but only supports a byte stream for the |
| output. |
| <br /><br /> |
| </dd> |
| |
| <dt><code>TranscoderInput</code></dt> |
| <dd> |
| Defines the input of a transcoder. There are various ways to create an |
| input and the most commons are already part of the API. The default |
| implementation lets you create an input using a |
| <code>org.w3c.dom.Document</code>, a <code>Reader</code>, an |
| <code>InputStream</code>, a <code>org.xml.sax.XMLReader</code>, or a |
| <code>URI</code>. |
| <br /><br /> |
| </dd> |
| |
| <dt><code>TranscoderOutput</code></dt> |
| <dd> |
| Defines the output of a transcoder. There are various ways to create an |
| output and the most commons are already part of the API. The default |
| implementation lets you create an output using a |
| <code>org.w3c.dom.Document</code>, a <code>Writer</code>, an |
| <code>OutputStream</code>, a <code>org.xml.sax.XMLFilter</code>, or a |
| <code>URI</code>. |
| <br /><br /> |
| </dd> |
| |
| <dt><code>TranscodingHints</code></dt> |
| <dd> |
| The <code>TranscodingHints</code> class contains different hints which can |
| be used to control the various options or parameters of a |
| transcoder. Each transcoder provides its own set of hints. A hint is |
| specified by (key, value) pair. For example, the |
| <code>JPEGTranscoder</code> provides a hint to control the encoding quality. |
| <br /><br /> |
| </dd> |
| |
| <dt><code>ErrorHandler</code></dt> |
| <dd> |
| This class provides a way to get the errors and/or warnings that might |
| occur while transcoding. A default implementation is provided but |
| you can, for example, implement your own handler that display a dialog |
| instead of stack trace. |
| </dd> |
| </dl> |
| </s1> |
| |
| <!-- ##################################################################### --> |
| <s1 title="How to Use the Image Transcoder API"> |
| <p> |
| The <code>org.apache.batik.transcoder.image</code> package provides an |
| easy way to transcode an SVG document to a raster image such as JPEG or |
| PNG. Additional raster image formats can be added by subclassing the |
| <code>ImageTranscoder</code> and implementing the |
| <code>writeImage</code> method. Although, in next sections, the |
| examples will use the JPEG transcoder, the PNG transcoder works the |
| same way. |
| </p> |
| |
| <s2 title="Creating an Image"> |
| <p> |
| The following example, using the <code>JPEGTranscoder</code> shows how to |
| trasnform a SVG document to a JPEG image. |
| </p> |
| <source> |
| SaveAsJpeg.java |
| =============== |
| |
| import java.io.*; |
| import org.apache.batik.transcoder.image.JPEGTranscoder; |
| import org.apache.batik.transcoder.TranscoderInput; |
| import org.apache.batik.transcoder.TranscoderOutput; |
| |
| public class SaveAsJPEG { |
| |
| public static void main(String [] args) throws Exception { |
| |
| // create a JPEG transcoder |
| <strong>JPEGTranscoder t = new JPEGTranscoder();</strong> |
| // set the transcoding hints |
| <strong>t.addTranscodingHint(JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, |
| "org.apache.crimson.parser.XMLReaderImpl");</strong> |
| <strong>t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, |
| new Float(.8));</strong> |
| // create the transcoder input |
| String svgURI = new File(args[0]).toURL().toString(); |
| <strong>TranscoderInput input = new TranscoderInput(svgURI);</strong> |
| // create the transcoder output |
| OutputStream ostream = new FileOutputStream("out.jpg"); |
| <strong>TranscoderOutput output = new TranscoderOutput(ostream);</strong> |
| // save the image |
| <strong>t.transcode(input, output);</strong> |
| // flush and close the stream then exit |
| ostream.flush(); |
| ostream.close(); |
| System.exit(0); |
| } |
| } |
| </source> |
| <p> |
| The code creates a <code>JPEGTranscoder</code> and sets the |
| transcoding hints. The first hint indicates the XML parser to use. The |
| second hint sets the encoding quality. Then, an input and an output |
| are created. The input is created using the first command line |
| argument which should represent a URI. The output is a byte stream |
| representing a file called "out.jpg". Finally, the |
| <code>transcode</code> method is invoked and the byte stream is |
| closed. |
| </p> |
| <p> |
| Although not shown above, the program might have specified additional |
| hints to indicate a user style sheet, the preferred language of the |
| document or the background color. |
| </p> |
| <p> |
| <strong>Try this:</strong> |
| </p> |
| <ol> |
| <li>Compile and run the program: SaveAsJPEG.java. You will need a SVG document.<br /> |
| <code>% java SaveAsJPEG <filename>.svg</code></li> |
| <li>Take a look at: out.jpg</li> |
| </ol> |
| </s2> |
| |
| |
| <s2 title="Defining the Size of the Image"> |
| <p> |
| By adding the following line of code to the previous example, you will |
| specify the raster image size (in pixels). The new transcoding hint |
| <code>KEY_WIDTH</code> lets you specify the raster image width. As the |
| raster image height is not provided (using the |
| <code>KEY_HEIGHT</code>), the transcoder will compute the raster image |
| dimension by keeping the aspect ratio of the SVG document. |
| </p> |
| <source> |
| t.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, new Integer(100)); |
| </source> |
| <p> |
| The transcoder will have the same behavior if you specify the |
| <code>KEY_HEIGHT</code> without initializing the |
| <code>KEY_WIDTH</code>. In all cases (though both keys are provided), |
| the transcoder will preserve the apsect ratio of the SVG document. |
| </p> |
| </s2> |
| |
| <s2 title="Selecting an Area of Interest"> |
| <p> |
| The image transcoder lets you specify an area of interest (ie. a part |
| of the SVG document). The key <code>KEY_AOI</code> enables to select |
| the region of the SVG document to render. The value of this key must |
| be a <code>java.awt.Rectangle</code> specified in pixels and described |
| in the SVG document's space. The following example shows how you can |
| split a SVG document into 4 tiles. |
| </p> |
| <source> |
| SaveAsJPEGTiles.java |
| ==================== |
| |
| import java.io.*; |
| import java.awt.*; |
| import org.apache.batik.transcoder.image.JPEGTranscoder; |
| import org.apache.batik.transcoder.TranscoderInput; |
| import org.apache.batik.transcoder.TranscoderOutput; |
| |
| public class SaveAsJPEGTiles { |
| |
| JPEGTranscoder trans = new JPEGTranscoder(); |
| |
| public SaveAsJPEGTiles() { |
| trans.addTranscodingHint(JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, |
| "org.apache.crimson.parser.XMLReaderImpl"); |
| trans.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, |
| new Float(.8)); |
| } |
| |
| public void tile(String inputFilename, |
| String outputFilename, |
| Rectangle aoi) throws Exception { |
| <strong>trans.addTranscodingHint(JPEGTranscoder.KEY_WIDTH, |
| new Integer(aoi.width));</strong> |
| <strong>trans.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, |
| new Integer(aoi.height));</strong> |
| <strong>trans.addTranscodingHint(JPEGTranscoder.KEY_AOI, aoi);</strong> |
| String svgURI = new File(inputFilename).toURL().toString(); |
| TranscoderInput input = new TranscoderInput(svgURI); |
| OutputStream ostream = new FileOutputStream(outputFilename); |
| TranscoderOutput output = new TranscoderOutput(ostream); |
| trans.transcode(input, output); |
| ostream.flush(); |
| ostream.close(); |
| } |
| |
| public static void main(String [] args) throws Exception { |
| SaveAsJPEGTiles p = new SaveAsJPEGTiles(); |
| <strong>String in = "samples/anne.svg"; |
| int documentWidth = 450; |
| int documentHeight = 500;</strong> |
| int dw2 = documentWidth / 2; |
| int dh2 = documentHeight / 2; |
| p.tile(in, "tileTopLeft.jpg", new Rectangle(0, 0, dw2, dh2)); |
| p.tile(in, "tileTopRight.jpg", new Rectangle(dw2, 0, dw2, dh2)); |
| p.tile(in, "tileBottomLeft.jpg", new Rectangle(0, dh2, dw2, dh2)); |
| p.tile(in, "tileBottomRight.jpg", new Rectangle(dw2, dh2, dw2, dh2)); |
| System.exit(0); |
| } |
| } |
| </source> |
| <p> |
| This code splits the same document "anne.svg" into four tiles of the |
| same size. Considering the document and its original size, we can |
| determine four regions. Then we rasterize each region using the |
| <code>KEY_AOI</code> key. Note that we also specify the image width |
| and height to be the same as the area of interest width and height (so |
| we keep a 1:1 zoom factor). You can of course combine the |
| <code>KEY_WIDTH</code>, <code>KEY_HEIGHT</code> keys with the |
| <code>KEY_AOI</code>. In that case, first the area of interest will |
| determine which part of the SVG document has to be rendered - then |
| that part could be zoom in or out depending on the specified raster |
| image size. |
| </p> |
| <p> |
| <strong>Try this:</strong> |
| </p> |
| <ol> |
| <li>Compile and run the program: SaveAsJPEGTiles.java. You will need the "anne.svg" document.<br /> |
| <code>% java SaveAsJPEGTiles</code></li> |
| <li>Take a look at: tileTopRight.jpg, tileTopRight.jpg, tileBottomRight.jpg |
| and tileBottomLeft.jpg</li> |
| </ol> |
| </s2> |
| |
| <s2 title="Generating an Image from a SVG DOM Tree"> |
| <p> |
| The following code creates and saves a SVG DOM tree. |
| </p> |
| <source> |
| DOMRasterizer.java |
| ================== |
| |
| import java.io.*; |
| import org.apache.batik.transcoder.image.JPEGTranscoder; |
| import org.apache.batik.transcoder.TranscoderInput; |
| import org.apache.batik.transcoder.TranscoderOutput; |
| import org.apache.batik.dom.svg.SVGDOMImplementation; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.DOMImplementation; |
| |
| public class DOMRasterizer { |
| |
| public Document createDocument() { |
| <strong>DOMImplementation impl = SVGDOMImplementation.getDOMImplementation(); |
| String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; |
| Document document = |
| impl.createDocument(svgNS, "svg", null); |
| Element root = document.getDocumentElement();</strong> |
| root.setAttributeNS(null, "width", "450"); |
| root.setAttributeNS(null, "height", "500"); |
| |
| Element e; |
| e = document.createElementNS(svgNS, "rect"); |
| e.setAttributeNS(null, "x", "10"); |
| e.setAttributeNS(null, "y", "10"); |
| e.setAttributeNS(null, "width", "200"); |
| e.setAttributeNS(null, "height", "300"); |
| e.setAttributeNS(null, "style", "fill:red;stroke:black;stroke-width:4"); |
| root.appendChild(e); |
| |
| e = document.createElementNS(svgNS, "circle"); |
| e.setAttributeNS(null, "cx", "225"); |
| e.setAttributeNS(null, "cy", "250"); |
| e.setAttributeNS(null, "r", "100"); |
| e.setAttributeNS(null, "style", "fill:green;fill-opacity:.5"); |
| root.appendChild(e); |
| |
| return document; |
| } |
| |
| public void save(Document document) throws Exception { |
| JPEGTranscoder t = new JPEGTranscoder(); |
| t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, |
| new Float(.8)); |
| <strong>TranscoderInput input = new TranscoderInput(document);</strong> |
| OutputStream ostream = new FileOutputStream("out.jpg"); |
| TranscoderOutput output = new TranscoderOutput(ostream); |
| t.transcode(input, output); |
| ostream.flush(); |
| ostream.close(); |
| } |
| |
| public static void main(String [] args) throws Exception { |
| DOMRasterizer rasterizer = new DOMRasterizer(); |
| Document document = rasterizer.createDocument(); |
| rasterizer.save(document); |
| System.exit(0); |
| } |
| } |
| </source> |
| <p> |
| This code is divided into two distinct parts. |
| </p> |
| <dl> |
| <dt>Creating a SVG DOM tree</dt> |
| <dd> |
| <br />See the <code>createDocument</code> method<br /> Three steps are |
| required at this time. The first one consists on getting the Batik SVG |
| DOM implementation (via the SVGDOMImplementation class). Then, you can |
| create a <code>org.w3c.dom.Document</code> (which is a SVG Document by |
| the way) by invoking the <code>createDocument</code> method with the |
| svg namespace URI and the "svg" document element. At last, you can get |
| the document element and start to build your DOM tree. <br /><br /> |
| </dd> |
| <dt>Rasterizing your DOM</dt> |
| <dd> |
| <br />See the <code>save</code> method<br /> Similar to the previous |
| examples, you can transcode a SVG document to a raster image by |
| creating a <code>TransocderInput</code> with this time, the SVG Document. |
| <br /><br /> |
| </dd> |
| </dl> |
| <p> |
| <strong>Try this:</strong> |
| </p> |
| <ol> |
| <li>Compile and run the program: DOMRasterizer.java.<br /> |
| <code>% java DOMRasterizer</code></li> |
| <li>Take a look at: out.jpg</li> |
| </ol> |
| </s2> |
| |
| </s1> |
| |
| |
| </body> |
| </document> |
| |