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.

PSSVGHandler.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  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. /* $Id$ */
  17. package org.apache.fop.render.ps;
  18. // Java
  19. import java.awt.geom.AffineTransform;
  20. import java.io.IOException;
  21. // DOM
  22. /* org.w3c.dom.Document is not imported to avoid conflict with
  23. org.apache.fop.control.Document */
  24. import org.w3c.dom.svg.SVGDocument;
  25. import org.w3c.dom.svg.SVGSVGElement;
  26. // Batik
  27. import org.apache.batik.bridge.GVTBuilder;
  28. import org.apache.batik.bridge.BridgeContext;
  29. import org.apache.batik.bridge.ViewBox;
  30. import org.apache.batik.dom.svg.SVGDOMImplementation;
  31. import org.apache.batik.gvt.GraphicsNode;
  32. // FOP
  33. import org.apache.fop.fonts.FontInfo;
  34. import org.apache.fop.render.XMLHandler;
  35. import org.apache.fop.render.RendererContext;
  36. import org.apache.fop.svg.SVGUserAgent;
  37. // Commons-Logging
  38. import org.apache.commons.logging.Log;
  39. import org.apache.commons.logging.LogFactory;
  40. /**
  41. * PostScript XML handler for SVG. Uses Apache Batik for SVG processing.
  42. * This handler handles XML for foreign objects when rendering to PostScript.
  43. * It renders SVG to the PostScript document using the PSGraphics2D.
  44. * The properties from the PostScript renderer are subject to change.
  45. *
  46. * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a>
  47. * @version $Id$
  48. */
  49. public class PSSVGHandler implements XMLHandler {
  50. /**
  51. * logging instance
  52. */
  53. private Log log = LogFactory.getLog(PSSVGHandler.class);
  54. /**
  55. * The PostScript generator that is being used to drawn into.
  56. */
  57. public static final String PS_GENERATOR = "psGenerator";
  58. /**
  59. * The font information for the PostScript renderer.
  60. */
  61. public static final String PS_FONT_INFO = "psFontInfo";
  62. /**
  63. * The width of the SVG graphic.
  64. */
  65. public static final String PS_WIDTH = "width";
  66. /**
  67. * The height of the SVG graphic.
  68. */
  69. public static final String PS_HEIGHT = "height";
  70. /**
  71. * The x position that this is being drawn at.
  72. */
  73. public static final String PS_XPOS = "xpos";
  74. /**
  75. * The y position that this is being drawn at.
  76. */
  77. public static final String PS_YPOS = "ypos";
  78. /**
  79. * Create a new PostScript XML handler for use by the PostScript renderer.
  80. */
  81. public PSSVGHandler() {
  82. }
  83. /** @see org.apache.fop.render.XMLHandler */
  84. public void handleXML(RendererContext context,
  85. org.w3c.dom.Document doc, String ns) throws Exception {
  86. PSInfo psi = getPSInfo(context);
  87. if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) {
  88. SVGHandler svghandler = new SVGHandler();
  89. svghandler.renderSVGDocument(context, doc, psi);
  90. } else {
  91. //nop
  92. }
  93. }
  94. /**
  95. * Get the pdf information from the render context.
  96. *
  97. * @param context the renderer context
  98. * @return the pdf information retrieved from the context
  99. */
  100. public static PSInfo getPSInfo(RendererContext context) {
  101. PSInfo psi = new PSInfo();
  102. psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR);
  103. psi.fontInfo = (org.apache.fop.fonts.FontInfo) context.getProperty(PS_FONT_INFO);
  104. psi.width = ((Integer)context.getProperty(PS_WIDTH)).intValue();
  105. psi.height = ((Integer)context.getProperty(PS_HEIGHT)).intValue();
  106. psi.currentXPosition = ((Integer)context.getProperty(PS_XPOS)).intValue();
  107. psi.currentYPosition = ((Integer)context.getProperty(PS_YPOS)).intValue();
  108. return psi;
  109. }
  110. /**
  111. * PostScript information structure for drawing the XML document.
  112. */
  113. public static class PSInfo {
  114. /** see PS_GENERATOR */
  115. private PSGenerator psGenerator;
  116. /** see PS_FONT_INFO */
  117. private org.apache.fop.fonts.FontInfo fontInfo;
  118. /** see PS_PAGE_WIDTH */
  119. private int width;
  120. /** see PS_PAGE_HEIGHT */
  121. private int height;
  122. /** see PS_XPOS */
  123. private int currentXPosition;
  124. /** see PS_YPOS */
  125. private int currentYPosition;
  126. /**
  127. * Returns the PSGenerator.
  128. * @return PSGenerator
  129. */
  130. public PSGenerator getPSGenerator() {
  131. return psGenerator;
  132. }
  133. /**
  134. * Sets the PSGenerator.
  135. * @param psGenerator The PSGenerator to set
  136. */
  137. public void setPsGenerator(PSGenerator psGenerator) {
  138. this.psGenerator = psGenerator;
  139. }
  140. /**
  141. * Returns the fontInfo.
  142. * @return FontInfo
  143. */
  144. public FontInfo getFontInfo() {
  145. return fontInfo;
  146. }
  147. /**
  148. * Sets the fontInfo.
  149. * @param fontInfo The fontInfo to set
  150. */
  151. public void setFontInfo(FontInfo fontInfo) {
  152. this.fontInfo = fontInfo;
  153. }
  154. /**
  155. * Returns the currentXPosition.
  156. * @return int
  157. */
  158. public int getCurrentXPosition() {
  159. return currentXPosition;
  160. }
  161. /**
  162. * Sets the currentXPosition.
  163. * @param currentXPosition The currentXPosition to set
  164. */
  165. public void setCurrentXPosition(int currentXPosition) {
  166. this.currentXPosition = currentXPosition;
  167. }
  168. /**
  169. * Returns the currentYPosition.
  170. * @return int
  171. */
  172. public int getCurrentYPosition() {
  173. return currentYPosition;
  174. }
  175. /**
  176. * Sets the currentYPosition.
  177. * @param currentYPosition The currentYPosition to set
  178. */
  179. public void setCurrentYPosition(int currentYPosition) {
  180. this.currentYPosition = currentYPosition;
  181. }
  182. /**
  183. * Returns the width.
  184. * @return int
  185. */
  186. public int getWidth() {
  187. return width;
  188. }
  189. /**
  190. * Sets the width.
  191. * @param width The pageWidth to set
  192. */
  193. public void setWidth(int width) {
  194. this.width = width;
  195. }
  196. /**
  197. * Returns the height.
  198. * @return int
  199. */
  200. public int getHeight() {
  201. return height;
  202. }
  203. /**
  204. * Sets the height.
  205. * @param height The height to set
  206. */
  207. public void setHeight(int height) {
  208. this.height = height;
  209. }
  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 psInfo the pdf information of the current context
  221. */
  222. protected void renderSVGDocument(RendererContext context,
  223. org.w3c.dom.Document doc, PSInfo psInfo) {
  224. int xOffset = psInfo.currentXPosition;
  225. int yOffset = psInfo.currentYPosition;
  226. PSGenerator gen = psInfo.psGenerator;
  227. SVGUserAgent ua
  228. = new SVGUserAgent(
  229. context.getUserAgent().getSourcePixelUnitToMillimeter(),
  230. new AffineTransform());
  231. GVTBuilder builder = new GVTBuilder();
  232. BridgeContext ctx = new BridgeContext(ua);
  233. PSTextPainter textPainter = new PSTextPainter(psInfo.getFontInfo());
  234. ctx.setTextPainter(textPainter);
  235. PSTextElementBridge tBridge = new PSTextElementBridge(textPainter);
  236. ctx.putBridge(tBridge);
  237. //PSAElementBridge aBridge = new PSAElementBridge();
  238. // to get the correct transform we need to use the PDFState
  239. AffineTransform transform = gen.getCurrentState().getTransform();
  240. transform.translate(xOffset / 1000f, yOffset / 1000f);
  241. //aBridge.setCurrentTransform(transform);
  242. //ctx.putBridge(aBridge);
  243. GraphicsNode root;
  244. try {
  245. root = builder.build(ctx, doc);
  246. } catch (Exception e) {
  247. log.error("SVG graphic could not be built: "
  248. + e.getMessage(), e);
  249. return;
  250. }
  251. // get the 'width' and 'height' attributes of the SVG document
  252. float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
  253. float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
  254. float sx = psInfo.getWidth() / (float)w;
  255. float sy = psInfo.getHeight() / (float)h;
  256. ctx = null;
  257. builder = null;
  258. try {
  259. gen.commentln("%FOPBeginSVG");
  260. gen.saveGraphicsState();
  261. /*
  262. * Clip to the svg area.
  263. * Note: To have the svg overlay (under) a text area then use
  264. * an fo:block-container
  265. */
  266. gen.writeln("newpath");
  267. gen.defineRect(xOffset / 1000f, yOffset / 1000f,
  268. psInfo.getWidth() / 1000f, psInfo.getWidth() / 1000f);
  269. //TODO Is the above correct? Twice getWidth??????????????
  270. gen.writeln("clip");
  271. // transform so that the coordinates (0,0) is from the top left
  272. // and positive is down and to the right. (0,0) is where the
  273. // viewBox puts it.
  274. gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f);
  275. SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
  276. AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg,
  277. psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f);
  278. if (false && !at.isIdentity()) {
  279. double[] vals = new double[6];
  280. at.getMatrix(vals);
  281. gen.concatMatrix(vals);
  282. }
  283. final boolean textAsShapes = false;
  284. PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
  285. graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
  286. transform = new AffineTransform();
  287. // scale to viewbox
  288. transform.translate(xOffset, yOffset);
  289. gen.getCurrentState().concatMatrix(transform);
  290. try {
  291. root.paint(graphics);
  292. } catch (Exception e) {
  293. log.error("SVG graphic could not be rendered: "
  294. + e.getMessage(), e);
  295. }
  296. gen.restoreGraphicsState();
  297. gen.commentln("%FOPEndSVG");
  298. } catch (IOException ioe) {
  299. log.error("SVG graphic could not be rendered: "
  300. + ioe.getMessage(), ioe);
  301. }
  302. }
  303. }
  304. /** @see org.apache.fop.render.XMLHandler#getMimeType() */
  305. public String getMimeType() {
  306. return PSRenderer.MIME_TYPE;
  307. }
  308. /** @see org.apache.fop.render.XMLHandler#getNamespace() */
  309. public String getNamespace() {
  310. return SVGDOMImplementation.SVG_NAMESPACE_URI;
  311. }
  312. }