diff options
author | Jeremias Maerki <jeremias@apache.org> | 2008-08-05 15:31:00 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2008-08-05 15:31:00 +0000 |
commit | 83abc0b9b18852ffed4533d18f27e1b27df081b5 (patch) | |
tree | 7659b6be4f8f6183f8625a343caed2f7606f6909 /src/sandbox | |
parent | 46631569e9ccd7e2a179b0c6d1349fa7451ccc70 (diff) | |
download | xmlgraphics-fop-83abc0b9b18852ffed4533d18f27e1b27df081b5.tar.gz xmlgraphics-fop-83abc0b9b18852ffed4533d18f27e1b27df081b5.zip |
First steps at unified image handling as proposed on http://wiki.apache.org/xmlgraphics-fop/ImageSupport/ImageHandler. This shall serve as a preview to motivate early feedback if anyone is interested.
Basic external-graphic support now available for PDF and SVG painters (for PDF: RenderedImage, SVG, JPEG, CCITT and Java2D, for SVG: embedded SVG and RFC2397 data URLs containing PNG and JPEG images)
Change to IFPainter: added support for foreign attributes for the "image" tag.
PDFContentGenerator introduced to hold the most important objects for PDF generation (unification for renderer and painter).
Re-routed most image handling through the new image handling code (not fully done, yet, some code duplication remains).
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@682757 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/sandbox')
6 files changed, 429 insertions, 3 deletions
diff --git a/src/sandbox/META-INF/services/org.apache.fop.render.ImageHandler b/src/sandbox/META-INF/services/org.apache.fop.render.ImageHandler new file mode 100644 index 000000000..49af6340e --- /dev/null +++ b/src/sandbox/META-INF/services/org.apache.fop.render.ImageHandler @@ -0,0 +1,2 @@ +org.apache.fop.render.svg.SVGDataUrlImageHandler
+org.apache.fop.render.svg.EmbeddedSVGImageHandler
diff --git a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java b/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java index 87f7a3df4..1dcc1a153 100644 --- a/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java +++ b/src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java @@ -24,13 +24,30 @@ 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.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +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.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.intermediate.AbstractXMLWritingIFPainter; +import org.apache.fop.render.intermediate.IFConstants; import org.apache.fop.render.intermediate.IFException; import org.apache.fop.render.intermediate.IFState; import org.apache.fop.util.ColorUtil; @@ -41,6 +58,9 @@ import org.apache.fop.util.ColorUtil; public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter implements SVGConstants { + /** logging instance */ + private static Log log = LogFactory.getLog(AbstractSVGPainter.class); + /** Holds the intermediate format state */ protected IFState state; @@ -184,11 +204,81 @@ public abstract class AbstractSVGPainter extends AbstractXMLWritingIFPainter } + private QName CONVERSION_MODE = new QName(ExtensionElementMapping.URI, null, "conversion-mode"); + /** {@inheritDoc} */ - public void drawImage(String uri, Rectangle rect) throws IFException { - //establish(MODE_NORMAL); - // TODO Auto-generated method stub + public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException { + try { + establish(MODE_NORMAL); + ImageManager manager = getUserAgent().getFactory().getImageManager(); + ImageInfo info = null; + 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) + && (MimeConstants.MIME_GIF.equals(mime) + || MimeConstants.MIME_JPEG.equals(mime) + || MimeConstants.MIME_PNG.equals(mime) + || MimeConstants.MIME_SVG.equals(mime))) { + //Just reference the image + //TODO Some additional URI rewriting might be necessary + AttributesImpl atts = new AttributesImpl(); + addAttribute(atts, IFConstants.XLINK_HREF, uri); + 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)); + 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; + } + } + } 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); + } + } catch (SAXException e) { + throw new IFException("SAX error in drawImage()", e); + } } /** {@inheritDoc} */ diff --git a/src/sandbox/org/apache/fop/render/svg/EmbeddedSVGImageHandler.java b/src/sandbox/org/apache/fop/render/svg/EmbeddedSVGImageHandler.java new file mode 100644 index 000000000..b20982d54 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/EmbeddedSVGImageHandler.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.svg; + +import java.awt.Rectangle; +import java.io.IOException; + +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.util.QName; + +import org.apache.fop.image.loader.batik.BatikImageFlavors; +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.intermediate.DelegatingFragmentContentHandler; + +/** + * Image handler implementation that embeds SVG images in the target SVG file. + */ +public class EmbeddedSVGImageHandler implements ImageHandler, SVGConstants { + + /** logging instance */ + private static Log log = LogFactory.getLog(EmbeddedSVGImageHandler.class); + + /** Constant for the "CDATA" attribute type. */ + private static final String CDATA = "CDATA"; + + /** {@inheritDoc} */ + public int getPriority() { + return 500; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawStream.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + BatikImageFlavors.SVG_DOM + }; + } + + private void addAttribute(AttributesImpl atts, QName attribute, String value) { + atts.addAttribute(attribute.getNamespaceURI(), + attribute.getLocalName(), attribute.getQName(), CDATA, value); + } + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, final Rectangle pos) + throws IOException { + SVGRenderingContext svgContext = (SVGRenderingContext)context; + ImageXMLDOM svg = (ImageXMLDOM)image; + ContentHandler handler = svgContext.getContentHandler(); + AttributesImpl atts = new AttributesImpl(); + atts.addAttribute("", "x", "x", CDATA, Integer.toString(pos.x)); + atts.addAttribute("", "y", "y", CDATA, Integer.toString(pos.y)); + atts.addAttribute("", "width", "width", CDATA, Integer.toString(pos.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(pos.height)); + try { + //handler.startElement(NAMESPACE, "svg", "svg", atts); + + Document doc = (Document)svg.getDocument(); + Element svgEl = (Element)doc.getDocumentElement(); + if (svgEl.getAttribute("viewBox").length() == 0) { + log.warn("SVG doesn't have a viewBox. The result might not be scaled correctly!"); + } + + TransformerFactory tFactory = TransformerFactory.newInstance(); + Transformer transformer = tFactory.newTransformer(); + DOMSource src = new DOMSource(svg.getDocument()); + SAXResult res = new SAXResult(new DelegatingFragmentContentHandler(handler) { + + private boolean topLevelSVGFound = false; + + private void setAttribute(AttributesImpl atts, String localName, String value) { + int index; + index = atts.getIndex("", localName); + if (index < 0) { + atts.addAttribute("", localName, localName, CDATA, value); + } else { + atts.setAttribute(index, "", localName, localName, CDATA, value); + } + } + + public void startElement(String uri, String localName, String name, Attributes atts) + throws SAXException { + if (!topLevelSVGFound + && SVG_ELEMENT.getNamespaceURI().equals(uri) + && SVG_ELEMENT.getLocalName().equals(localName)) { + topLevelSVGFound = true; + AttributesImpl modAtts = new AttributesImpl(atts); + setAttribute(modAtts, "x", Integer.toString(pos.x)); + setAttribute(modAtts, "y", Integer.toString(pos.y)); + setAttribute(modAtts, "width", Integer.toString(pos.width)); + setAttribute(modAtts, "height", Integer.toString(pos.height)); + super.startElement(uri, localName, name, modAtts); + } else { + super.startElement(uri, localName, name, atts); + } + } + + }); + transformer.transform(src, res); + //handler.endElement(NAMESPACE, "svg", "svg"); + //} catch (SAXException e) { + //throw new IOException(e.getMessage()); + } catch (TransformerException te) { + throw new IOException(te.getMessage()); + } + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + if (targetContext instanceof SVGRenderingContext) { + if (image == null) { + return true; + } + if (image instanceof ImageXMLDOM) { + ImageXMLDOM svg = (ImageXMLDOM)image; + return NAMESPACE.equals(svg.getRootNamespace()); + } + } + return false; + } + +} diff --git a/src/sandbox/org/apache/fop/render/svg/SVGConstants.java b/src/sandbox/org/apache/fop/render/svg/SVGConstants.java index 56b8d2a8a..54051faf2 100644 --- a/src/sandbox/org/apache/fop/render/svg/SVGConstants.java +++ b/src/sandbox/org/apache/fop/render/svg/SVGConstants.java @@ -19,6 +19,8 @@ package org.apache.fop.render.svg; +import org.apache.xmlgraphics.util.QName; + import org.apache.fop.apps.MimeConstants; /** @@ -46,4 +48,7 @@ public interface SVGConstants { /** XML namespace for XLink */ String XLINK_NAMESPACE = "http://www.w3.org/1999/xlink"; + /** the SVG element */ + QName SVG_ELEMENT = new QName(NAMESPACE, null, "svg"); + } diff --git a/src/sandbox/org/apache/fop/render/svg/SVGDataUrlImageHandler.java b/src/sandbox/org/apache/fop/render/svg/SVGDataUrlImageHandler.java new file mode 100644 index 000000000..4ff565331 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/SVGDataUrlImageHandler.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.svg; + +import java.awt.Rectangle; +import java.io.IOException; +import java.io.InputStream; + +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.AttributesImpl; + +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.util.QName; + +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; +import org.apache.fop.render.intermediate.IFConstants; +import org.apache.fop.util.DataURLUtil; + +/** + * Image handler implementation that embeds JPEG bitmaps as RFC 2397 data URLs in the target SVG + * file. + */ +public class SVGDataUrlImageHandler implements ImageHandler, SVGConstants { + + /** Constant for the "CDATA" attribute type. */ + private static final String CDATA = "CDATA"; + + /** {@inheritDoc} */ + public int getPriority() { + return 500; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawStream.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + ImageFlavor.RAW_PNG, + ImageFlavor.RAW_JPEG, + }; + } + + private void addAttribute(AttributesImpl atts, QName attribute, String value) { + atts.addAttribute(attribute.getNamespaceURI(), + attribute.getLocalName(), attribute.getQName(), CDATA, value); + } + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + SVGRenderingContext svgContext = (SVGRenderingContext)context; + ImageRawStream raw = (ImageRawStream)image; + InputStream in = raw.createInputStream(); + try { + ContentHandler handler = svgContext.getContentHandler(); + String url = DataURLUtil.createDataURL(in, raw.getMimeType()); + AttributesImpl atts = new AttributesImpl(); + addAttribute(atts, IFConstants.XLINK_HREF, url); + atts.addAttribute("", "x", "x", CDATA, Integer.toString(pos.x)); + atts.addAttribute("", "y", "y", CDATA, Integer.toString(pos.y)); + atts.addAttribute("", "width", "width", CDATA, Integer.toString(pos.width)); + atts.addAttribute("", "height", "height", CDATA, Integer.toString(pos.height)); + try { + handler.startElement(NAMESPACE, "image", "image", atts); + handler.endElement(NAMESPACE, "image", "image"); + } catch (SAXException e) { + throw new IOException(e.getMessage()); + } + } finally { + IOUtils.closeQuietly(in); + } + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + return (image == null || image instanceof ImageRawStream) + && targetContext instanceof SVGRenderingContext; + } + +} diff --git a/src/sandbox/org/apache/fop/render/svg/SVGRenderingContext.java b/src/sandbox/org/apache/fop/render/svg/SVGRenderingContext.java new file mode 100644 index 000000000..5e64af677 --- /dev/null +++ b/src/sandbox/org/apache/fop/render/svg/SVGRenderingContext.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.render.svg; + +import org.xml.sax.ContentHandler; + +import org.apache.xmlgraphics.util.MimeConstants; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.AbstractRenderingContext; + +/** + * Rendering context for SVG production. + */ +public class SVGRenderingContext extends AbstractRenderingContext { + + private ContentHandler handler; + + /** + * Main constructor. + * @param userAgent the user agent + * @param handler the target content handler + */ + public SVGRenderingContext(FOUserAgent userAgent, ContentHandler handler) { + super(userAgent); + this.handler = handler; + } + + /** {@inheritDoc} */ + public String getMimeType() { + return MimeConstants.MIME_SVG; + } + + /** + * Returns the target content handler. + * @return the content handler + */ + public ContentHandler getContentHandler() { + return this.handler; + } + +} |