選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

PDFXMLHandler.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * $Id$
  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.render.pdf;
  52. import org.apache.fop.render.XMLHandler;
  53. import org.apache.fop.render.RendererContext;
  54. import org.apache.fop.pdf.PDFDocument;
  55. import org.apache.fop.pdf.PDFPage;
  56. import org.apache.fop.pdf.PDFState;
  57. import org.apache.fop.pdf.PDFStream;
  58. import org.apache.fop.pdf.PDFNumber;
  59. import org.apache.fop.pdf.PDFResourceContext;
  60. import org.apache.fop.svg.PDFTextElementBridge;
  61. import org.apache.fop.svg.PDFAElementBridge;
  62. import org.apache.fop.svg.PDFGraphics2D;
  63. import org.apache.fop.svg.SVGUserAgent;
  64. import org.apache.fop.layout.FontInfo;
  65. import org.w3c.dom.Document;
  66. import java.io.OutputStream;
  67. import org.apache.batik.bridge.GVTBuilder;
  68. import org.apache.batik.bridge.BridgeContext;
  69. import org.apache.batik.bridge.ViewBox;
  70. import org.apache.batik.gvt.GraphicsNode;
  71. import org.w3c.dom.svg.SVGDocument;
  72. import org.w3c.dom.svg.SVGSVGElement;
  73. import java.awt.geom.AffineTransform;
  74. /**
  75. * PDF XML handler.
  76. * This handler handles XML for foreign objects when rendering to PDF.
  77. * It renders SVG to the PDF document using the PDFGraphics2D.
  78. * The properties from the PDF renderer are subject to change.
  79. */
  80. public class PDFXMLHandler implements XMLHandler {
  81. /**
  82. * The PDF document that is being drawn into.
  83. */
  84. public static final String PDF_DOCUMENT = "pdfDoc";
  85. /**
  86. * The output stream that the document is being sent to.
  87. */
  88. public static final String OUTPUT_STREAM = "outputStream";
  89. /**
  90. * The current pdf state.
  91. */
  92. public static final String PDF_STATE = "pdfState";
  93. /**
  94. * The current PDF page for page renference and as a resource context.
  95. */
  96. public static final String PDF_PAGE = "pdfPage";
  97. /**
  98. * The current PDF page for page renference and as a resource context.
  99. */
  100. public static final String PDF_CONTEXT = "pdfContext";
  101. /**
  102. * The current PDF stream to draw directly to.
  103. */
  104. public static final String PDF_STREAM = "pdfStream";
  105. /**
  106. * The width of the current pdf page.
  107. */
  108. public static final String PDF_WIDTH = "width";
  109. /**
  110. * The height of the current pdf page.
  111. */
  112. public static final String PDF_HEIGHT = "height";
  113. /**
  114. * The current font information for the pdf renderer.
  115. */
  116. public static final String PDF_FONT_INFO = "fontInfo";
  117. /**
  118. * The current pdf font name.
  119. */
  120. public static final String PDF_FONT_NAME = "fontName";
  121. /**
  122. * The current pdf font size.
  123. */
  124. public static final String PDF_FONT_SIZE = "fontSize";
  125. /**
  126. * The x position that this is being drawn at.
  127. */
  128. public static final String PDF_XPOS = "xpos";
  129. /**
  130. * The y position that this is being drawn at.
  131. */
  132. public static final String PDF_YPOS = "ypos";
  133. /**
  134. * Create a new PDF XML handler for use by the PDF renderer.
  135. */
  136. public PDFXMLHandler() {
  137. }
  138. /**
  139. * Handle the XML.
  140. * This checks the type of XML and handles appropraitely.
  141. *
  142. * @param context the renderer context
  143. * @param doc the XML document to render
  144. * @param ns the namespace of the XML document
  145. * @throws Exception any sort of exception could be thrown and shuld be handled
  146. */
  147. public void handleXML(RendererContext context, Document doc,
  148. String ns) throws Exception {
  149. PDFInfo pdfi = getPDFInfo(context);
  150. String svg = "http://www.w3.org/2000/svg";
  151. if (svg.equals(ns)) {
  152. SVGHandler svghandler = new SVGHandler();
  153. svghandler.renderSVGDocument(context, doc, pdfi);
  154. } else {
  155. }
  156. }
  157. /**
  158. * Get the pdf information from the render context.
  159. *
  160. * @param context the renderer context
  161. * @return the pdf information retrieved from the context
  162. */
  163. public static PDFInfo getPDFInfo(RendererContext context) {
  164. PDFInfo pdfi = new PDFInfo();
  165. pdfi.pdfDoc = (PDFDocument)context.getProperty(PDF_DOCUMENT);
  166. pdfi.outputStream = (OutputStream)context.getProperty(OUTPUT_STREAM);
  167. pdfi.pdfState = (PDFState)context.getProperty(PDF_STATE);
  168. pdfi.pdfPage = (PDFPage)context.getProperty(PDF_PAGE);
  169. pdfi.pdfContext = (PDFResourceContext)context.getProperty(PDF_CONTEXT);
  170. pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM);
  171. pdfi.width = ((Integer)context.getProperty(PDF_WIDTH)).intValue();
  172. pdfi.height = ((Integer)context.getProperty(PDF_HEIGHT)).intValue();
  173. pdfi.fi = (FontInfo)context.getProperty(PDF_FONT_INFO);
  174. pdfi.currentFontName = (String)context.getProperty(PDF_FONT_NAME);
  175. pdfi.currentFontSize = ((Integer)context.getProperty(PDF_FONT_SIZE)).intValue();
  176. pdfi.currentXPosition = ((Integer)context.getProperty(PDF_XPOS)).intValue();
  177. pdfi.currentYPosition = ((Integer)context.getProperty(PDF_YPOS)).intValue();
  178. return pdfi;
  179. }
  180. /**
  181. * PDF information structure for drawing the XML document.
  182. */
  183. public static class PDFInfo {
  184. /** see PDF_DOCUMENT */
  185. public PDFDocument pdfDoc;
  186. /** see OUTPUT_STREAM */
  187. public OutputStream outputStream;
  188. /** see PDF_STATE */
  189. public PDFState pdfState;
  190. /** see PDF_PAGE */
  191. public PDFPage pdfPage;
  192. /** see PDF_CONTEXT */
  193. public PDFResourceContext pdfContext;
  194. /** see PDF_STREAM */
  195. public PDFStream currentStream;
  196. /** see PDF_WIDTH */
  197. public int width;
  198. /** see PDF_HEIGHT */
  199. public int height;
  200. /** see PDF_FONT_INFO */
  201. public FontInfo fi;
  202. /** see PDF_FONT_NAME */
  203. public String currentFontName;
  204. /** see PDF_FONT_SIZE */
  205. public int currentFontSize;
  206. /** see PDF_XPOS */
  207. public int currentXPosition;
  208. /** see PDF_YPOS */
  209. public int currentYPosition;
  210. }
  211. /**
  212. * This method is placed in an inner class so that we don't get class
  213. * loading errors if batik is not present.
  214. */
  215. protected class SVGHandler {
  216. /**
  217. * Render the svg document.
  218. * @param context the renderer context
  219. * @param doc the svg document
  220. * @param pdfInfo the pdf information of the current context
  221. */
  222. protected void renderSVGDocument(RendererContext context, Document doc, PDFInfo pdfInfo) {
  223. int xOffset = pdfInfo.currentXPosition;
  224. int yOffset = pdfInfo.currentYPosition;
  225. SVGUserAgent ua
  226. = new SVGUserAgent(context.getUserAgent(), new AffineTransform());
  227. GVTBuilder builder = new GVTBuilder();
  228. BridgeContext ctx = new BridgeContext(ua);
  229. PDFTextElementBridge tBridge = new PDFTextElementBridge(pdfInfo.fi);
  230. ctx.putBridge(tBridge);
  231. PDFAElementBridge aBridge = new PDFAElementBridge();
  232. // to get the correct transform we need to use the PDFState
  233. AffineTransform transform = pdfInfo.pdfState.getTransform();
  234. transform.translate(xOffset / 1000f, yOffset / 1000f);
  235. aBridge.setCurrentTransform(transform);
  236. ctx.putBridge(aBridge);
  237. GraphicsNode root;
  238. try {
  239. root = builder.build(ctx, doc);
  240. } catch (Exception e) {
  241. context.getUserAgent().getLogger().error("svg graphic could not be built: "
  242. + e.getMessage(), e);
  243. return;
  244. }
  245. // get the 'width' and 'height' attributes of the SVG document
  246. float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
  247. float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
  248. float sx = pdfInfo.width / (float)w;
  249. float sy = pdfInfo.height / (float)h;
  250. ctx = null;
  251. builder = null;
  252. /*
  253. * Clip to the svg area.
  254. * Note: To have the svg overlay (under) a text area then use
  255. * an fo:block-container
  256. */
  257. pdfInfo.currentStream.add("q\n");
  258. // transform so that the coordinates (0,0) is from the top left
  259. // and positive is down and to the right. (0,0) is where the
  260. // viewBox puts it.
  261. pdfInfo.currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " "
  262. + yOffset / 1000f + " cm\n");
  263. SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
  264. AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, w / 1000f, h / 1000f);
  265. if (!at.isIdentity()) {
  266. double[] vals = new double[6];
  267. at.getMatrix(vals);
  268. pdfInfo.currentStream.add(PDFNumber.doubleOut(vals[0], 5) + " "
  269. + PDFNumber.doubleOut(vals[1], 5) + " "
  270. + PDFNumber.doubleOut(vals[2], 5) + " "
  271. + PDFNumber.doubleOut(vals[3], 5) + " "
  272. + PDFNumber.doubleOut(vals[4]) + " "
  273. + PDFNumber.doubleOut(vals[5]) + " cm\n");
  274. }
  275. if (pdfInfo.pdfContext == null) {
  276. pdfInfo.pdfContext = pdfInfo.pdfPage;
  277. }
  278. PDFGraphics2D graphics = new PDFGraphics2D(true, pdfInfo.fi, pdfInfo.pdfDoc,
  279. pdfInfo.pdfContext, pdfInfo.pdfPage.referencePDF(),
  280. pdfInfo.currentFontName,
  281. pdfInfo.currentFontSize);
  282. graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
  283. pdfInfo.pdfState.push();
  284. transform = new AffineTransform();
  285. // scale to viewbox
  286. transform.translate(xOffset / 1000f, yOffset / 1000f);
  287. pdfInfo.pdfState.setTransform(transform);
  288. graphics.setPDFState(pdfInfo.pdfState);
  289. graphics.setOutputStream(pdfInfo.outputStream);
  290. try {
  291. root.paint(graphics);
  292. pdfInfo.currentStream.add(graphics.getString());
  293. } catch (Exception e) {
  294. context.getUserAgent().getLogger().error("svg graphic could not be rendered: "
  295. + e.getMessage(), e);
  296. }
  297. pdfInfo.currentStream.add("Q\n");
  298. pdfInfo.pdfState.pop();
  299. }
  300. }
  301. }