diff options
6 files changed, 260 insertions, 121 deletions
diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java index f5e43229b..c7d6a578b 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -22,15 +22,40 @@ package org.apache.fop.render.intermediate; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.geom.AffineTransform; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Map; + +import javax.xml.transform.dom.DOMSource; + +import org.w3c.dom.Document; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.events.ResourceEventProducer; +import org.apache.fop.render.ImageHandler; import org.apache.fop.render.ImageHandlerRegistry; +import org.apache.fop.render.RenderingContext; /** * Abstract base class for IFPainter implementations. */ public abstract class AbstractIFPainter implements IFPainter { + /** logging instance */ + private static Log log = LogFactory.getLog(AbstractIFPainter.class); + + /** non-URI that can be used in feedback messages that an image is an instream-object */ + protected static final String INSTREAM_OBJECT_URI = "(instream-object)"; + private FOUserAgent userAgent; /** Image handler registry */ @@ -77,4 +102,110 @@ public abstract class AbstractIFPainter implements IFPainter { startGroup(combine(transforms)); } + /** + * Creates a new RenderingContext instance. + * @return the new rendering context. + */ + protected abstract RenderingContext createRenderingContext(); + + /** + * Loads a preloaded image and draws it using a suitable image handler. + * @param info the information object of the preloaded image + * @param rect the rectangle in which to paint the image + * @throws ImageException if there's an error while processing the image + * @throws IOException if there's an I/O error while loading the image + */ + protected void drawImageUsingImageHandler(ImageInfo info, Rectangle rect) + throws ImageException, IOException { + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + + //Load and convert the image to a supported format + RenderingContext context = createRenderingContext(); + Map hints = ImageUtil.getDefaultHints(sessionContext); + org.apache.xmlgraphics.image.loader.Image img = manager.getImage( + info, imageHandlerRegistry.getSupportedFlavors(context), + hints, sessionContext); + + //First check for a dynamically registered handler + ImageHandler handler = imageHandlerRegistry.getHandler(context, img); + if (handler == null) { + throw new UnsupportedOperationException( + "No ImageHandler available for image: " + + info + " (" + img.getClass().getName() + ")"); + } + + if (log.isDebugEnabled()) { + log.debug("Using ImageHandler: " + handler.getClass().getName()); + } + try { + //TODO foreign attributes + handler.handleImage(context, img, rect); + } catch (IOException ioe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageWritingError(this, ioe); + return; + } + } + + /** + * Default drawing method for handling an image referenced by a URI. + * @param uri the image's URI + * @param rect the rectangle in which to paint the image + */ + protected void drawImageUsingURI(String uri, Rectangle rect) { + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageInfo info = null; + try { + ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); + info = manager.getImageInfo(uri, sessionContext); + + drawImageUsingImageHandler(info, rect); + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); + } catch (FileNotFoundException fe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); + } catch (IOException ioe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); + } + } + + /** + * Default drawing method for handling a foreign object in the form of a DOM document. + * @param doc the DOM document containing the foreign object + * @param rect the rectangle in which to paint the image + */ + protected void drawImageUsingDocument(Document doc, Rectangle rect) { + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageInfo info = null; + try { + info = manager.preloadImage(null, new DOMSource(doc)); + + drawImageUsingImageHandler(info, rect); + } catch (ImageException ie) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageError(this, + (info != null ? info.toString() : INSTREAM_OBJECT_URI), ie, null); + } catch (FileNotFoundException fe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageNotFound(this, + (info != null ? info.toString() : INSTREAM_OBJECT_URI), fe, null); + } catch (IOException ioe) { + ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( + getUserAgent().getEventBroadcaster()); + eventProducer.imageIOError(this, + (info != null ? info.toString() : INSTREAM_OBJECT_URI), ioe, null); + } + } + + } diff --git a/src/java/org/apache/fop/render/intermediate/IFPainter.java b/src/java/org/apache/fop/render/intermediate/IFPainter.java index e257caec4..a201c4b06 100644 --- a/src/java/org/apache/fop/render/intermediate/IFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/IFPainter.java @@ -28,6 +28,8 @@ import java.util.Map; import javax.xml.transform.Result; +import org.w3c.dom.Document; + import org.apache.fop.apps.FOUserAgent; import org.apache.fop.fonts.FontInfo; @@ -258,9 +260,33 @@ public interface IFPainter { * @throws IFException if an error occurs while handling this event */ void drawRect(Rectangle rect, Paint fill, Color stroke) throws IFException; - void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException; //external images - void startImage(Rectangle rect) throws IFException; //followed by a SAX stream (SVG etc.) - void endImage() throws IFException; + + /** + * Draws an image identified by a URI inside a given rectangle. This is the equivalent to + * an fo:external-graphic in XSL-FO. + * @param uri the image's URI + * @param rect the rectangle in which the image shall be painted + * @param foreignAttributes a optional Map with foreign attributes (Map<QName,String>) + * @throws IFException if an error occurs while handling this event + */ + void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException; + + /** + * Draws an image (represented by a DOM document) inside a given rectangle. This is the + * equivalent to an fo:instream-foreign-object in XSL-FO. + * @param doc the DOM document containing the foreign object + * @param rect the rectangle in which the image shall be painted + * @param foreignAttributes a optional Map with foreign attributes (Map<QName,String>) + * @throws IFException if an error occurs while handling this event + */ + void drawImage(Document doc, Rectangle rect, Map foreignAttributes) + throws IFException; + //Note: For now, all foreign objects are handled as DOM documents. At the moment, all known + //implementations use a DOM anyway, so optimizing this to work with SAX wouldn't result in + //any performance benefits. The IFRenderer itself has a DOM anyway. Only the IFParser could + //potentially profit if there's an image handler that can efficiently deal with the foreign + //object without building a DOM. + //etc. etc. /** diff --git a/src/java/org/apache/fop/render/intermediate/IFRenderer.java b/src/java/org/apache/fop/render/intermediate/IFRenderer.java index ed25063e5..9bfb10904 100644 --- a/src/java/org/apache/fop/render/intermediate/IFRenderer.java +++ b/src/java/org/apache/fop/render/intermediate/IFRenderer.java @@ -32,6 +32,8 @@ import java.util.Stack; import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; + import org.xml.sax.SAXException; import org.apache.batik.parser.AWTTransformProducer; @@ -57,6 +59,7 @@ import org.apache.fop.area.PageViewport; import org.apache.fop.area.RegionViewport; import org.apache.fop.area.Trait; import org.apache.fop.area.inline.AbstractTextArea; +import org.apache.fop.area.inline.ForeignObject; import org.apache.fop.area.inline.Image; import org.apache.fop.area.inline.SpaceArea; import org.apache.fop.area.inline.TextArea; @@ -73,6 +76,10 @@ import org.apache.fop.fonts.Typeface; import org.apache.fop.render.AbstractPathOrientedRenderer; import org.apache.fop.render.Renderer; +/** + * This renderer implementation is an adapter to the {@code IFPainter} interface. It is used + * to generate content using FOP's intermediate format. + */ public class IFRenderer extends AbstractPathOrientedRenderer { /** logging instance */ @@ -714,21 +721,41 @@ public class IFRenderer extends AbstractPathOrientedRenderer { } } + /** {@inheritDoc} */ + public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + endTextObject(); + Rectangle posInt = new Rectangle( + currentIPPosition + (int)pos.getX(), + currentBPPosition + (int)pos.getY(), + (int)pos.getWidth(), + (int)pos.getHeight()); + Document doc = fo.getDocument(); + try { + painter.drawImage(doc, posInt, fo.getForeignAttributes()); + } catch (IFException ife) { + handleIFException(ife); + } + } + + /** {@inheritDoc} */ protected void clip() { // TODO Auto-generated method stub log.warn("clip() NYI"); } + /** {@inheritDoc} */ protected void clipRect(float x, float y, float width, float height) { // TODO Auto-generated method stub log.warn("clipRect() NYI"); } + /** {@inheritDoc} */ protected void closePath() { // TODO Auto-generated method stub log.warn("closePath() NYI"); } + /** {@inheritDoc} */ protected void drawBorderLine(float x1, float y1, float x2, float y2, boolean horz, boolean startOrBefore, int style, Color col) { // TODO Auto-generated method stub diff --git a/src/java/org/apache/fop/render/intermediate/IFSerializer.java b/src/java/org/apache/fop/render/intermediate/IFSerializer.java index 0f3d20f0b..509746de6 100644 --- a/src/java/org/apache/fop/render/intermediate/IFSerializer.java +++ b/src/java/org/apache/fop/render/intermediate/IFSerializer.java @@ -27,13 +27,17 @@ import java.awt.geom.AffineTransform; import java.util.Iterator; import java.util.Map; +import org.w3c.dom.Document; + import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.util.XMLizable; +import org.apache.fop.render.RenderingContext; import org.apache.fop.util.ColorUtil; +import org.apache.fop.util.DOM2SAX; /** * IFPainter implementation that serializes the intermediate format to XML. @@ -214,7 +218,8 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst startViewport(toString(transforms), size, clipRect); } - private void startViewport(String transform, Dimension size, Rectangle clipRect) throws IFException { + private void startViewport(String transform, Dimension size, Rectangle clipRect) + throws IFException { try { AttributesImpl atts = new AttributesImpl(); if (transform != null && transform.length() > 0) { @@ -272,12 +277,6 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst } /** {@inheritDoc} */ - public void startImage(Rectangle rect) throws IFException { - // TODO Auto-generated method stub - - } - - /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { try { AttributesImpl atts = new AttributesImpl(); @@ -300,9 +299,26 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst } /** {@inheritDoc} */ - public void endImage() throws IFException { - // TODO Auto-generated method stub - + public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { + try { + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "x", "x", CDATA, Integer.toString(rect.x)); + atts.addAttribute("", "y", "y", CDATA, Integer.toString(rect.y)); + atts.addAttribute("", "width", "width", CDATA, Integer.toString(rect.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height)); + if (foreignAttributes != null) { + Iterator iter = foreignAttributes.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + addAttribute(atts, (QName)entry.getKey(), entry.getValue().toString()); + } + } + startElement(EL_IMAGE, atts); + new DOM2SAX(handler).writeDocument(doc, true); + endElement(EL_IMAGE); + } catch (SAXException e) { + throw new IFException("SAX error in startGroup()", e); + } } /** {@inheritDoc} */ @@ -406,4 +422,9 @@ public class IFSerializer extends AbstractXMLWritingIFPainter implements IFConst } } + /** {@inheritDoc} */ + protected RenderingContext createRenderingContext() { + throw new IllegalStateException("Should never be called!"); + } + } diff --git a/src/java/org/apache/fop/render/pdf/PDFPainter.java b/src/java/org/apache/fop/render/pdf/PDFPainter.java index 8747edcec..389025034 100644 --- a/src/java/org/apache/fop/render/pdf/PDFPainter.java +++ b/src/java/org/apache/fop/render/pdf/PDFPainter.java @@ -24,23 +24,18 @@ import java.awt.Dimension; import java.awt.Paint; import java.awt.Rectangle; import java.awt.geom.AffineTransform; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; +import org.w3c.dom.Document; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.xmlgraphics.image.loader.ImageException; -import org.apache.xmlgraphics.image.loader.ImageInfo; -import org.apache.xmlgraphics.image.loader.ImageManager; -import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.xmp.Metadata; import org.apache.fop.apps.FOUserAgent; import org.apache.fop.apps.MimeConstants; -import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fo.extensions.xmp.XMPMetadata; import org.apache.fop.fonts.Font; import org.apache.fop.fonts.FontTriplet; @@ -55,7 +50,7 @@ import org.apache.fop.pdf.PDFResourceContext; import org.apache.fop.pdf.PDFResources; import org.apache.fop.pdf.PDFTextUtil; import org.apache.fop.pdf.PDFXObject; -import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFPainter; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; @@ -295,60 +290,16 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { return; } - ImageManager manager = getUserAgent().getFactory().getImageManager(); - ImageInfo info = null; - try { - ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); - info = manager.getImageInfo(uri, sessionContext); - - PDFRenderingContext pdfContext = new PDFRenderingContext( - getUserAgent(), generator, currentPage, getFontInfo()); - - Map hints = ImageUtil.getDefaultHints(sessionContext); - org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, imageHandlerRegistry.getSupportedFlavors(pdfContext), - hints, sessionContext); - - //First check for a dynamically registered handler - ImageHandler handler = imageHandlerRegistry.getHandler(pdfContext, img); - if (handler == null) { - throw new UnsupportedOperationException( - "No ImageHandler available for image: " - + info + " (" + img.getClass().getName() + ")"); - } + drawImageUsingURI(uri, rect); - if (log.isDebugEnabled()) { - log.debug("Using ImageHandler: " + handler.getClass().getName()); - } - try { - //TODO foreign attributes - handler.handleImage(pdfContext, img, rect); - } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageWritingError(this, ioe); - return; - } - } catch (ImageException ie) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageError(this, (info != null ? info.toString() : uri), ie, null); - } catch (FileNotFoundException fe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageNotFound(this, (info != null ? info.toString() : uri), fe, null); - } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageIOError(this, (info != null ? info.toString() : uri), ioe, null); - } + flushPDFDoc(); + } - // output new data - try { - generator.flushPDFDoc(); - } catch (IOException ioe) { - throw new IFException("I/O error flushing the PDF document", ioe); - } + /** {@inheritDoc} */ + protected RenderingContext createRenderingContext() { + PDFRenderingContext pdfContext = new PDFRenderingContext( + getUserAgent(), generator, currentPage, getFontInfo()); + return pdfContext; } /** @@ -369,17 +320,20 @@ public class PDFPainter extends AbstractBinaryWritingIFPainter { generator.restoreGraphicsState(); } - /** {@inheritDoc} */ - public void startImage(Rectangle rect) throws IFException { - // TODO Auto-generated method stub + public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { + drawImageUsingDocument(doc, rect); + flushPDFDoc(); } - /** {@inheritDoc} */ - public void endImage() throws IFException { - // TODO Auto-generated method stub - + private void flushPDFDoc() throws IFException { + // output new data + try { + generator.flushPDFDoc(); + } catch (IOException ioe) { + throw new IFException("I/O error flushing the PDF document", ioe); + } } /** {@inheritDoc} */ diff --git a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java b/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java index 1dcc1a153..c5d72ad9f 100644 --- a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java +++ b/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java @@ -28,6 +28,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.util.Map; +import org.w3c.dom.Document; + import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; @@ -38,14 +40,13 @@ import org.apache.xmlgraphics.image.loader.ImageException; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.ImageManager; import org.apache.xmlgraphics.image.loader.ImageSessionContext; -import org.apache.xmlgraphics.image.loader.util.ImageUtil; import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.QName; import org.apache.xmlgraphics.xmp.Metadata; import org.apache.fop.events.ResourceEventProducer; import org.apache.fop.fo.extensions.ExtensionElementMapping; -import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; import org.apache.fop.render.intermediate.AbstractXMLWritingIFPainter; import org.apache.fop.render.intermediate.IFConstants; import org.apache.fop.render.intermediate.IFException; @@ -197,14 +198,8 @@ public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter } } - /** {@inheritDoc} */ - public void startImage(Rectangle rect) throws IFException { - //establish(MODE_NORMAL); - // TODO Auto-generated method stub - - } - - private QName CONVERSION_MODE = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); + private static final QName CONVERSION_MODE + = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); /** {@inheritDoc} */ public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { @@ -216,6 +211,7 @@ public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter try { ImageSessionContext sessionContext = getUserAgent().getImageSessionContext(); info = manager.getImageInfo(uri, sessionContext); + String mime = info.getMimeType(); String conversionMode = (String)foreignAttributes.get(CONVERSION_MODE); if ("reference".equals(conversionMode) @@ -233,35 +229,7 @@ public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter atts.addAttribute("", "height", "height", CDATA, Integer.toString(rect.height)); element("image", atts); } else { - //Convert the image - SVGRenderingContext svgContext = new SVGRenderingContext( - getUserAgent(), handler); - - Map hints = ImageUtil.getDefaultHints(sessionContext); - org.apache.xmlgraphics.image.loader.Image img = manager.getImage( - info, imageHandlerRegistry.getSupportedFlavors(svgContext), - hints, sessionContext); - - //First check for a dynamically registered handler - ImageHandler handler = imageHandlerRegistry.getHandler(svgContext, img); - if (handler == null) { - throw new UnsupportedOperationException( - "No ImageHandler available for image: " - + info + " (" + img.getClass().getName() + ")"); - } - - if (log.isDebugEnabled()) { - log.debug("Using ImageHandler: " + handler.getClass().getName()); - } - try { - //TODO foreign attributes - handler.handleImage(svgContext, img, rect); - } catch (IOException ioe) { - ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( - getUserAgent().getEventBroadcaster()); - eventProducer.imageWritingError(this, ioe); - return; - } + drawImageUsingImageHandler(info, rect); } } catch (ImageException ie) { ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get( @@ -282,9 +250,21 @@ public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter } /** {@inheritDoc} */ - public void endImage() throws IFException { - // TODO Auto-generated method stub + public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException { + try { + establish(MODE_NORMAL); + + drawImageUsingDocument(doc, rect); + } catch (SAXException e) { + throw new IFException("SAX error in drawImage()", e); + } + } + /** {@inheritDoc} */ + protected RenderingContext createRenderingContext() { + SVGRenderingContext svgContext = new SVGRenderingContext( + getUserAgent(), handler); + return svgContext; } /** {@inheritDoc} */ |