aboutsummaryrefslogtreecommitdiffstats
path: root/src/sandbox
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2008-08-05 15:31:00 +0000
committerJeremias Maerki <jeremias@apache.org>2008-08-05 15:31:00 +0000
commit83abc0b9b18852ffed4533d18f27e1b27df081b5 (patch)
tree7659b6be4f8f6183f8625a343caed2f7606f6909 /src/sandbox
parent46631569e9ccd7e2a179b0c6d1349fa7451ccc70 (diff)
downloadxmlgraphics-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')
-rw-r--r--src/sandbox/META-INF/services/org.apache.fop.render.ImageHandler2
-rw-r--r--src/sandbox/org/apache/fop/render/svg/AbstractSVGPainter.java96
-rw-r--r--src/sandbox/org/apache/fop/render/svg/EmbeddedSVGImageHandler.java164
-rw-r--r--src/sandbox/org/apache/fop/render/svg/SVGConstants.java5
-rw-r--r--src/sandbox/org/apache/fop/render/svg/SVGDataUrlImageHandler.java106
-rw-r--r--src/sandbox/org/apache/fop/render/svg/SVGRenderingContext.java59
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;
+ }
+
+}