You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PDFTranscoder.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 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. import java.awt.Dimension;
  53. import java.awt.geom.AffineTransform;
  54. import java.awt.geom.Dimension2D;
  55. import java.awt.geom.Rectangle2D;
  56. import java.awt.Color;
  57. import java.net.MalformedURLException;
  58. import java.net.URL;
  59. import java.io.IOException;
  60. import org.apache.avalon.framework.configuration.Configurable;
  61. import org.apache.avalon.framework.configuration.Configuration;
  62. import org.apache.avalon.framework.configuration.ConfigurationException;
  63. import org.apache.avalon.framework.container.ContainerUtil;
  64. import org.apache.avalon.framework.logger.AbstractLogEnabled;
  65. import org.apache.batik.bridge.BridgeContext;
  66. import org.apache.batik.bridge.BridgeException;
  67. import org.apache.batik.bridge.GVTBuilder;
  68. import org.apache.batik.bridge.UserAgent;
  69. import org.apache.batik.bridge.UserAgentAdapter;
  70. import org.apache.batik.bridge.ViewBox;
  71. import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
  72. import org.apache.batik.dom.svg.SVGDOMImplementation;
  73. import org.apache.batik.dom.svg.SVGOMDocument;
  74. import org.apache.batik.dom.util.DocumentFactory;
  75. import org.apache.batik.gvt.GraphicsNode;
  76. import org.apache.batik.transcoder.ErrorHandler;
  77. import org.apache.batik.transcoder.TranscoderException;
  78. import org.apache.batik.transcoder.TranscoderOutput;
  79. import org.apache.batik.transcoder.XMLAbstractTranscoder;
  80. import org.apache.batik.transcoder.image.resources.Messages;
  81. import org.apache.batik.transcoder.image.ImageTranscoder;
  82. import org.apache.batik.util.SVGConstants;
  83. import org.apache.batik.util.XMLResourceDescriptor;
  84. import org.apache.batik.gvt.TextPainter;
  85. import org.apache.batik.gvt.renderer.StrokingTextPainter;
  86. import org.w3c.dom.DOMImplementation;
  87. import org.w3c.dom.Document;
  88. import org.w3c.dom.svg.SVGDocument;
  89. import org.w3c.dom.svg.SVGSVGElement;
  90. /**
  91. * This class enables to transcode an input to a pdf document.
  92. *
  93. * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and
  94. * <tt>KEY_HEIGHT</tt>) can be used to respectively specify the image
  95. * width and the image height. If only one of these keys is specified,
  96. * the transcoder preserves the aspect ratio of the original image.
  97. *
  98. * <p>The <tt>KEY_BACKGROUND_COLOR</tt> defines the background color
  99. * to use for opaque image formats, or the background color that may
  100. * be used for image formats that support alpha channel.
  101. *
  102. * <p>The <tt>KEY_AOI</tt> represents the area of interest to paint
  103. * in device space.
  104. *
  105. * <p>Three additional transcoding hints that act on the SVG
  106. * processor can be specified:
  107. *
  108. * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be
  109. * used by a &lt;switch> SVG element for example),
  110. * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user
  111. * stylesheet, and <tt>KEY_PIXEL_TO_MM</tt> to specify the pixel to
  112. * millimeter conversion factor.
  113. *
  114. * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  115. * @version $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $
  116. */
  117. public class PDFTranscoder extends AbstractFOPTranscoder
  118. implements Configurable {
  119. private Configuration cfg;
  120. /**
  121. * Constructs a new <tt>ImageTranscoder</tt>.
  122. */
  123. public PDFTranscoder() {
  124. super();
  125. this.handler = new FOPErrorHandler();
  126. }
  127. /**
  128. * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
  129. */
  130. public void configure(Configuration cfg) throws ConfigurationException {
  131. this.cfg = cfg;
  132. }
  133. /**
  134. * Transcodes the specified Document as an image in the specified output.
  135. *
  136. * @param document the document to transcode
  137. * @param uri the uri of the document or null if any
  138. * @param output the ouput where to transcode
  139. * @exception TranscoderException if an error occured while transcoding
  140. */
  141. protected void transcode(Document document, String uri,
  142. TranscoderOutput output) throws TranscoderException {
  143. if (!(document instanceof SVGOMDocument)) {
  144. throw new TranscoderException(Messages.formatMessage("notsvg",
  145. null));
  146. }
  147. SVGDocument svgDoc = (SVGDocument)document;
  148. SVGSVGElement root = svgDoc.getRootElement();
  149. // initialize the SVG document with the appropriate context
  150. String parserClassname = (String)hints.get(KEY_XML_PARSER_CLASSNAME);
  151. /*boolean stroke = true;
  152. if (hints.containsKey(KEY_STROKE_TEXT)) {
  153. stroke = ((Boolean)hints.get(KEY_STROKE_TEXT)).booleanValue();
  154. }*/
  155. PDFDocumentGraphics2D graphics = new PDFDocumentGraphics2D();
  156. ContainerUtil.enableLogging(graphics, getLogger());
  157. try {
  158. if (this.cfg != null) {
  159. ContainerUtil.configure(graphics, this.cfg);
  160. }
  161. ContainerUtil.initialize(graphics);
  162. } catch (Exception e) {
  163. throw new TranscoderException(
  164. "Error while setting up PDFDocumentGraphics2D", e);
  165. }
  166. // build the GVT tree
  167. GVTBuilder builder = new GVTBuilder();
  168. BridgeContext ctx = new BridgeContext(userAgent);
  169. TextPainter textPainter = null;
  170. textPainter = new StrokingTextPainter();
  171. ctx.setTextPainter(textPainter);
  172. PDFTextElementBridge pdfTextElementBridge;
  173. pdfTextElementBridge = new PDFTextElementBridge(graphics.getFontInfo());
  174. ctx.putBridge(pdfTextElementBridge);
  175. PDFAElementBridge pdfAElementBridge = new PDFAElementBridge();
  176. AffineTransform currentTransform = new AffineTransform(1, 0, 0, 1, 0, 0);
  177. pdfAElementBridge.setCurrentTransform(currentTransform);
  178. ctx.putBridge(pdfAElementBridge);
  179. ctx.putBridge(new PDFImageElementBridge());
  180. GraphicsNode gvtRoot;
  181. try {
  182. gvtRoot = builder.build(ctx, svgDoc);
  183. } catch (BridgeException ex) {
  184. throw new TranscoderException(ex);
  185. }
  186. // get the 'width' and 'height' attributes of the SVG document
  187. float docWidth = (float)ctx.getDocumentSize().getWidth();
  188. float docHeight = (float)ctx.getDocumentSize().getHeight();
  189. ctx = null;
  190. builder = null;
  191. // compute the image's width and height according the hints
  192. float imgWidth = -1;
  193. if (hints.containsKey(ImageTranscoder.KEY_WIDTH)) {
  194. imgWidth =
  195. ((Float)hints.get(ImageTranscoder.KEY_WIDTH)).floatValue();
  196. }
  197. float imgHeight = -1;
  198. if (hints.containsKey(ImageTranscoder.KEY_HEIGHT)) {
  199. imgHeight =
  200. ((Float)hints.get(ImageTranscoder.KEY_HEIGHT)).floatValue();
  201. }
  202. float width, height;
  203. if (imgWidth > 0 && imgHeight > 0) {
  204. width = imgWidth;
  205. height = imgHeight;
  206. } else if (imgHeight > 0) {
  207. width = (docWidth * imgHeight) / docHeight;
  208. height = imgHeight;
  209. } else if (imgWidth > 0) {
  210. width = imgWidth;
  211. height = (docHeight * imgWidth) / docWidth;
  212. } else {
  213. width = docWidth;
  214. height = docHeight;
  215. }
  216. // compute the preserveAspectRatio matrix
  217. AffineTransform px;
  218. String ref = null;
  219. try {
  220. ref = new URL(uri).getRef();
  221. } catch (MalformedURLException ex) {
  222. // nothing to do, catched previously
  223. }
  224. try {
  225. px = ViewBox.getViewTransform(ref, root, width, height);
  226. } catch (BridgeException ex) {
  227. throw new TranscoderException(ex);
  228. }
  229. if (px.isIdentity() && (width != docWidth || height != docHeight)) {
  230. // The document has no viewBox, we need to resize it by hand.
  231. // we want to keep the document size ratio
  232. float d = Math.max(docWidth, docHeight);
  233. float dd = Math.max(width, height);
  234. float scale = dd / d;
  235. px = AffineTransform.getScaleInstance(scale, scale);
  236. }
  237. // take the AOI into account if any
  238. if (hints.containsKey(ImageTranscoder.KEY_AOI)) {
  239. Rectangle2D aoi = (Rectangle2D)hints.get(ImageTranscoder.KEY_AOI);
  240. // transform the AOI into the image's coordinate system
  241. aoi = px.createTransformedShape(aoi).getBounds2D();
  242. AffineTransform mx = new AffineTransform();
  243. double sx = width / aoi.getWidth();
  244. double sy = height / aoi.getHeight();
  245. mx.scale(sx, sy);
  246. double tx = -aoi.getX();
  247. double ty = -aoi.getY();
  248. mx.translate(tx, ty);
  249. // take the AOI transformation matrix into account
  250. // we apply first the preserveAspectRatio matrix
  251. px.preConcatenate(mx);
  252. }
  253. // prepare the image to be painted
  254. int w = (int)width;
  255. int h = (int)height;
  256. try {
  257. graphics.setupDocument(output.getOutputStream(), w, h);
  258. } catch (IOException ex) {
  259. throw new TranscoderException(ex);
  260. }
  261. graphics.setSVGDimension(docWidth, docHeight);
  262. currentTransform.setTransform(1, 0, 0, -1, 0, height);
  263. /*if (!stroke) {
  264. textPainter = new PDFTextPainter(graphics.getFontInfo());
  265. ctx.setTextPainter(textPainter);
  266. }*/
  267. if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) {
  268. graphics.setBackgroundColor((Color)hints.get(ImageTranscoder.KEY_BACKGROUND_COLOR));
  269. }
  270. graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
  271. graphics.setTransform(px);
  272. gvtRoot.paint(graphics);
  273. try {
  274. graphics.finish();
  275. } catch (IOException ex) {
  276. throw new TranscoderException(ex);
  277. }
  278. }
  279. }