KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > svg > PDFTranscoder


1 /*
2  * $Id: PDFTranscoder.java,v 1.11.2.5 2003/02/25 15:08:11 jeremias Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.svg;
52
53 import java.awt.Dimension JavaDoc;
54
55 import java.awt.geom.AffineTransform JavaDoc;
56 import java.awt.geom.Dimension2D JavaDoc;
57 import java.awt.geom.Rectangle2D JavaDoc;
58
59 import java.awt.*;
60
61 import java.net.MalformedURLException JavaDoc;
62 import java.net.URL JavaDoc;
63
64 import org.apache.fop.apps.FOPException;
65
66 import org.apache.batik.bridge.BridgeContext;
67 import org.apache.batik.bridge.BridgeException;
68 import org.apache.batik.bridge.GVTBuilder;
69 import org.apache.batik.bridge.UserAgent;
70 import org.apache.batik.bridge.ViewBox;
71
72 import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
73 import org.apache.batik.dom.svg.SVGDOMImplementation;
74 import org.apache.batik.dom.svg.SVGOMDocument;
75 import org.apache.batik.dom.util.DocumentFactory;
76
77 import org.apache.batik.gvt.GraphicsNode;
78
79 import org.apache.batik.transcoder.TranscoderException;
80 import org.apache.batik.transcoder.TranscoderOutput;
81 import org.apache.batik.transcoder.TranscodingHints;
82 import org.apache.batik.transcoder.XMLAbstractTranscoder;
83 import org.apache.batik.transcoder.image.resources.Messages;
84
85 import org.apache.batik.transcoder.keys.StringKey;
86 import org.apache.batik.transcoder.image.*;
87
88 import org.apache.batik.util.SVGConstants;
89 import org.apache.batik.util.XMLResourceDescriptor;
90
91 import org.apache.batik.bridge.*;
92 import org.apache.batik.gvt.*;
93 import org.apache.batik.gvt.renderer.*;
94
95 import org.apache.fop.svg.*;
96
97 import org.w3c.dom.DOMImplementation JavaDoc;
98 import org.w3c.dom.Document JavaDoc;
99 import org.w3c.dom.svg.SVGDocument;
100 import org.w3c.dom.svg.SVGSVGElement;
101
102 /**
103  * This class enables to transcode an input to a pdf document.
104  *
105  * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and
106  * <tt>KEY_HEIGHT</tt>) can be used to respectively specify the image
107  * width and the image height. If only one of these keys is specified,
108  * the transcoder preserves the aspect ratio of the original image.
109  *
110  * <p>The <tt>KEY_BACKGROUND_COLOR</tt> defines the background color
111  * to use for opaque image formats, or the background color that may
112  * be used for image formats that support alpha channel.
113  *
114  * <p>The <tt>KEY_AOI</tt> represents the area of interest to paint
115  * in device space.
116  *
117  * <p>Three additional transcoding hints that act on the SVG
118  * processor can be specified:
119  *
120  * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be
121  * used by a &lt;switch> SVG element for example),
122  * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user
123  * stylesheet, and <tt>KEY_PIXEL_UNIT_TO_MILLIMETER</tt> to specify the pixel to
124  * millimeter conversion factor.
125  *
126  * @author <a HREF="mailto:keiron@aftexsw.com">Keiron Liddle</a>
127  * @version $Id: PDFTranscoder.java,v 1.11.2.5 2003/02/25 15:08:11 jeremias Exp $
128  */

129 public class PDFTranscoder extends XMLAbstractTranscoder {
130
131     public static final TranscodingHints.Key KEY_STROKE_TEXT =
132         new StringKey();
133
134     /**
135      * The user agent dedicated to an <tt>ImageTranscoder</tt>.
136      */

137     protected UserAgent userAgent = new ImageTranscoderUserAgent();
138
139     /**
140      * Constructs a new <tt>ImageTranscoder</tt>.
141      */

142     public PDFTranscoder() {
143         hints.put(KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,
144                   SVGConstants.SVG_NAMESPACE_URI);
145         hints.put(KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG);
146         hints.put(KEY_DOM_IMPLEMENTATION,
147                   SVGDOMImplementation.getDOMImplementation());
148     }
149
150     /**
151      * Transcodes the specified Document as an image in the specified output.
152      *
153      * @param document the document to transcode
154      * @param uri the uri of the document or null if any
155      * @param output the ouput where to transcode
156      * @exception TranscoderException if an error occured while transcoding
157      */

158     protected void transcode(Document document, String JavaDoc uri,
159                              TranscoderOutput output)
160                              throws TranscoderException {
161
162         if (!(document instanceof SVGOMDocument)) {
163             throw new TranscoderException(Messages.formatMessage("notsvg",
164                     null));
165         }
166         SVGDocument svgDoc = (SVGDocument)document;
167         SVGSVGElement root = svgDoc.getRootElement();
168         // initialize the SVG document with the appropriate context
169
String JavaDoc parserClassname = (String JavaDoc)hints.get(KEY_XML_PARSER_CLASSNAME);
170
171         boolean stroke = true;
172         if (hints.containsKey(KEY_STROKE_TEXT)) {
173             stroke = ((Boolean JavaDoc)hints.get(KEY_STROKE_TEXT)).booleanValue();
174         }
175
176         // build the GVT tree
177
GVTBuilder builder = new GVTBuilder();
178         BridgeContext ctx = new BridgeContext(userAgent);
179         TextPainter textPainter = null;
180         textPainter = new StrokingTextPainter();
181         ctx.setTextPainter(textPainter);
182
183         PDFAElementBridge pdfAElementBridge = new PDFAElementBridge();
184         AffineTransform JavaDoc currentTransform = new AffineTransform JavaDoc(1, 0, 0, 1, 0, 0);
185         pdfAElementBridge.setCurrentTransform(currentTransform);
186         ctx.putBridge(pdfAElementBridge);
187         ctx.putBridge(new PDFImageElementBridge());
188         GraphicsNode gvtRoot;
189         try {
190             gvtRoot = builder.build(ctx, svgDoc);
191         } catch (BridgeException ex) {
192             throw new TranscoderException(ex);
193         }
194         // get the 'width' and 'height' attributes of the SVG document
195
float docWidth = (float)ctx.getDocumentSize().getWidth();
196         float docHeight = (float)ctx.getDocumentSize().getHeight();
197         ctx = null;
198         builder = null;
199
200         // compute the image's width and height according the hints
201
float imgWidth = -1;
202         if (hints.containsKey(ImageTranscoder.KEY_WIDTH)) {
203             imgWidth =
204                 ((Float JavaDoc)hints.get(ImageTranscoder.KEY_WIDTH)).floatValue();
205         }
206         float imgHeight = -1;
207         if (hints.containsKey(ImageTranscoder.KEY_HEIGHT)) {
208             imgHeight =
209                 ((Float JavaDoc)hints.get(ImageTranscoder.KEY_HEIGHT)).floatValue();
210         }
211         float width, height;
212         if (imgWidth > 0 && imgHeight > 0) {
213             width = imgWidth;
214             height = imgHeight;
215         } else if (imgHeight > 0) {
216             width = (docWidth * imgHeight) / docHeight;
217             height = imgHeight;
218         } else if (imgWidth > 0) {
219             width = imgWidth;
220             height = (docHeight * imgWidth) / docWidth;
221         } else {
222             width = docWidth;
223             height = docHeight;
224         }
225         // compute the preserveAspectRatio matrix
226
AffineTransform JavaDoc Px;
227         String JavaDoc ref = null;
228         try {
229             ref = new URL JavaDoc(uri).getRef();
230         } catch (MalformedURLException JavaDoc ex) {
231             // nothing to do, catched previously
232
}
233
234         try {
235             Px = ViewBox.getViewTransform(ref, root, width, height);
236         } catch (BridgeException ex) {
237             throw new TranscoderException(ex);
238         }
239
240         if (Px.isIdentity() && (width != docWidth || height != docHeight)) {
241             // The document has no viewBox, we need to resize it by hand.
242
// we want to keep the document size ratio
243
float d = Math.max(docWidth, docHeight);
244             float dd = Math.max(width, height);
245             float scale = dd / d;
246             Px = AffineTransform.getScaleInstance(scale, scale);
247         }
248         // take the AOI into account if any
249
if (hints.containsKey(ImageTranscoder.KEY_AOI)) {
250             Rectangle2D JavaDoc aoi = (Rectangle2D JavaDoc)hints.get(ImageTranscoder.KEY_AOI);
251             // transform the AOI into the image's coordinate system
252
aoi = Px.createTransformedShape(aoi).getBounds2D();
253             AffineTransform JavaDoc Mx = new AffineTransform JavaDoc();
254             double sx = width / aoi.getWidth();
255             double sy = height / aoi.getHeight();
256             Mx.scale(sx, sy);
257             double tx = -aoi.getX();
258             double ty = -aoi.getY();
259             Mx.translate(tx, ty);
260             // take the AOI transformation matrix into account
261
// we apply first the preserveAspectRatio matrix
262
Px.preConcatenate(Mx);
263         }
264         // prepare the image to be painted
265
int w = (int)width;
266         int h = (int)height;
267
268         PDFDocumentGraphics2D graphics;
269         try {
270             graphics = new PDFDocumentGraphics2D(stroke,
271                 output.getOutputStream(), w, h);
272         } catch (FOPException ex) {
273             throw new TranscoderException(ex);
274         }
275         graphics.setSVGDimension(docWidth, docHeight);
276         currentTransform.setTransform(1, 0, 0, -1, 0, height);
277         if (!stroke) {
278             textPainter = new PDFTextPainter(graphics.getFontState());
279             ctx.setTextPainter(textPainter);
280         }
281
282         if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) {
283             graphics.setBackgroundColor((Color)hints.get(ImageTranscoder.KEY_BACKGROUND_COLOR));
284         }
285         graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
286
287         gvtRoot.paint(graphics);
288
289         try {
290             graphics.finish();
291         } catch (Exception JavaDoc ex) {
292             ex.printStackTrace();
293             throw new TranscoderException(ex);
294         }
295     }
296
297     /**
298      * Creates a <tt>DocumentFactory</tt> that is used to create an SVG DOM
299      * tree. The specified DOM Implementation is ignored and the Batik
300      * SVG DOM Implementation is automatically used.
301      *
302      * @param domImpl the DOM Implementation (not used)
303      * @param parserClassname the XML parser classname
304      */

305     protected DocumentFactory createDocumentFactory(DOMImplementation domImpl,
306             String JavaDoc parserClassname) {
307         return new SAXSVGDocumentFactory(parserClassname);
308     }
309
310     // --------------------------------------------------------------------
311
// UserAgent implementation
312
// --------------------------------------------------------------------
313

314     /**
315      * A user agent implementation for <tt>ImageTranscoder</tt>.
316      */

317     protected class ImageTranscoderUserAgent extends UserAgentAdapter {
318
319     public boolean isXMLParserValidating() {
320         return true;
321     }
322
323         /**
324          * Returns the default size of this user agent (400x400).
325          */

326         public Dimension2D JavaDoc getViewportSize() {
327             return new Dimension JavaDoc(400, 400);
328         }
329
330         /**
331          * Displays the specified error message using the <tt>ErrorHandler</tt>.
332          */

333         public void displayError(String JavaDoc message) {
334             try {
335                 getErrorHandler().error(new TranscoderException(message));
336             } catch (TranscoderException ex) {
337                 throw new RuntimeException JavaDoc();
338             }
339         }
340
341         /**
342          * Displays the specified error using the <tt>ErrorHandler</tt>.
343          */

344         public void displayError(Exception JavaDoc e) {
345             try {
346                 getErrorHandler().error(new TranscoderException(e));
347             } catch (TranscoderException ex) {
348                 throw new RuntimeException JavaDoc();
349             }
350         }
351
352         /**
353          * Displays the specified message using the <tt>ErrorHandler</tt>.
354          */

355         public void displayMessage(String JavaDoc message) {
356             try {
357                 getErrorHandler().warning(new TranscoderException(message));
358             } catch (TranscoderException ex) {
359                 throw new RuntimeException JavaDoc();
360             }
361         }
362
363         /**
364          * Returns the pixel to millimeter conversion factor specified in the
365          * <tt>TranscodingHints</tt> or 0.3528 if any.
366          */

367         public float getPixelToMM() {
368             if (getTranscodingHints().containsKey(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER)) {
369                 return ((Float JavaDoc)getTranscodingHints().get(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER)).floatValue();
370             } else {
371                 // return 0.3528f; // 72 dpi
372
return 0.26458333333333333333333333333333f; // 96dpi
373
}
374         }
375
376         /**
377          * Returns the user language specified in the
378          * <tt>TranscodingHints</tt> or "en" (english) if any.
379          */

380         public String JavaDoc getLanguages() {
381             if (getTranscodingHints().containsKey(ImageTranscoder.KEY_LANGUAGE)) {
382                 return (String JavaDoc)getTranscodingHints().get(ImageTranscoder.KEY_LANGUAGE);
383             } else {
384                 return "en";
385             }
386         }
387
388         public String JavaDoc getMedia() {
389             return "print";
390         }
391
392         /**
393          * Returns the user stylesheet specified in the
394          * <tt>TranscodingHints</tt> or null if any.
395          */

396         public String JavaDoc getUserStyleSheetURI() {
397             return (String JavaDoc)getTranscodingHints().get(ImageTranscoder.KEY_USER_STYLESHEET_URI);
398         }
399
400         /**
401          * Returns the XML parser to use from the TranscodingHints.
402          */

403         public String JavaDoc getXMLParserClassName() {
404             if (getTranscodingHints().containsKey(KEY_XML_PARSER_CLASSNAME)) {
405                 return (String JavaDoc)getTranscodingHints().get(KEY_XML_PARSER_CLASSNAME);
406             } else {
407                 return XMLResourceDescriptor.getXMLParserClassName();
408             }
409         }
410
411     }
412
413 }
414
Popular Tags