diff options
Diffstat (limited to 'src/java/org/apache/fop/image')
11 files changed, 960 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/image/loader/batik/BatikUtil.java b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java new file mode 100644 index 000000000..1ae2a9917 --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/BatikUtil.java @@ -0,0 +1,41 @@ +/* + * 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.image.loader.batik; + +/** + * Helper utilities for Apache Batik. + */ +public class BatikUtil { + + /** + * Checks whether Apache Batik is available in the classpath. + * @return true if Apache Batik is available + */ + public static boolean isBatikAvailable() { + try { + Class.forName("org.apache.batik.dom.svg.SVGDOMImplementation"); + return true; + } catch (Exception e) { + //ignore + } + return false; + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java new file mode 100644 index 000000000..81b3b4c07 --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterSVG2G2D.java @@ -0,0 +1,120 @@ +/* + * 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.image.loader.batik; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.util.Map; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.gvt.GraphicsNode; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageProcessingHints; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageConverter; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; +import org.apache.xmlgraphics.util.UnitConv; + +import org.apache.fop.svg.SVGUserAgent; + +/** + * This ImageConverter converts SVG images to Java2D. + * <p> + * Note: The target flavor is "generic" Java2D. No Batik-specific bridges are hooked into the + * conversion process. Specialized renderers may want to provide specialized adapters to profit + * from target-format features (for example with PDF or PS). This converter is mainly for formats + * which only support bitmap images or rudimentary Java2D support. + */ +public class ImageConverterSVG2G2D extends AbstractImageConverter { + + /** {@inheritDoc} */ + public Image convert(Image src, Map hints) throws ImageException { + checkSourceFlavor(src); + final ImageXMLDOM svg = (ImageXMLDOM)src; + if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svg.getRootNamespace())) { + throw new IllegalArgumentException("XML DOM is not in the SVG namespace: " + + svg.getRootNamespace()); + } + + //Prepare + float pxToMillimeter = (float)UnitConv.mm2in(72); //default: 72dpi + Number ptm = (Number)hints.get(ImageProcessingHints.SOURCE_RESOLUTION); + if (ptm != null) { + pxToMillimeter = (float)UnitConv.mm2in(ptm.doubleValue()); + } + SVGUserAgent ua = new SVGUserAgent( + pxToMillimeter, + new AffineTransform()); + GVTBuilder builder = new GVTBuilder(); + final BridgeContext ctx = new BridgeContext(ua); + + //Build the GVT tree + final GraphicsNode root; + try { + root = builder.build(ctx, svg.getDocument()); + } catch (Exception e) { + throw new ImageException("GVT tree could not be built for SVG graphic", e); + } + + //Create the painter + Graphics2DImagePainter painter = new Graphics2DImagePainter() { + + public void paint(Graphics2D g2d, Rectangle2D area) { + // If no viewbox is defined in the svg file, a viewbox of 100x100 is + // assumed, as defined in SVGUserAgent.getViewportSize() + float iw = (float) ctx.getDocumentSize().getWidth(); + float ih = (float) ctx.getDocumentSize().getHeight(); + float w = (float) area.getWidth(); + float h = (float) area.getHeight(); + g2d.translate(area.getX(), area.getY()); + g2d.scale(w / iw, h / ih); + + root.paint(g2d); + } + + public Dimension getImageSize() { + return new Dimension(svg.getSize().getWidthMpt(), svg.getSize().getHeightMpt()); + } + + }; + + ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter); + return g2dImage; + } + + /** {@inheritDoc} */ + public ImageFlavor getSourceFlavor() { + return ImageFlavor.XML_DOM; + } + + /** {@inheritDoc} */ + public ImageFlavor getTargetFlavor() { + return ImageFlavor.GRAPHICS2D; + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java b/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java new file mode 100644 index 000000000..6babe4523 --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageConverterWMF2G2D.java @@ -0,0 +1,107 @@ +/* + * 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.image.loader.batik; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.util.Map; + +import org.apache.batik.transcoder.wmf.tosvg.WMFPainter; +import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore; +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.AbstractImageConverter; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.java2d.Graphics2DImagePainter; + +/** + * This ImageConverter converts WMF (Windows Metafile) images (represented by Batik's + * WMFRecordStore) to Java2D. + */ +public class ImageConverterWMF2G2D extends AbstractImageConverter { + + /** logger */ + private static Log log = LogFactory.getLog(ImageConverterWMF2G2D.class); + + /** {@inheritDoc} */ + public Image convert(Image src, Map hints) { + checkSourceFlavor(src); + ImageWMF wmf = (ImageWMF)src; + + Graphics2DImagePainter painter; + painter = new Graphics2DImagePainterWMF(wmf); + + ImageGraphics2D g2dImage = new ImageGraphics2D(src.getInfo(), painter); + return g2dImage; + } + + /** {@inheritDoc} */ + public ImageFlavor getSourceFlavor() { + return ImageWMF.WMF_IMAGE; + } + + /** {@inheritDoc} */ + public ImageFlavor getTargetFlavor() { + return ImageFlavor.GRAPHICS2D; + } + + private static class Graphics2DImagePainterWMF implements Graphics2DImagePainter { + + private ImageWMF wmf; + + public Graphics2DImagePainterWMF(ImageWMF wmf) { + this.wmf = wmf; + } + + /** {@inheritDoc} */ + public Dimension getImageSize() { + return wmf.getSize().getDimensionMpt(); + } + + /** {@inheritDoc} */ + public void paint(Graphics2D g2d, Rectangle2D area) { + WMFRecordStore wmfStore = wmf.getRecordStore(); + double w = area.getWidth(); + double h = area.getHeight(); + + //Fit in paint area + g2d.translate(area.getX(), area.getY()); + double sx = w / wmfStore.getWidthPixels(); + double sy = h / wmfStore.getHeightPixels(); + if (sx != 1.0 || sy != 1.0) { + g2d.scale(sx, sy); + } + + WMFPainter painter = new WMFPainter(wmfStore, 1.0f); + long start = System.currentTimeMillis(); + painter.paint(g2d); + if (log.isDebugEnabled()) { + long duration = System.currentTimeMillis() - start; + log.debug("Painting WMF took " + duration + " ms."); + } + } + + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java new file mode 100644 index 000000000..fa58d8e4a --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactorySVG.java @@ -0,0 +1,63 @@ +/* + * 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.image.loader.batik; + +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoaderFactory; +import org.apache.xmlgraphics.image.loader.spi.ImageLoader; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * Factory class for the ImageLoader for SVG. + */ +public class ImageLoaderFactorySVG extends AbstractImageLoaderFactory { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageFlavor.XML_DOM}; + + private static final String[] MIMES = new String[] { + MimeConstants.MIME_SVG}; + + /** {@inheritDoc} */ + public String[] getSupportedMIMETypes() { + return MIMES; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedFlavors(String mime) { + return FLAVORS; + } + + /** {@inheritDoc} */ + public ImageLoader newImageLoader(ImageFlavor targetFlavor) { + return new ImageLoaderSVG(targetFlavor); + } + + /** {@inheritDoc} */ + public int getUsagePenalty(String mime, ImageFlavor flavor) { + return 0; + } + + /** {@inheritDoc} */ + public boolean isAvailable() { + return BatikUtil.isBatikAvailable(); + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java new file mode 100644 index 000000000..bfa004d7e --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderFactoryWMF.java @@ -0,0 +1,62 @@ +/* + * 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.image.loader.batik; + +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoaderFactory; +import org.apache.xmlgraphics.image.loader.spi.ImageLoader; + +/** + * Factory class for the ImageLoader for WMF (Windows Metafile). + */ +public class ImageLoaderFactoryWMF extends AbstractImageLoaderFactory { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] { + ImageWMF.WMF_IMAGE}; + + private static final String[] MIMES = new String[] { + ImageWMF.MIME_WMF}; + + /** {@inheritDoc} */ + public String[] getSupportedMIMETypes() { + return MIMES; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedFlavors(String mime) { + return FLAVORS; + } + + /** {@inheritDoc} */ + public ImageLoader newImageLoader(ImageFlavor targetFlavor) { + return new ImageLoaderWMF(targetFlavor); + } + + /** {@inheritDoc} */ + public int getUsagePenalty(String mime, ImageFlavor flavor) { + return 0; + } + + /** {@inheritDoc} */ + public boolean isAvailable() { + return BatikUtil.isBatikAvailable(); + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java new file mode 100644 index 000000000..64aff962b --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderSVG.java @@ -0,0 +1,78 @@ +/* + * 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.image.loader.batik; + +import java.io.IOException; +import java.util.Map; + +import org.apache.batik.dom.svg.SVGDOMImplementation; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoader; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.util.MimeConstants; + +/** + * ImageLoader for SVG (using Apache Batik). + */ +public class ImageLoaderSVG extends AbstractImageLoader { + + private ImageFlavor targetFlavor; + + /** + * Main constructor. + * @param targetFlavor the target flavor + */ + public ImageLoaderSVG(ImageFlavor targetFlavor) { + if (!(ImageFlavor.XML_DOM.equals(targetFlavor))) { + throw new IllegalArgumentException("Unsupported target ImageFlavor: " + targetFlavor); + } + this.targetFlavor = targetFlavor; + } + + /** {@inheritDoc} */ + public ImageFlavor getTargetFlavor() { + return this.targetFlavor; + } + + /** {@inheritDoc} */ + public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session) + throws ImageException, IOException { + if (!MimeConstants.MIME_SVG.equals(info.getMimeType())) { + throw new IllegalArgumentException("ImageInfo must be from an SVG image"); + } + Image img = info.getOriginalImage(); + if (!(img instanceof ImageXMLDOM)) { + throw new IllegalArgumentException( + "ImageInfo was expected to contain the SVG document as DOM"); + } + ImageXMLDOM svgImage = (ImageXMLDOM)img; + if (!SVGDOMImplementation.SVG_NAMESPACE_URI.equals(svgImage.getRootNamespace())) { + throw new IllegalArgumentException( + "The Image is not in the SVG namespace: " + svgImage.getRootNamespace()); + } + return svgImage; + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java new file mode 100644 index 000000000..e7f3e0f0a --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageLoaderWMF.java @@ -0,0 +1,70 @@ +/* + * 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.image.loader.batik; + +import java.io.IOException; +import java.util.Map; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageException; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSessionContext; +import org.apache.xmlgraphics.image.loader.impl.AbstractImageLoader; + +/** + * ImageLoader for WMF (Windows Metafile). Depends on the WMF preloader based on Apache Batik. + */ +public class ImageLoaderWMF extends AbstractImageLoader { + + private ImageFlavor targetFlavor; + + /** + * Main constructor. + * @param targetFlavor the target flavor + */ + public ImageLoaderWMF(ImageFlavor targetFlavor) { + if (!(ImageWMF.WMF_IMAGE.equals(targetFlavor))) { + throw new IllegalArgumentException("Unsupported target ImageFlavor: " + targetFlavor); + } + this.targetFlavor = targetFlavor; + } + + /** {@inheritDoc} */ + public ImageFlavor getTargetFlavor() { + return this.targetFlavor; + } + + /** {@inheritDoc} */ + public Image loadImage(ImageInfo info, Map hints, ImageSessionContext session) + throws ImageException, IOException { + if (!ImageWMF.MIME_WMF.equals(info.getMimeType())) { + throw new IllegalArgumentException("ImageInfo must be from a WMF image"); + } + Image img = info.getOriginalImage(); + if (!(img instanceof ImageWMF)) { + throw new IllegalArgumentException( + "ImageInfo was expected to contain the Windows Metafile (WMF)"); + } + ImageWMF wmfImage = (ImageWMF)img; + return wmfImage; + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/ImageWMF.java b/src/java/org/apache/fop/image/loader/batik/ImageWMF.java new file mode 100644 index 000000000..f785d27cc --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/ImageWMF.java @@ -0,0 +1,69 @@ +/* + * 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.image.loader.batik; + +import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore; + +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.impl.AbstractImage; + +/** + * This class is an implementation of the Image interface exposing a RenderedImage. + */ +public class ImageWMF extends AbstractImage { + + /** MIME type for WMF */ + public static final String MIME_WMF = "image/x-wmf"; + + /** ImageFlavor for Batik's WMFRecordStore */ + public static final ImageFlavor WMF_IMAGE = new ImageFlavor("WMFRecordStore"); + + private WMFRecordStore store; + + /** + * Main constructor. + * @param info the image info object + * @param store the WMF record store containing the loaded WMF file + */ + public ImageWMF(ImageInfo info, WMFRecordStore store) { + super(info); + this.store = store; + } + + /** {@inheritDoc} */ + public ImageFlavor getFlavor() { + return WMF_IMAGE; + } + + /** {@inheritDoc} */ + public boolean isCacheable() { + return true; + } + + /** + * Returns the contained WMF record store. + * @return the WMFRecordStore + */ + public WMFRecordStore getRecordStore() { + return this.store; + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java new file mode 100644 index 000000000..e83a302da --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/PreloaderSVG.java @@ -0,0 +1,182 @@ +/* + * 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.image.loader.batik; + +import java.awt.geom.AffineTransform; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.SAXParserFactory; +import javax.xml.transform.Source; + +import org.w3c.dom.Element; +import org.w3c.dom.svg.SVGDocument; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.UnitProcessor; +import org.apache.batik.dom.svg.SAXSVGDocumentFactory; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.dom.svg.SVGOMDocument; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.ImageContext; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader; +import org.apache.xmlgraphics.image.loader.impl.ImageXMLDOM; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; +import org.apache.xmlgraphics.util.MimeConstants; + +import org.apache.fop.svg.SVGUserAgent; +import org.apache.fop.util.UnclosableInputStream; + +/** + * Image preloader for SVG images. + */ +public class PreloaderSVG extends AbstractImagePreloader { + + /** Logger instance */ + private static Log log = LogFactory.getLog(PreloaderSVG.class); + + private boolean batikAvailable = true; + + /** {@inheritDoc} */ + public ImageInfo preloadImage(String uri, Source src, ImageContext context) + throws IOException { + if (!ImageUtil.hasInputStream(src)) { + //TODO Remove this and support DOMSource and possibly SAXSource + return null; + } + ImageInfo info = null; + if (batikAvailable) { + try { + Loader loader = new Loader(); + info = loader.getImage(uri, src, context); + } catch (NoClassDefFoundError e) { + batikAvailable = false; + log.warn("Batik not in class path", e); + return null; + } + } + if (info != null) { + ImageUtil.closeQuietly(src); //Image is fully read + } + return info; + } + + /** + * Returns the fully qualified classname of an XML parser for + * Batik classes that apparently need it (error messages, perhaps) + * @return an XML parser classname + */ + public static String getParserName() { + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + return factory.newSAXParser().getXMLReader().getClass().getName(); + } catch (Exception e) { + return null; + } + } + + /** + * This method is put in another class so that the class loader does not + * attempt to load Batik related classes when constructing the SVGPreloader + * class. + */ + class Loader { + private ImageInfo getImage(String uri, Source src, + ImageContext context) { + // parse document and get the size attributes of the svg element + + InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); + try { + int length = in.available(); + in.mark(length + 1); + SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( + getParserName()); + SVGDocument doc = (SVGDocument) factory.createSVGDocument(src.getSystemId(), in); + + Element e = doc.getRootElement(); + float pxUnitToMillimeter = 25.4f / context.getSourceResolution(); + SVGUserAgent userAg = new SVGUserAgent(pxUnitToMillimeter, + new AffineTransform()); + BridgeContext ctx = new BridgeContext(userAg); + UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, e); + + String s; + // 'width' attribute - default is 100% + s = e.getAttributeNS(null, SVGOMDocument.SVG_WIDTH_ATTRIBUTE); + if (s.length() == 0) { + s = SVGOMDocument.SVG_SVG_WIDTH_DEFAULT_VALUE; + } + float width = UnitProcessor.svgHorizontalLengthToUserSpace( + s, SVGOMDocument.SVG_WIDTH_ATTRIBUTE, uctx); + + // 'height' attribute - default is 100% + s = e.getAttributeNS(null, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE); + if (s.length() == 0) { + s = SVGOMDocument.SVG_SVG_HEIGHT_DEFAULT_VALUE; + } + float height = UnitProcessor.svgVerticalLengthToUserSpace( + s, SVGOMDocument.SVG_HEIGHT_ATTRIBUTE, uctx); + + ImageInfo info = new ImageInfo(uri, MimeConstants.MIME_SVG); + ImageSize size = new ImageSize(); + size.setSizeInMillipoints(Math.round(width * 1000), Math.round(height * 1000)); + //Set the resolution to that of the FOUserAgent + size.setResolution(context.getSourceResolution()); + size.calcPixelsFromSize(); + info.setSize(size); + + //The whole image had to be loaded for this, so keep it + ImageXMLDOM xmlImage = new ImageXMLDOM(info, + doc, SVGDOMImplementation.SVG_NAMESPACE_URI); + info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, xmlImage); + + return info; + } catch (NoClassDefFoundError ncdfe) { + try { + in.reset(); + } catch (IOException ioe) { + // we're more interested in the original exception + } + batikAvailable = false; + log.warn("Batik not in class path", ncdfe); + return null; + } catch (IOException e) { + // If the svg is invalid then it throws an IOException + // so there is no way of knowing if it is an svg document + + log.debug("Error while trying to load stream as an SVG file: " + + e.getMessage()); + // assuming any exception means this document is not svg + // or could not be loaded for some reason + try { + in.reset(); + } catch (IOException ioe) { + // we're more interested in the original exception + } + return null; + } + } + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java new file mode 100644 index 000000000..abb740411 --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/PreloaderWMF.java @@ -0,0 +1,142 @@ +/* + * 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.image.loader.batik; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.transform.Source; + +import org.apache.batik.transcoder.wmf.WMFConstants; +import org.apache.batik.transcoder.wmf.tosvg.WMFRecordStore; +import org.apache.commons.io.EndianUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.xmlgraphics.image.loader.ImageContext; +import org.apache.xmlgraphics.image.loader.ImageInfo; +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.AbstractImagePreloader; +import org.apache.xmlgraphics.image.loader.util.ImageUtil; + +import org.apache.fop.util.UnclosableInputStream; + +/** + * Image preloader for WMF images (Windows Metafile). + */ +public class PreloaderWMF extends AbstractImagePreloader { + + /** Logger instance */ + private static Log log = LogFactory.getLog(PreloaderWMF.class); + + private boolean batikAvailable = true; + + /** {@inheritDoc} */ + public ImageInfo preloadImage(String uri, Source src, ImageContext context) + throws IOException { + if (!ImageUtil.hasInputStream(src)) { + return null; + } + ImageInfo info = null; + if (batikAvailable) { + try { + Loader loader = new Loader(); + info = loader.getImage(uri, src, context); + } catch (NoClassDefFoundError e) { + batikAvailable = false; + log.warn("Batik not in class path", e); + return null; + } + } + if (info != null) { + ImageUtil.closeQuietly(src); //Image is fully read + } + return info; + } + + /** + * This method is put in another class so that the class loader does not + * attempt to load Batik related classes when constructing the WMFPreloader + * class. + */ + class Loader { + private ImageInfo getImage(String uri, Source src, + ImageContext context) { + // parse document and get the size attributes of the svg element + + InputStream in = new UnclosableInputStream(ImageUtil.needInputStream(src)); + try { + in.mark(4 + 1); + + DataInputStream din = new DataInputStream(in); + int magic = EndianUtils.swapInteger(din.readInt()); + din.reset(); + if (magic != WMFConstants.META_ALDUS_APM) { + return null; //Not a WMF file + } + + WMFRecordStore wmfStore = new WMFRecordStore(); + wmfStore.read(din); + IOUtils.closeQuietly(din); + + int width = wmfStore.getWidthUnits(); + int height = wmfStore.getHeightUnits(); + int dpi = wmfStore.getMetaFileUnitsPerInch(); + + ImageInfo info = new ImageInfo(uri, "image/x-wmf"); + ImageSize size = new ImageSize(); + size.setSizeInPixels(width, height); + size.setResolution(dpi); + size.calcSizeFromPixels(); + info.setSize(size); + ImageWMF img = new ImageWMF(info, wmfStore); + info.getCustomObjects().put(ImageInfo.ORIGINAL_IMAGE, img); + + return info; + } catch (NoClassDefFoundError ncdfe) { + try { + in.reset(); + } catch (IOException ioe) { + // we're more interested in the original exception + } + batikAvailable = false; + log.warn("Batik not in class path", ncdfe); + return null; + } catch (IOException e) { + // If the svg is invalid then it throws an IOException + // so there is no way of knowing if it is an svg document + + log.debug("Error while trying to load stream as an WMF file: " + + e.getMessage()); + // assuming any exception means this document is not svg + // or could not be loaded for some reason + try { + in.reset(); + } catch (IOException ioe) { + // we're more interested in the original exception + } + return null; + } + } + } + +} diff --git a/src/java/org/apache/fop/image/loader/batik/package.html b/src/java/org/apache/fop/image/loader/batik/package.html new file mode 100644 index 000000000..f664913d7 --- /dev/null +++ b/src/java/org/apache/fop/image/loader/batik/package.html @@ -0,0 +1,26 @@ +<!-- + 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$ --> +<HTML> +<TITLE>org.apache.fop.image2.impl.batik Package</TITLE> +<BODY> +<P> + Contains implementations of image loaders and converters which are dependent + on Apache Batik (SVG and WMF). +</P> +</BODY> +</HTML>
\ No newline at end of file |