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 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright 1999-2006 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. import org.w3c.dom.Document;
  23. import org.w3c.dom.svg.SVGDocument;
  24. import org.w3c.dom.svg.SVGSVGElement;
  25. // Batik
  26. import org.apache.avalon.framework.configuration.Configuration;
  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.Renderer;
  35. import org.apache.fop.render.XMLHandler;
  36. import org.apache.fop.render.RendererContext;
  37. import org.apache.fop.svg.SVGUserAgent;
  38. import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
  39. import org.apache.xmlgraphics.ps.PSGenerator;
  40. // Commons-Logging
  41. import org.apache.commons.logging.Log;
  42. import org.apache.commons.logging.LogFactory;
  43. /**
  44. * PostScript XML handler for SVG. Uses Apache Batik for SVG processing.
  45. * This handler handles XML for foreign objects when rendering to PostScript.
  46. * It renders SVG to the PostScript document using the PSGraphics2D.
  47. * The properties from the PostScript renderer are subject to change.
  48. *
  49. * @version $Id$
  50. */
  51. public class PSSVGHandler implements XMLHandler, PSRendererContextConstants {
  52. /** logging instance */
  53. private static Log log = LogFactory.getLog(PSSVGHandler.class);
  54. /**
  55. * Create a new PostScript XML handler for use by the PostScript renderer.
  56. */
  57. public PSSVGHandler() {
  58. }
  59. /** @see org.apache.fop.render.XMLHandler */
  60. public void handleXML(RendererContext context,
  61. Document doc, String ns) throws Exception {
  62. PSInfo psi = getPSInfo(context);
  63. if (SVGDOMImplementation.SVG_NAMESPACE_URI.equals(ns)) {
  64. renderSVGDocument(context, doc, psi);
  65. }
  66. }
  67. /**
  68. * Get the pdf information from the render context.
  69. *
  70. * @param context the renderer context
  71. * @return the pdf information retrieved from the context
  72. */
  73. public static PSInfo getPSInfo(RendererContext context) {
  74. PSInfo psi = new PSInfo();
  75. psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR);
  76. psi.fontInfo = (org.apache.fop.fonts.FontInfo) context.getProperty(PS_FONT_INFO);
  77. psi.width = ((Integer)context.getProperty(WIDTH)).intValue();
  78. psi.height = ((Integer)context.getProperty(HEIGHT)).intValue();
  79. psi.currentXPosition = ((Integer)context.getProperty(XPOS)).intValue();
  80. psi.currentYPosition = ((Integer)context.getProperty(YPOS)).intValue();
  81. psi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION);
  82. return psi;
  83. }
  84. /**
  85. * PostScript information structure for drawing the XML document.
  86. */
  87. public static class PSInfo {
  88. /** see PS_GENERATOR */
  89. private PSGenerator psGenerator;
  90. /** see PS_FONT_INFO */
  91. private org.apache.fop.fonts.FontInfo fontInfo;
  92. /** see WIDTH */
  93. private int width;
  94. /** see HEIGHT */
  95. private int height;
  96. /** see XPOS */
  97. private int currentXPosition;
  98. /** see YPOS */
  99. private int currentYPosition;
  100. /** see HANDLER_CONFIGURATION */
  101. private Configuration cfg;
  102. /**
  103. * Returns the PSGenerator.
  104. * @return PSGenerator
  105. */
  106. public PSGenerator getPSGenerator() {
  107. return psGenerator;
  108. }
  109. /**
  110. * Sets the PSGenerator.
  111. * @param psGenerator The PSGenerator to set
  112. */
  113. public void setPsGenerator(PSGenerator psGenerator) {
  114. this.psGenerator = psGenerator;
  115. }
  116. /**
  117. * Returns the fontInfo.
  118. * @return FontInfo
  119. */
  120. public FontInfo getFontInfo() {
  121. return fontInfo;
  122. }
  123. /**
  124. * Sets the fontInfo.
  125. * @param fontInfo The fontInfo to set
  126. */
  127. public void setFontInfo(FontInfo fontInfo) {
  128. this.fontInfo = fontInfo;
  129. }
  130. /**
  131. * Returns the currentXPosition.
  132. * @return int
  133. */
  134. public int getCurrentXPosition() {
  135. return currentXPosition;
  136. }
  137. /**
  138. * Sets the currentXPosition.
  139. * @param currentXPosition The currentXPosition to set
  140. */
  141. public void setCurrentXPosition(int currentXPosition) {
  142. this.currentXPosition = currentXPosition;
  143. }
  144. /**
  145. * Returns the currentYPosition.
  146. * @return int
  147. */
  148. public int getCurrentYPosition() {
  149. return currentYPosition;
  150. }
  151. /**
  152. * Sets the currentYPosition.
  153. * @param currentYPosition The currentYPosition to set
  154. */
  155. public void setCurrentYPosition(int currentYPosition) {
  156. this.currentYPosition = currentYPosition;
  157. }
  158. /**
  159. * Returns the width.
  160. * @return int
  161. */
  162. public int getWidth() {
  163. return width;
  164. }
  165. /**
  166. * Sets the width.
  167. * @param width The pageWidth to set
  168. */
  169. public void setWidth(int width) {
  170. this.width = width;
  171. }
  172. /**
  173. * Returns the height.
  174. * @return int
  175. */
  176. public int getHeight() {
  177. return height;
  178. }
  179. /**
  180. * Sets the height.
  181. * @param height The height to set
  182. */
  183. public void setHeight(int height) {
  184. this.height = height;
  185. }
  186. /**
  187. * Returns the height.
  188. * @return int
  189. */
  190. public Configuration getHandlerConfiguration() {
  191. return this.cfg;
  192. }
  193. /**
  194. * Sets the handler configuration.
  195. * @param cfg the configuration object
  196. */
  197. public void setHandlerConfiguration(Configuration cfg) {
  198. this.cfg = cfg;
  199. }
  200. }
  201. /**
  202. * Render the svg document.
  203. * @param context the renderer context
  204. * @param doc the svg document
  205. * @param psInfo the pdf information of the current context
  206. */
  207. protected void renderSVGDocument(RendererContext context,
  208. Document doc, PSInfo psInfo) {
  209. int xOffset = psInfo.currentXPosition;
  210. int yOffset = psInfo.currentYPosition;
  211. PSGenerator gen = psInfo.psGenerator;
  212. //Controls whether text painted by Batik is generated using text or path operations
  213. boolean strokeText = false;
  214. Configuration cfg = psInfo.getHandlerConfiguration();
  215. if (cfg != null) {
  216. strokeText = cfg.getChild("stroke-text", true).getValueAsBoolean(strokeText);
  217. }
  218. SVGUserAgent ua
  219. = new SVGUserAgent(
  220. context.getUserAgent().getSourcePixelUnitToMillimeter(),
  221. new AffineTransform());
  222. PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
  223. graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
  224. GVTBuilder builder = new GVTBuilder();
  225. NativeTextHandler nativeTextHandler = null;
  226. BridgeContext ctx = new BridgeContext(ua);
  227. if (!strokeText) {
  228. nativeTextHandler = new NativeTextHandler(graphics, psInfo.getFontInfo());
  229. graphics.setCustomTextHandler(nativeTextHandler);
  230. PSTextPainter textPainter = new PSTextPainter(nativeTextHandler);
  231. ctx.setTextPainter(textPainter);
  232. PSTextElementBridge tBridge = new PSTextElementBridge(textPainter);
  233. ctx.putBridge(tBridge);
  234. }
  235. GraphicsNode root;
  236. try {
  237. root = builder.build(ctx, doc);
  238. } catch (Exception e) {
  239. log.error("SVG graphic could not be built: "
  240. + e.getMessage(), e);
  241. return;
  242. }
  243. // get the 'width' and 'height' attributes of the SVG document
  244. float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
  245. float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
  246. float sx = psInfo.getWidth() / (float)w;
  247. float sy = psInfo.getHeight() / (float)h;
  248. ctx = null;
  249. builder = null;
  250. try {
  251. gen.commentln("%FOPBeginSVG");
  252. gen.saveGraphicsState();
  253. /*
  254. * Clip to the svg area.
  255. * Note: To have the svg overlay (under) a text area then use
  256. * an fo:block-container
  257. */
  258. gen.writeln("newpath");
  259. gen.defineRect(xOffset / 1000f, yOffset / 1000f,
  260. psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f);
  261. gen.writeln("clip");
  262. // transform so that the coordinates (0,0) is from the top left
  263. // and positive is down and to the right. (0,0) is where the
  264. // viewBox puts it.
  265. gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f);
  266. SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
  267. AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg,
  268. psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f);
  269. /*
  270. if (!at.isIdentity()) {
  271. double[] vals = new double[6];
  272. at.getMatrix(vals);
  273. gen.concatMatrix(vals);
  274. }*/
  275. AffineTransform transform = new AffineTransform();
  276. // scale to viewbox
  277. transform.translate(xOffset, yOffset);
  278. gen.getCurrentState().concatMatrix(transform);
  279. try {
  280. root.paint(graphics);
  281. } catch (Exception e) {
  282. log.error("SVG graphic could not be rendered: "
  283. + e.getMessage(), e);
  284. }
  285. gen.restoreGraphicsState();
  286. gen.commentln("%FOPEndSVG");
  287. } catch (IOException ioe) {
  288. log.error("SVG graphic could not be rendered: "
  289. + ioe.getMessage(), ioe);
  290. }
  291. }
  292. /** @see org.apache.fop.render.XMLHandler#supportsRenderer(org.apache.fop.render.Renderer) */
  293. public boolean supportsRenderer(Renderer renderer) {
  294. return (renderer instanceof PSRenderer);
  295. }
  296. /** @see org.apache.fop.render.XMLHandler#getNamespace() */
  297. public String getNamespace() {
  298. return SVGDOMImplementation.SVG_NAMESPACE_URI;
  299. }
  300. }