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.

AbstractFOPImageElementBridge.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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.svg;
  19. import java.awt.Graphics2D;
  20. import java.awt.Shape;
  21. import java.awt.geom.Rectangle2D;
  22. import org.apache.batik.bridge.BridgeContext;
  23. import org.apache.batik.bridge.SVGImageElementBridge;
  24. import org.apache.batik.gvt.AbstractGraphicsNode;
  25. import org.apache.batik.gvt.GraphicsNode;
  26. import org.apache.batik.util.ParsedURL;
  27. import org.apache.xmlgraphics.image.loader.Image;
  28. import org.apache.xmlgraphics.image.loader.ImageException;
  29. import org.apache.xmlgraphics.image.loader.ImageFlavor;
  30. import org.apache.xmlgraphics.image.loader.ImageInfo;
  31. import org.apache.xmlgraphics.image.loader.ImageManager;
  32. import org.apache.xmlgraphics.image.loader.ImageSessionContext;
  33. import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
  34. import org.apache.xmlgraphics.image.loader.impl.ImageRawCCITTFax;
  35. import org.apache.xmlgraphics.image.loader.impl.ImageRawJPEG;
  36. import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM;
  37. import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
  38. import org.w3c.dom.Element;
  39. import org.w3c.dom.svg.SVGDocument;
  40. /**
  41. * Bridge class for the <image> element when jpeg images.
  42. *
  43. * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
  44. */
  45. public abstract class AbstractFOPImageElementBridge extends SVGImageElementBridge {
  46. /**
  47. * Constructs a new bridge for the &lt;image> element.
  48. */
  49. public AbstractFOPImageElementBridge() { }
  50. /**
  51. * Create the raster image node.
  52. * THis checks if it is a jpeg file and creates a jpeg node
  53. * so the jpeg can be inserted directly into the pdf document.
  54. * @param ctx the bridge context
  55. * @param imageElement the svg element for the image
  56. * @param purl the parsed url for the image resource
  57. * @return a new graphics node
  58. */
  59. protected GraphicsNode createImageGraphicsNode
  60. (BridgeContext ctx, Element imageElement, ParsedURL purl) {
  61. AbstractFOPBridgeContext bridgeCtx = (AbstractFOPBridgeContext)ctx;
  62. ImageManager manager = bridgeCtx.getImageManager();
  63. ImageSessionContext sessionContext = bridgeCtx.getImageSessionContext();
  64. try {
  65. ImageInfo info = manager.getImageInfo(purl.toString(), sessionContext);
  66. ImageFlavor[] supportedFlavors = getSupportedFlavours();
  67. Image image = manager.getImage(info, supportedFlavors, sessionContext);
  68. //TODO color profile overrides aren't handled, yet!
  69. //ICCColorSpaceExt colorspaceOverride = extractColorSpace(e, ctx);
  70. AbstractGraphicsNode specializedNode = null;
  71. if (image instanceof ImageXMLDOM) {
  72. ImageXMLDOM xmlImage = (ImageXMLDOM)image;
  73. if (xmlImage.getDocument() instanceof SVGDocument) {
  74. return createSVGImageNode(ctx, imageElement,
  75. (SVGDocument)xmlImage.getDocument());
  76. } else {
  77. //Convert image to Graphics2D
  78. image = manager.convertImage(xmlImage,
  79. new ImageFlavor[] {ImageFlavor.GRAPHICS2D});
  80. }
  81. }
  82. if (image instanceof ImageRawJPEG) {
  83. specializedNode = createLoaderImageNode(image, ctx, imageElement, purl);
  84. } else if (image instanceof ImageRawCCITTFax) {
  85. specializedNode = createLoaderImageNode(image, ctx, imageElement, purl);
  86. } else if (image instanceof ImageGraphics2D) {
  87. ImageGraphics2D g2dImage = (ImageGraphics2D)image;
  88. specializedNode = new Graphics2DNode(g2dImage);
  89. } else {
  90. ctx.getUserAgent().displayError(
  91. new ImageException("Cannot convert an image to a usable format: " + purl));
  92. }
  93. Rectangle2D imgBounds = getImageBounds(ctx, imageElement);
  94. Rectangle2D bounds = specializedNode.getPrimitiveBounds();
  95. float [] vb = new float[4];
  96. vb[0] = 0; // x
  97. vb[1] = 0; // y
  98. vb[2] = (float) bounds.getWidth(); // width
  99. vb[3] = (float) bounds.getHeight(); // height
  100. // handles the 'preserveAspectRatio', 'overflow' and 'clip'
  101. // and sets the appropriate AffineTransform to the image node
  102. initializeViewport(ctx, imageElement, specializedNode, vb, imgBounds);
  103. return specializedNode;
  104. } catch (Exception e) {
  105. ctx.getUserAgent().displayError(e);
  106. }
  107. return superCreateGraphicsNode(ctx, imageElement, purl);
  108. }
  109. /**
  110. * Calls the superclass' createImageGraphicNode() method to create the normal GraphicsNode.
  111. * @param ctx the bridge context
  112. * @param imageElement the image element
  113. * @param purl the parsed URL
  114. * @return the newly created graphics node
  115. * @see org.apache.batik.bridge.SVGImageElementBridge#createGraphicsNode(BridgeContext, Element)
  116. */
  117. protected GraphicsNode superCreateGraphicsNode
  118. (BridgeContext ctx, Element imageElement, ParsedURL purl) {
  119. return super.createImageGraphicsNode(ctx, imageElement, purl);
  120. }
  121. /**
  122. * Returns an array of supported image flavours
  123. *
  124. * @return an array of supported image flavours
  125. */
  126. protected abstract ImageFlavor[] getSupportedFlavours();
  127. /**
  128. * Creates a loader image node implementation
  129. * @param purl the parsed url
  130. * @param imageElement the image element
  131. * @param ctx the batik bridge context
  132. * @param image the image
  133. *
  134. * @return a loader image node implementation
  135. */
  136. protected LoaderImageNode createLoaderImageNode(
  137. Image image, BridgeContext ctx, Element imageElement, ParsedURL purl) {
  138. return new LoaderImageNode(image, ctx, imageElement, purl);
  139. }
  140. /**
  141. * An image node for natively handled Image instance.
  142. * This holds a natively handled image so that it can be drawn into
  143. * the PDFGraphics2D.
  144. */
  145. public class LoaderImageNode extends AbstractGraphicsNode {
  146. protected final Image image;
  147. protected final BridgeContext ctx;
  148. protected final Element imageElement;
  149. protected final ParsedURL purl;
  150. protected GraphicsNode origGraphicsNode = null;
  151. /**
  152. * Create a new image node for drawing natively handled images
  153. * into PDF graphics.
  154. * @param image the JPEG image
  155. * @param ctx the bridge context
  156. * @param imageElement the SVG image element
  157. * @param purl the URL to the image
  158. */
  159. public LoaderImageNode(Image image, BridgeContext ctx,
  160. Element imageElement, ParsedURL purl) {
  161. this.image = image;
  162. this.ctx = ctx;
  163. this.imageElement = imageElement;
  164. this.purl = purl;
  165. }
  166. /** {@inheritDoc} */
  167. public Shape getOutline() {
  168. return getPrimitiveBounds();
  169. }
  170. /** {@inheritDoc} */
  171. public void primitivePaint(Graphics2D g2d) {
  172. if (g2d instanceof NativeImageHandler) {
  173. NativeImageHandler nativeImageHandler = (NativeImageHandler) g2d;
  174. float x = 0;
  175. float y = 0;
  176. try {
  177. float width = image.getSize().getWidthPx();
  178. float height = image.getSize().getHeightPx();
  179. nativeImageHandler.addNativeImage(image, x, y, width, height);
  180. } catch (Exception e) {
  181. ctx.getUserAgent().displayError(e);
  182. }
  183. } else {
  184. // Not going directly into PDF so use
  185. // original implementation so filters etc work.
  186. if (origGraphicsNode == null) {
  187. // Haven't constructed base class Graphics Node,
  188. // so do so now.
  189. origGraphicsNode
  190. = superCreateGraphicsNode(ctx, imageElement, purl);
  191. }
  192. origGraphicsNode.primitivePaint(g2d);
  193. }
  194. }
  195. /** {@inheritDoc} */
  196. public Rectangle2D getGeometryBounds() {
  197. return getPrimitiveBounds();
  198. }
  199. /** {@inheritDoc} */
  200. public Rectangle2D getPrimitiveBounds() {
  201. return new Rectangle2D.Double(0, 0,
  202. image.getSize().getWidthPx(),
  203. image.getSize().getHeightPx());
  204. }
  205. /** {@inheritDoc} */
  206. public Rectangle2D getSensitiveBounds() {
  207. //No interactive features, just return primitive bounds
  208. return getPrimitiveBounds();
  209. }
  210. }
  211. /**
  212. * A node that holds a Graphics2D image.
  213. */
  214. public class Graphics2DNode extends AbstractGraphicsNode {
  215. private final ImageGraphics2D image;
  216. /**
  217. * Create a new Graphics2D node.
  218. * @param g2d the Graphics2D image
  219. */
  220. public Graphics2DNode(ImageGraphics2D g2d) {
  221. this.image = g2d;
  222. }
  223. /** {@inheritDoc} */
  224. public Shape getOutline() {
  225. return getPrimitiveBounds();
  226. }
  227. /** {@inheritDoc} */
  228. public void primitivePaint(Graphics2D g2d) {
  229. int width = image.getSize().getWidthPx();
  230. int height = image.getSize().getHeightPx();
  231. Rectangle2D area = new Rectangle2D.Double(0, 0, width, height);
  232. Graphics2DImagePainter painter = image.getGraphics2DImagePainter();
  233. painter.paint(g2d, area);
  234. }
  235. /** {@inheritDoc} */
  236. public Rectangle2D getGeometryBounds() {
  237. return getPrimitiveBounds();
  238. }
  239. /** {@inheritDoc} */
  240. public Rectangle2D getPrimitiveBounds() {
  241. return new Rectangle2D.Double(0, 0,
  242. image.getSize().getWidthPx(),
  243. image.getSize().getHeightPx());
  244. }
  245. /** {@inheritDoc} */
  246. public Rectangle2D getSensitiveBounds() {
  247. //No interactive features, just return primitive bounds
  248. return getPrimitiveBounds();
  249. }
  250. }
  251. }