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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.render.ps;
  19. // Java
  20. import java.awt.geom.AffineTransform;
  21. import java.io.IOException;
  22. import java.util.Map;
  23. import org.w3c.dom.Document;
  24. import org.apache.batik.bridge.BridgeContext;
  25. import org.apache.batik.bridge.GVTBuilder;
  26. import org.apache.batik.gvt.GraphicsNode;
  27. import org.apache.xmlgraphics.java2d.ps.PSGraphics2D;
  28. import org.apache.xmlgraphics.ps.PSGenerator;
  29. import org.apache.fop.configuration.Configuration;
  30. import org.apache.fop.fonts.FontInfo;
  31. import org.apache.fop.image.loader.batik.BatikUtil;
  32. import org.apache.fop.render.AbstractGenericSVGHandler;
  33. import org.apache.fop.render.ImageHandlerUtil;
  34. import org.apache.fop.render.Renderer;
  35. import org.apache.fop.render.RendererContext;
  36. import org.apache.fop.render.RendererContextConstants;
  37. import org.apache.fop.svg.SVGEventProducer;
  38. import org.apache.fop.svg.SVGUserAgent;
  39. /**
  40. * PostScript XML handler for SVG. Uses Apache Batik for SVG processing.
  41. * This handler handles XML for foreign objects when rendering to PostScript.
  42. * It renders SVG to the PostScript document using the PSGraphics2D.
  43. * The properties from the PostScript renderer are subject to change.
  44. *
  45. * @version $Id$
  46. */
  47. public class PSSVGHandler extends AbstractGenericSVGHandler
  48. implements PSRendererContextConstants {
  49. /**
  50. * Create a new PostScript XML handler for use by the PostScript renderer.
  51. */
  52. public PSSVGHandler() {
  53. }
  54. /**
  55. * Get the pdf information from the render context.
  56. *
  57. * @param context the renderer context
  58. * @return the pdf information retrieved from the context
  59. */
  60. public static PSInfo getPSInfo(RendererContext context) {
  61. PSInfo psi = new PSInfo();
  62. psi.psGenerator = (PSGenerator)context.getProperty(PS_GENERATOR);
  63. psi.fontInfo = (org.apache.fop.fonts.FontInfo) context.getProperty(PS_FONT_INFO);
  64. psi.width = (Integer) context.getProperty(WIDTH);
  65. psi.height = (Integer) context.getProperty(HEIGHT);
  66. psi.currentXPosition = (Integer) context.getProperty(XPOS);
  67. psi.currentYPosition = (Integer) context.getProperty(YPOS);
  68. psi.cfg = (Configuration)context.getProperty(HANDLER_CONFIGURATION);
  69. return psi;
  70. }
  71. /**
  72. * PostScript information structure for drawing the XML document.
  73. */
  74. public static class PSInfo {
  75. /** see PS_GENERATOR */
  76. private PSGenerator psGenerator;
  77. /** see PS_FONT_INFO */
  78. private org.apache.fop.fonts.FontInfo fontInfo;
  79. /** see WIDTH */
  80. private int width;
  81. /** see HEIGHT */
  82. private int height;
  83. /** see XPOS */
  84. private int currentXPosition;
  85. /** see YPOS */
  86. private int currentYPosition;
  87. /** see HANDLER_CONFIGURATION */
  88. private Configuration cfg;
  89. /**
  90. * Returns the PSGenerator.
  91. * @return PSGenerator
  92. */
  93. public PSGenerator getPSGenerator() {
  94. return psGenerator;
  95. }
  96. /**
  97. * Sets the PSGenerator.
  98. * @param psGenerator The PSGenerator to set
  99. */
  100. public void setPsGenerator(PSGenerator psGenerator) {
  101. this.psGenerator = psGenerator;
  102. }
  103. /**
  104. * Returns the fontInfo.
  105. * @return FontInfo
  106. */
  107. public FontInfo getFontInfo() {
  108. return fontInfo;
  109. }
  110. /**
  111. * Sets the fontInfo.
  112. * @param fontInfo The fontInfo to set
  113. */
  114. public void setFontInfo(FontInfo fontInfo) {
  115. this.fontInfo = fontInfo;
  116. }
  117. /**
  118. * Returns the currentXPosition.
  119. * @return int
  120. */
  121. public int getCurrentXPosition() {
  122. return currentXPosition;
  123. }
  124. /**
  125. * Sets the currentXPosition.
  126. * @param currentXPosition The currentXPosition to set
  127. */
  128. public void setCurrentXPosition(int currentXPosition) {
  129. this.currentXPosition = currentXPosition;
  130. }
  131. /**
  132. * Returns the currentYPosition.
  133. * @return int
  134. */
  135. public int getCurrentYPosition() {
  136. return currentYPosition;
  137. }
  138. /**
  139. * Sets the currentYPosition.
  140. * @param currentYPosition The currentYPosition to set
  141. */
  142. public void setCurrentYPosition(int currentYPosition) {
  143. this.currentYPosition = currentYPosition;
  144. }
  145. /**
  146. * Returns the width.
  147. * @return int
  148. */
  149. public int getWidth() {
  150. return width;
  151. }
  152. /**
  153. * Sets the width.
  154. * @param width The pageWidth to set
  155. */
  156. public void setWidth(int width) {
  157. this.width = width;
  158. }
  159. /**
  160. * Returns the height.
  161. * @return int
  162. */
  163. public int getHeight() {
  164. return height;
  165. }
  166. /**
  167. * Sets the height.
  168. * @param height The height to set
  169. */
  170. public void setHeight(int height) {
  171. this.height = height;
  172. }
  173. /**
  174. * Returns the height.
  175. * @return int
  176. */
  177. public Configuration getHandlerConfiguration() {
  178. return this.cfg;
  179. }
  180. /**
  181. * Sets the handler configuration.
  182. * @param cfg the configuration object
  183. */
  184. public void setHandlerConfiguration(Configuration cfg) {
  185. this.cfg = cfg;
  186. }
  187. }
  188. /**
  189. * Render the svg document.
  190. * @param context the renderer context
  191. * @param doc the svg document
  192. */
  193. protected void renderSVGDocument(RendererContext context, Document doc) {
  194. assert context != null;
  195. PSInfo psInfo = getPSInfo(context);
  196. int xOffset = psInfo.currentXPosition;
  197. int yOffset = psInfo.currentYPosition;
  198. PSGenerator gen = psInfo.psGenerator;
  199. boolean paintAsBitmap = false;
  200. Map foreign = (Map)context.getProperty(RendererContextConstants.FOREIGN_ATTRIBUTES);
  201. paintAsBitmap = ImageHandlerUtil.isConversionModeBitmap(foreign);
  202. if (paintAsBitmap) {
  203. try {
  204. super.renderSVGDocument(context, doc);
  205. } catch (IOException ioe) {
  206. SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
  207. context.getUserAgent().getEventBroadcaster());
  208. eventProducer.svgRenderingError(this, ioe, getDocumentURI(doc));
  209. }
  210. return;
  211. }
  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 = new SVGUserAgent(context.getUserAgent(), null /* TODO */, new AffineTransform());
  219. PSGraphics2D graphics = new PSGraphics2D(strokeText, gen);
  220. graphics.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext());
  221. BridgeContext ctx = new PSBridgeContext(ua,
  222. (strokeText ? null : psInfo.fontInfo),
  223. context.getUserAgent().getImageManager(),
  224. context.getUserAgent().getImageSessionContext());
  225. //Cloning SVG DOM as Batik attaches non-thread-safe facilities (like the CSS engine)
  226. //to it.
  227. Document clonedDoc = BatikUtil.cloneSVGDocument(doc);
  228. GraphicsNode root;
  229. try {
  230. GVTBuilder builder = new GVTBuilder();
  231. root = builder.build(ctx, clonedDoc);
  232. } catch (Exception e) {
  233. SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
  234. context.getUserAgent().getEventBroadcaster());
  235. eventProducer.svgNotBuilt(this, e, getDocumentURI(doc));
  236. return;
  237. }
  238. // get the 'width' and 'height' attributes of the SVG document
  239. float w = (float)ctx.getDocumentSize().getWidth() * 1000f;
  240. float h = (float)ctx.getDocumentSize().getHeight() * 1000f;
  241. float sx = psInfo.getWidth() / w;
  242. float sy = psInfo.getHeight() / h;
  243. try {
  244. gen.commentln("%FOPBeginSVG");
  245. gen.saveGraphicsState();
  246. /*
  247. * Clip to the svg area.
  248. * Note: To have the svg overlay (under) a text area then use
  249. * an fo:block-container
  250. */
  251. gen.writeln("newpath");
  252. gen.defineRect(xOffset / 1000f, yOffset / 1000f,
  253. psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f);
  254. gen.writeln("clip");
  255. // transform so that the coordinates (0,0) is from the top left
  256. // and positive is down and to the right. (0,0) is where the
  257. // viewBox puts it.
  258. gen.concatMatrix(sx, 0, 0, sy, xOffset / 1000f, yOffset / 1000f);
  259. /*
  260. SVGSVGElement svg = ((SVGDocument)doc).getRootElement();
  261. AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg,
  262. psInfo.getWidth() / 1000f, psInfo.getHeight() / 1000f, ctx);
  263. if (!at.isIdentity()) {
  264. double[] vals = new double[6];
  265. at.getMatrix(vals);
  266. gen.concatMatrix(vals);
  267. }*/
  268. AffineTransform transform = new AffineTransform();
  269. // scale to viewbox
  270. transform.translate(xOffset, yOffset);
  271. gen.getCurrentState().concatMatrix(transform);
  272. try {
  273. root.paint(graphics);
  274. } catch (Exception e) {
  275. SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
  276. context.getUserAgent().getEventBroadcaster());
  277. eventProducer.svgRenderingError(this, e, getDocumentURI(doc));
  278. }
  279. gen.restoreGraphicsState();
  280. gen.commentln("%FOPEndSVG");
  281. } catch (IOException ioe) {
  282. SVGEventProducer eventProducer = SVGEventProducer.Provider.get(
  283. context.getUserAgent().getEventBroadcaster());
  284. eventProducer.svgRenderingError(this, ioe, getDocumentURI(doc));
  285. }
  286. }
  287. /** {@inheritDoc} */
  288. public boolean supportsRenderer(Renderer renderer) {
  289. return false;
  290. }
  291. }