KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > outerj > daisy > books > publisher > impl > publicationprocess > SvgRenderTask


1 /*
2  * Copyright 2004 Outerthought bvba and Schaubroeck nv
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.outerj.daisy.books.publisher.impl.publicationprocess;
17
18 import org.outerj.daisy.books.store.BookInstance;
19 import org.outerj.daisy.books.publisher.impl.BookInstanceLayout;
20 import org.outerj.daisy.books.publisher.impl.util.AbstractContentHandler;
21 import org.outerj.daisy.books.publisher.impl.util.PublicationLog;
22 import org.outerj.daisy.xmlutil.LocalSAXParserFactory;
23 import org.outerj.daisy.xmlutil.XmlSerializer;
24 import org.xml.sax.InputSource JavaDoc;
25 import org.xml.sax.ContentHandler JavaDoc;
26 import org.xml.sax.Attributes JavaDoc;
27 import org.xml.sax.SAXException JavaDoc;
28 import org.apache.batik.transcoder.image.PNGTranscoder;
29 import org.apache.batik.transcoder.image.JPEGTranscoder;
30 import org.apache.batik.transcoder.*;
31 import org.apache.batik.bridge.BridgeContext;
32 import org.apache.batik.bridge.UserAgentAdapter;
33 import org.apache.batik.bridge.GVTBuilder;
34 import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
35 import org.apache.batik.util.XMLResourceDescriptor;
36 import org.apache.cocoon.xml.AttributesImpl;
37 import org.outerx.daisy.x10Bookstoremeta.ResourcePropertiesDocument;
38 import org.w3c.dom.Document JavaDoc;
39 import org.w3c.dom.svg.SVGDocument;
40
41 import javax.xml.parsers.SAXParser JavaDoc;
42 import java.io.InputStream JavaDoc;
43 import java.io.OutputStream JavaDoc;
44 import java.util.Map JavaDoc;
45 import java.awt.*;
46 import java.awt.geom.Dimension2D JavaDoc;
47
48 /**
49  * A book publication process task to render SVG images.
50  * Reacts on a renderSVG tag, renders the referenced image, and replaces this tag with
51  * a normal img tag.
52  *
53  * <p>In contrast to using a Cocoon pipeline with the SVG serializer
54  * (e.g. using the {@link CallPipelineTask}), this task allows to specify
55  * a dpi parameter to generate high-resolution images.
56  */

57 public class SvgRenderTask implements PublicationProcessTask {
58     private final String JavaDoc input;
59     private final String JavaDoc output;
60     private final String JavaDoc outputPrefix;
61     private final String JavaDoc format;
62     private final float dpi;
63     private final float defaultDpi = 96;
64     private final float quality;
65     private final Color backgroundColor;
66     private final boolean enableScripts;
67     private final float maxPrintWidth;
68     private final float maxPrintHeight;
69     private static final String JavaDoc NS = "http://outerx.org/daisy/1.0#bookSvgRenderTask";
70
71     public SvgRenderTask(Map JavaDoc attributes) throws Exception JavaDoc {
72         this.input = PublicationProcessTaskUtil.getRequiredAttribute(attributes, "input", "renderSVG");
73         this.output = PublicationProcessTaskUtil.getRequiredAttribute(attributes, "output", "renderSVG");
74
75         if (attributes.containsKey("outputPrefix")) {
76             outputPrefix = (String JavaDoc)attributes.get("outputPrefix");
77         } else {
78             outputPrefix = "from-svg/";
79         }
80
81         if (attributes.containsKey("format")) {
82             format = (String JavaDoc)attributes.get("format");
83         } else {
84             format = "jpg";
85         }
86
87         if (attributes.containsKey("dpi")) {
88             dpi = parseFloat((String JavaDoc)attributes.get("dpi"), "dpi");
89         } else {
90             dpi = defaultDpi;
91         }
92
93         if (attributes.containsKey("quality")) {
94             quality = parseFloat((String JavaDoc)attributes.get("quality"), "quality");
95         } else {
96             quality = 1f;
97         }
98
99         if (attributes.containsKey("backgroundColor")) {
100             backgroundColor = parseColor((String JavaDoc)attributes.get("backgroundColor"));
101         } else {
102             backgroundColor = null;
103         }
104
105         if (attributes.containsKey("enableScripts")) {
106             enableScripts = "true".equalsIgnoreCase((String JavaDoc)attributes.get("enableScripts"));
107         } else {
108             enableScripts = false;
109         }
110
111         if (attributes.containsKey("maxPrintWidth")) {
112             maxPrintWidth = parseFloat((String JavaDoc)attributes.get("maxPrintWidth"), "maxPrintWidth");
113         } else {
114             maxPrintWidth = 6.45f;
115         }
116
117         if (attributes.containsKey("maxPrintHeight")) {
118             maxPrintHeight = parseFloat((String JavaDoc)attributes.get("maxPrintHeight"), "maxPrintHeight");
119         } else {
120             maxPrintHeight = 8.6f;
121         }
122     }
123
124     private static float parseFloat(String JavaDoc value, String JavaDoc name) throws Exception JavaDoc {
125         try {
126             return Float.parseFloat(value);
127         } catch (NumberFormatException JavaDoc e) {
128             throw new Exception JavaDoc("Invalid float value specified for " + name + ": " + value);
129         }
130     }
131
132     private static Color parseColor(String JavaDoc value) throws Exception JavaDoc {
133         if (!value.startsWith("#") && value.length() != 7) {
134             throw new Exception JavaDoc("Color specification should be in the form #FFFFFF, not: " + value);
135         }
136
137         int r, g, b;
138         try {
139             r = Integer.parseInt(value.substring(1, 3), 16);
140             g = Integer.parseInt(value.substring(3, 5), 16);
141             b = Integer.parseInt(value.substring(5, 7), 16);
142         } catch (NumberFormatException JavaDoc e) {
143             throw new Exception JavaDoc("Invalid color specification: " + value);
144         }
145
146         return new Color(r, g, b);
147     }
148
149     public void run(PublicationContext context) throws Exception JavaDoc {
150         context.getPublicationLog().info("Running SVG render task.");
151         BookInstance bookInstance = context.getBookInstance();
152         String JavaDoc publicationOutputPath = BookInstanceLayout.getPublicationOutputPath(context.getPublicationOutputName());
153         String JavaDoc startXmlLocation = publicationOutputPath + input;
154         InputStream JavaDoc is = null;
155         OutputStream JavaDoc os = null;
156         try {
157             is = bookInstance.getResource(startXmlLocation);
158             os = bookInstance.getResourceOutputStream(publicationOutputPath + output);
159             SAXParser JavaDoc parser = LocalSAXParserFactory.getSAXParserFactory().newSAXParser();
160             XmlSerializer serializer = new XmlSerializer(os);
161             SvgRenderHandler svgRenderHandler = new SvgRenderHandler(serializer, context);
162             parser.getXMLReader().setContentHandler(svgRenderHandler);
163             parser.getXMLReader().parse(new InputSource JavaDoc(is));
164         } finally {
165             if (is != null)
166                 try { is.close(); } catch (Exception JavaDoc e) { /* ignore */ }
167             if (os != null)
168                 try { os.close(); } catch (Exception JavaDoc e) { /* ignore */ }
169         }
170     }
171
172     class SvgRenderHandler extends AbstractContentHandler {
173         private PublicationContext context;
174
175         public SvgRenderHandler(ContentHandler consumer, PublicationContext context) {
176             super(consumer);
177             this.context = context;
178         }
179
180         public void startElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName, Attributes JavaDoc atts) throws SAXException JavaDoc {
181             if (namespaceURI.equals(NS) && localName.equals("renderSVG")) {
182                 InputStream JavaDoc svgInputStream = null;
183                 OutputStream JavaDoc svgOutputStream = null;
184                 try {
185                     String JavaDoc svgPath = atts.getValue("bookStorePath");
186                     svgInputStream = context.getBookInstance().getResource(svgPath);
187
188                     SAXSVGDocumentFactory svgDocumentFactory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
189                     SVGDocument svgDocument = (SVGDocument)svgDocumentFactory.createDocument(context.getBookInstance().getResourceURI(svgPath).toString(), svgInputStream);
190
191                     Dimension2D JavaDoc svgDimension = getSvgDimension(svgDocument);
192
193                     float svgWidth = (float)svgDimension.getWidth();
194                     float svgHeight = (float)svgDimension.getHeight();
195                     float width = (float)Math.floor(svgWidth * (dpi / defaultDpi));
196                     float height = (float)Math.floor(svgHeight * (dpi / defaultDpi));
197
198                     Transcoder transcoder;
199                     if (format.equals("jpg"))
200                         transcoder = new JPEGTranscoder();
201                     else if (format.equals("png"))
202                         transcoder = new PNGTranscoder();
203                     else
204                         throw new Exception JavaDoc("svgRender task: unrecognized format: " + format);
205
206                     transcoder.setErrorHandler(new MyErrorHandler(context.getPublicationLog()));
207                     transcoder.addTranscodingHint(JPEGTranscoder.KEY_HEIGHT, new Float JavaDoc(height));
208                     if (backgroundColor != null)
209                         transcoder.addTranscodingHint(JPEGTranscoder.KEY_BACKGROUND_COLOR, backgroundColor);
210                     transcoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float JavaDoc(quality));
211                     if (enableScripts) {
212                         transcoder.addTranscodingHint(JPEGTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE);
213                         transcoder.addTranscodingHint(JPEGTranscoder.KEY_CONSTRAIN_SCRIPT_ORIGIN, Boolean.FALSE);
214                     }
215
216                     TranscoderInput transcoderInput = new TranscoderInput(svgDocument);
217
218                     String JavaDoc publicationOutputPath = BookInstanceLayout.getPublicationOutputPath(context.getPublicationOutputName());
219                     String JavaDoc svgOutputPath = publicationOutputPath + outputPrefix + PublicationProcessTaskUtil.getFileName(svgPath);
220                     svgOutputStream = context.getBookInstance().getResourceOutputStream(svgOutputPath);
221                     TranscoderOutput transcoderOutput = new TranscoderOutput(svgOutputStream);
222
223                     // the actual SVG rendering
224
transcoder.transcode(transcoderInput, transcoderOutput);
225
226                     // write a meta file
227
ResourcePropertiesDocument propertiesDocument = ResourcePropertiesDocument.Factory.newInstance();
228                     propertiesDocument.addNewResourceProperties().setMimeType("image/" + format);
229                     context.getBookInstance().storeResourceProperties(svgOutputPath, propertiesDocument);
230
231                     float printWidth = width / dpi;
232                     float printHeight = height / dpi;
233                     if (printWidth > maxPrintWidth) {
234                         printHeight = printHeight * (maxPrintWidth / printWidth);
235                         printWidth = maxPrintWidth;
236                     }
237                     if (printHeight > maxPrintHeight) {
238                         printWidth = printWidth * (maxPrintHeight / printHeight);
239                         printHeight = maxPrintHeight;
240                     }
241
242                     AttributesImpl attrs = new AttributesImpl();
243                     attrs.addCDATAAttribute("src", "bookinstance:" + svgOutputPath);
244                     attrs.addCDATAAttribute("width", String.valueOf((int)width));
245                     attrs.addCDATAAttribute("height", String.valueOf((int)height));
246                     attrs.addCDATAAttribute("print-width", String.valueOf(printWidth) + "in");
247                     attrs.addCDATAAttribute("print-height", String.valueOf(printHeight) + "in");
248                     startElement("", "img", "img", attrs);
249                     endElement("", "img", "img");
250                 } catch (Exception JavaDoc e) {
251                     throw new SAXException JavaDoc("Error rendering SVG.", e);
252                 } finally {
253                     if (svgInputStream != null)
254                         try { svgInputStream.close(); } catch (Exception JavaDoc e) { /* ignore */ }
255                     if (svgOutputStream != null)
256                         try { svgOutputStream.close(); } catch (Exception JavaDoc e) { /* ignore */ }
257                 }
258             } else {
259                 super.startElement(namespaceURI, localName, qName, atts);
260             }
261         }
262
263         private Dimension2D JavaDoc getSvgDimension(Document document) {
264             UserAgentAdapter userAgent = new UserAgentAdapter();
265             BridgeContext ctx = new BridgeContext(userAgent);
266             GVTBuilder builder = new GVTBuilder();
267             ctx.setDynamicState(enableScripts ? BridgeContext.DYNAMIC : BridgeContext.STATIC);
268             builder.build(ctx, document);
269             return ctx.getDocumentSize();
270         }
271
272         public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName) throws SAXException JavaDoc {
273             if (namespaceURI.equals(NS) && localName.equals("renderSVG")) {
274                 // don't propagatge
275
} else {
276                 super.endElement(namespaceURI, localName, qName);
277             }
278         }
279     }
280
281     static class MyErrorHandler implements ErrorHandler {
282         private PublicationLog log;
283
284         public MyErrorHandler(PublicationLog log) {
285             this.log = log;
286         }
287
288         public void error(TranscoderException transcoderException) throws TranscoderException {
289             log.error("Error reported by Batik.", transcoderException);
290         }
291
292         public void fatalError(TranscoderException transcoderException) throws TranscoderException {
293             log.error("Fatal error reported by Batik.", transcoderException);
294         }
295
296         public void warning(TranscoderException transcoderException) throws TranscoderException {
297             log.error("Warning reported by Batik.", transcoderException);
298         }
299     }
300
301 }
302
Popular Tags