From 244bced08cc4a6d21e844c143a6fd690d833d5e7 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 12 Mar 2003 15:33:03 +0000 Subject: [PATCH] Added the basic infrastructure for the PostScript Transcoder. Works, but output doesn't look good, yet. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196087 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/render/ps/PSDocumentGraphics2D.java | 288 ++++++++++++ .../apache/fop/render/ps/PSGraphics2D.java | 21 +- .../org/apache/fop/render/ps/PSRenderer.java | 33 +- .../apache/fop/render/ps/PSTranscoder.java | 425 ++++++++++++++++++ 4 files changed, 750 insertions(+), 17 deletions(-) create mode 100644 src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java create mode 100644 src/java/org/apache/fop/render/ps/PSTranscoder.java diff --git a/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java new file mode 100644 index 000000000..f462b8873 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java @@ -0,0 +1,288 @@ +/* + * $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber . For more information on the Apache + * Software Foundation, please see . + */ +package org.apache.fop.render.ps; + +//Java +import java.awt.Graphics; +import java.awt.Font; +import java.awt.Color; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.io.OutputStream; +import java.io.IOException; + +//FOP +import org.apache.fop.render.pdf.FontSetup; +import org.apache.fop.layout.FontInfo; + +/** + * This class is a wrapper for the PSGraphics2D that + * is used to create a full document around the PostScript rendering from + * PSGraphics2D. + * + * @author Keiron Liddle + * @author Jeremias Maerki + * @version $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $ + * @see org.apache.fop.svg.PSGraphics2D + */ +public class PSDocumentGraphics2D extends PSGraphics2D { + + private int width; + private int height; + + /** + * Create a new PSDocumentGraphics2D. + * This is used to create a new PostScript document, the height, + * width and output stream can be setup later. + * For use by the transcoder which needs font information + * for the bridge before the document size is known. + * The resulting document is written to the stream after rendering. + * + * @param textAsShapes set this to true so that text will be rendered + * using curves and not the font. + */ + PSDocumentGraphics2D(boolean textAsShapes) { + super(textAsShapes); + + if (!textAsShapes) { + fontInfo = new FontInfo(); + FontSetup.setup(fontInfo, null); + //FontState fontState = new FontState("Helvetica", "normal", + // FontInfo.NORMAL, 12, 0); + } + + currentFontName = ""; + currentFontSize = 0; + } + + /** + * Setup the document. + * @param stream the output stream to write the document + * @param width the width of the page + * @param height the height of the page + * @throws IOException an io exception if there is a problem + * writing to the output stream + */ + public void setupDocument(OutputStream stream, int width, int height) throws IOException { + this.width = width; + this.height = height; + + final Integer zero = new Integer(0); + final Long pagewidth = new Long(this.width); + final Long pageheight = new Long(this.height); + + //Setup for PostScript generation + setPSGenerator(new PSGenerator(stream)); + + //PostScript Header + gen.writeln(DSCConstants.PS_ADOBE_30); + gen.writeDSCComment(DSCConstants.CREATOR, + new String[] {"FOP PostScript Transcoder for SVG"}); + gen.writeDSCComment(DSCConstants.CREATION_DATE, + new Object[] {new java.util.Date()}); + gen.writeDSCComment(DSCConstants.PAGES, new Object[] {new Integer(1)}); + gen.writeDSCComment(DSCConstants.BBOX, new Object[] + {zero, zero, pagewidth, pageheight}); + gen.writeDSCComment(DSCConstants.END_COMMENTS); + + //Defaults + gen.writeDSCComment(DSCConstants.BEGIN_DEFAULTS); + gen.writeDSCComment(DSCConstants.END_DEFAULTS); + + //Prolog + gen.writeDSCComment(DSCConstants.BEGIN_PROLOG); + gen.writeDSCComment(DSCConstants.END_PROLOG); + + //Setup + gen.writeDSCComment(DSCConstants.BEGIN_SETUP); + PSProcSets.writeFOPStdProcSet(gen); + PSProcSets.writeFOPEPSProcSet(gen); + PSRenderer.writeFontDict(gen, fontInfo); + gen.writeDSCComment(DSCConstants.END_SETUP); + + //Start page + Integer pageNumber = new Integer(1); + gen.writeDSCComment(DSCConstants.PAGE, new Object[] + {pageNumber.toString(), pageNumber}); + gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] + {zero, zero, pagewidth, pageheight}); + gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP); + gen.writeln("FOPFonts begin"); + gen.writeln("0.001 0.001 scale"); + gen.concatMatrix(1, 0, 0, -1, 0, pageheight.doubleValue() * 1000); + gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); + + } + + /** + * Create a new PSDocumentGraphics2D. + * This is used to create a new PostScript document of the given height + * and width. + * The resulting document is written to the stream after rendering. + * + * @param textAsShapes set this to true so that text will be rendered + * using curves and not the font. + * @param stream the stream that the final document should be written to. + * @param width the width of the document + * @param height the height of the document + * @throws IOException an io exception if there is a problem + * writing to the output stream + */ + public PSDocumentGraphics2D(boolean textAsShapes, OutputStream stream, + int width, int height) throws IOException { + this(textAsShapes); + setupDocument(stream, width, height); + } + + /** + * Get the font info for this PostScript document. + * @return the font information + */ + public FontInfo getFontInfo() { + return fontInfo; + } + + /** + * Set the dimensions of the SVG document that will be drawn. + * This is useful if the dimensions of the SVG document are different + * from the PostScript document that is to be created. + * The result is scaled so that the SVG fits correctly inside the + * PostScript document. + * @param w the width of the page + * @param h the height of the page + * @throws IOException in case of an I/O problem + */ + public void setSVGDimension(float w, float h) throws IOException { + gen.concatMatrix(width / w, 0, 0, height / h, 0, 0); + } + + /** + * Set the background of the PostScript document. + * This is used to set the background for the PostScript document + * Rather than leaving it as the default white. + * @param col the background colour to fill + */ + public void setBackgroundColor(Color col) { + /**@todo Implement this */ + /* + Color c = col; + PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); + currentStream.write("q\n"); + currentStream.write(currentColour.getColorSpaceOut(true)); + + currentStream.write("0 0 " + width + " " + height + " re\n"); + + currentStream.write("f\n"); + currentStream.write("Q\n"); + */ + } + + /** + * The rendering process has finished. + * This should be called after the rendering has completed as there is + * no other indication it is complete. + * This will then write the results to the output stream. + * @throws IOException an io exception if there is a problem + * writing to the output stream + */ + public void finish() throws IOException { + //Finish page + gen.writeln("showpage"); + gen.writeDSCComment(DSCConstants.PAGE_TRAILER); + gen.writeDSCComment(DSCConstants.END_PAGE); + + //Finish document + gen.writeDSCComment(DSCConstants.TRAILER); + gen.writeDSCComment(DSCConstants.EOF); + gen.flush(); + } + + /** + * This constructor supports the create method + * @param g the PostScript document graphics to make a copy of + */ + public PSDocumentGraphics2D(PSDocumentGraphics2D g) { + super(g); + } + + /** + * Creates a new Graphics object that is + * a copy of this Graphics object. + * @return a new graphics context that is a copy of + * this graphics context. + */ + public Graphics create() { + return new PSDocumentGraphics2D(this); + } + + /** + * Draw a string to the PostScript document. + * This either draws the string directly or if drawing text as + * shapes it converts the string into shapes and draws that. + * @param s the string to draw + * @param x the x position + * @param y the y position + */ + public void drawString(String s, float x, float y) { + if (super.textAsShapes) { + Font font = super.getFont(); + FontRenderContext frc = super.getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(frc, s); + Shape glyphOutline = gv.getOutline(x, y); + super.fill(glyphOutline); + } else { + super.drawString(s, x, y); + } + } + +} + diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java index 9a2908422..e5d26327a 100644 --- a/src/java/org/apache/fop/render/ps/PSGraphics2D.java +++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java @@ -146,6 +146,15 @@ public class PSGraphics2D extends AbstractGraphics2D { /** FontInfo containing all available fonts */ protected FontInfo fontInfo; + /** + * Create a new Graphics2D that generates PostScript code. + * @param textAsShapes True if text should be rendered as graphics + * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean) + */ + public PSGraphics2D(boolean textAsShapes) { + super(textAsShapes); + } + /** * Create a new Graphics2D that generates PostScript code. * @param textAsShapes True if text should be rendered as graphics @@ -153,8 +162,8 @@ public class PSGraphics2D extends AbstractGraphics2D { * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean) */ public PSGraphics2D(boolean textAsShapes, PSGenerator gen) { - super(textAsShapes); - this.gen = gen; + this(textAsShapes); + setPSGenerator(gen); } /** @@ -165,6 +174,14 @@ public class PSGraphics2D extends AbstractGraphics2D { super(g); } + /** + * Sets the PostScript generator + * @param gen the PostScript generator + */ + public void setPSGenerator(PSGenerator gen) { + this.gen = gen; + } + /** * Sets the GraphicContext * @param c GraphicContext to use diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java index 9e22812ed..5071d86e8 100644 --- a/src/java/org/apache/fop/render/ps/PSRenderer.java +++ b/src/java/org/apache/fop/render/ps/PSRenderer.java @@ -182,12 +182,15 @@ public class PSRenderer extends AbstractRenderer { /** * Generates the PostScript code for the font dictionary. + * @param gen PostScript generator to use for output * @param fontInfo available fonts + * @throws IOException in case of an I/O problem */ - protected void writeFontDict(FontInfo fontInfo) { - writeln("%%BeginResource: procset FOPFonts"); - writeln("%%Title: Font setup (shortcuts) for this file"); - writeln("/FOPFonts 100 dict dup begin"); + public static void writeFontDict(PSGenerator gen, FontInfo fontInfo) + throws IOException { + gen.writeln("%%BeginResource: procset FOPFonts"); + gen.writeln("%%Title: Font setup (shortcuts) for this file"); + gen.writeln("/FOPFonts 100 dict dup begin"); // write("/gfF1{/Helvetica findfont} bd"); // write("/gfF3{/Helvetica-Bold findfont} bd"); @@ -196,21 +199,21 @@ public class PSRenderer extends AbstractRenderer { while (enum.hasNext()) { String key = (String)enum.next(); Font fm = (Font)fonts.get(key); - writeln("/" + key + " /" + fm.getFontName() + " def"); + gen.writeln("/" + key + " /" + fm.getFontName() + " def"); } - writeln("end def"); - writeln("%%EndResource"); + gen.writeln("end def"); + gen.writeln("%%EndResource"); enum = fonts.keySet().iterator(); while (enum.hasNext()) { String key = (String)enum.next(); Font fm = (Font)fonts.get(key); - writeln("/" + fm.getFontName() + " findfont"); - writeln("dup length dict begin"); - writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); - writeln(" /Encoding ISOLatin1Encoding def"); - writeln(" currentdict"); - writeln("end"); - writeln("/" + fm.getFontName() + " exch definefont pop"); + gen.writeln("/" + fm.getFontName() + " findfont"); + gen.writeln("dup length dict begin"); + gen.writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); + gen.writeln(" /Encoding ISOLatin1Encoding def"); + gen.writeln(" currentdict"); + gen.writeln("end"); + gen.writeln("/" + fm.getFontName() + " exch definefont pop"); } } @@ -396,7 +399,7 @@ public class PSRenderer extends AbstractRenderer { gen.writeDSCComment(DSCConstants.BEGIN_SETUP); PSProcSets.writeFOPStdProcSet(gen); PSProcSets.writeFOPEPSProcSet(gen); - writeFontDict(fontInfo); + writeFontDict(gen, fontInfo); gen.writeDSCComment(DSCConstants.END_SETUP); } diff --git a/src/java/org/apache/fop/render/ps/PSTranscoder.java b/src/java/org/apache/fop/render/ps/PSTranscoder.java new file mode 100644 index 000000000..2f741c9b4 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSTranscoder.java @@ -0,0 +1,425 @@ +/* + * $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $ + * ============================================================================ + * The Apache Software License, Version 1.1 + * ============================================================================ + * + * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The end-user documentation included with the redistribution, if any, must + * include the following acknowledgment: "This product includes software + * developed by the Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, if + * and wherever such third-party acknowledgments normally appear. + * + * 4. The names "FOP" and "Apache Software Foundation" must not be used to + * endorse or promote products derived from this software without prior + * written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", nor may + * "Apache" appear in their name, without prior written permission of the + * Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- + * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ============================================================================ + * + * This software consists of voluntary contributions made by many individuals + * on behalf of the Apache Software Foundation and was originally created by + * James Tauber . For more information on the Apache + * Software Foundation, please see . + */ +package org.apache.fop.render.ps; + +import java.awt.Dimension; + +import java.awt.geom.AffineTransform; +import java.awt.geom.Dimension2D; +import java.awt.geom.Rectangle2D; + +import java.awt.Color; + +import java.net.MalformedURLException; +import java.net.URL; + +import java.io.IOException; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.BridgeException; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.bridge.SVGTextElementBridge; +import org.apache.batik.bridge.UserAgent; +import org.apache.batik.bridge.UserAgentAdapter; +import org.apache.batik.bridge.ViewBox; + +import org.apache.batik.dom.svg.SAXSVGDocumentFactory; +import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.dom.svg.SVGOMDocument; +import org.apache.batik.dom.util.DocumentFactory; + +import org.apache.batik.gvt.GraphicsNode; + +import org.apache.batik.transcoder.TranscoderException; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.XMLAbstractTranscoder; +import org.apache.batik.transcoder.image.resources.Messages; + +import org.apache.batik.transcoder.image.ImageTranscoder; + +import org.apache.batik.util.SVGConstants; +import org.apache.batik.util.XMLResourceDescriptor; + +import org.apache.batik.gvt.TextPainter; +import org.apache.batik.gvt.renderer.StrokingTextPainter; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGSVGElement; + +/** + * This class enables to transcode an input to a PostScript document. + * + *

Two transcoding hints (KEY_WIDTH and + * KEY_HEIGHT) can be used to respectively specify the image + * width and the image height. If only one of these keys is specified, + * the transcoder preserves the aspect ratio of the original image. + * + *

The KEY_BACKGROUND_COLOR defines the background color + * to use for opaque image formats, or the background color that may + * be used for image formats that support alpha channel. + * + *

The KEY_AOI represents the area of interest to paint + * in device space. + * + *

Three additional transcoding hints that act on the SVG + * processor can be specified: + * + *

KEY_LANGUAGE to set the default language to use (may be + * used by a <switch> SVG element for example), + * KEY_USER_STYLESHEET_URI to fix the URI of a user + * stylesheet, and KEY_PIXEL_TO_MM to specify the pixel to + * millimeter conversion factor. + * + * @author Keiron Liddle + * @author Jeremias Maerki + * @version $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $ + */ +public class PSTranscoder extends XMLAbstractTranscoder { + + /** + * The user agent dedicated to an ImageTranscoder. + */ + protected UserAgent userAgent = new ImageTranscoderUserAgent(); + + /** + * Constructs a new ImageTranscoder. + */ + public PSTranscoder() { + hints.put(KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, + SVGConstants.SVG_NAMESPACE_URI); + hints.put(KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG); + hints.put(KEY_DOM_IMPLEMENTATION, + SVGDOMImplementation.getDOMImplementation()); + } + + /** + * Transcodes the specified Document as an image in the specified output. + * + * @param document the document to transcode + * @param uri the uri of the document or null if any + * @param output the ouput where to transcode + * @exception TranscoderException if an error occured while transcoding + */ + protected void transcode(Document document, String uri, + TranscoderOutput output) throws TranscoderException { + + if (!(document instanceof SVGOMDocument)) { + throw new TranscoderException(Messages.formatMessage("notsvg", + null)); + } + SVGDocument svgDoc = (SVGDocument)document; + SVGSVGElement root = svgDoc.getRootElement(); + // initialize the SVG document with the appropriate context + String parserClassname = (String)hints.get(KEY_XML_PARSER_CLASSNAME); + + PSDocumentGraphics2D graphics = new PSDocumentGraphics2D(false); + + // build the GVT tree + GVTBuilder builder = new GVTBuilder(); + BridgeContext ctx = new BridgeContext(userAgent); + TextPainter textPainter = null; + textPainter = new StrokingTextPainter(); + ctx.setTextPainter(textPainter); + + SVGTextElementBridge textElementBridge = + new PSTextElementBridge(graphics.getFontInfo()); + ctx.putBridge(textElementBridge); + + //PDFAElementBridge pdfAElementBridge = new PDFAElementBridge(); + //AffineTransform currentTransform = new AffineTransform(1, 0, 0, 1, 0, 0); + //pdfAElementBridge.setCurrentTransform(currentTransform); + //ctx.putBridge(pdfAElementBridge); + + //ctx.putBridge(new PSImageElementBridge()); + GraphicsNode gvtRoot; + try { + gvtRoot = builder.build(ctx, svgDoc); + } catch (BridgeException ex) { + throw new TranscoderException(ex); + } + // get the 'width' and 'height' attributes of the SVG document + float docWidth = (float)ctx.getDocumentSize().getWidth(); + float docHeight = (float)ctx.getDocumentSize().getHeight(); + ctx = null; + builder = null; + + // compute the image's width and height according the hints + float imgWidth = -1; + if (hints.containsKey(ImageTranscoder.KEY_WIDTH)) { + imgWidth = + ((Float)hints.get(ImageTranscoder.KEY_WIDTH)).floatValue(); + } + float imgHeight = -1; + if (hints.containsKey(ImageTranscoder.KEY_HEIGHT)) { + imgHeight = + ((Float)hints.get(ImageTranscoder.KEY_HEIGHT)).floatValue(); + } + float width, height; + if (imgWidth > 0 && imgHeight > 0) { + width = imgWidth; + height = imgHeight; + } else if (imgHeight > 0) { + width = (docWidth * imgHeight) / docHeight; + height = imgHeight; + } else if (imgWidth > 0) { + width = imgWidth; + height = (docHeight * imgWidth) / docWidth; + } else { + width = docWidth; + height = docHeight; + } + // compute the preserveAspectRatio matrix + AffineTransform px; + String ref = null; + try { + ref = new URL(uri).getRef(); + } catch (MalformedURLException ex) { + // nothing to do, catched previously + } + + try { + px = ViewBox.getViewTransform(ref, root, width, height); + } catch (BridgeException ex) { + throw new TranscoderException(ex); + } + + if (px.isIdentity() && (width != docWidth || height != docHeight)) { + // The document has no viewBox, we need to resize it by hand. + // we want to keep the document size ratio + float d = Math.max(docWidth, docHeight); + float dd = Math.max(width, height); + float scale = dd / d; + px = AffineTransform.getScaleInstance(scale, scale); + } + // take the AOI into account if any + if (hints.containsKey(ImageTranscoder.KEY_AOI)) { + Rectangle2D aoi = (Rectangle2D)hints.get(ImageTranscoder.KEY_AOI); + // transform the AOI into the image's coordinate system + aoi = px.createTransformedShape(aoi).getBounds2D(); + AffineTransform mx = new AffineTransform(); + double sx = width / aoi.getWidth(); + double sy = height / aoi.getHeight(); + mx.scale(sx, sy); + double tx = -aoi.getX(); + double ty = -aoi.getY(); + mx.translate(tx, ty); + // take the AOI transformation matrix into account + // we apply first the preserveAspectRatio matrix + px.preConcatenate(mx); + } + // prepare the image to be painted + int w = (int)width; + int h = (int)height; + + try { + graphics.setupDocument(output.getOutputStream(), w, h); + graphics.setSVGDimension(docWidth, docHeight); + + if (hints.containsKey(ImageTranscoder.KEY_BACKGROUND_COLOR)) { + graphics.setBackgroundColor((Color)hints.get(ImageTranscoder.KEY_BACKGROUND_COLOR)); + } + graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); + graphics.setTransform(px); + + gvtRoot.paint(graphics); + + graphics.finish(); + } catch (IOException ex) { + throw new TranscoderException(ex); + } + } + + /** + * Creates a DocumentFactory that is used to create an SVG DOM + * tree. The specified DOM Implementation is ignored and the Batik + * SVG DOM Implementation is automatically used. + * + * @param domImpl the DOM Implementation (not used) + * @param parserClassname the XML parser classname + * @return the document factory + */ + protected DocumentFactory createDocumentFactory(DOMImplementation domImpl, + String parserClassname) { + return new SAXSVGDocumentFactory(parserClassname); + } + + // -------------------------------------------------------------------- + // UserAgent implementation + // -------------------------------------------------------------------- + + /** + * A user agent implementation for ImageTranscoder. + */ + protected class ImageTranscoderUserAgent extends UserAgentAdapter { + + /** + * Returns the default size of this user agent (400x400). + * @return the default viewport size + */ + public Dimension2D getViewportSize() { + return new Dimension(400, 400); + } + + /** + * Displays the specified error message using the ErrorHandler. + * @param message the message to display + */ + public void displayError(String message) { + try { + getErrorHandler().error(new TranscoderException(message)); + } catch (TranscoderException ex) { + throw new RuntimeException(); + } + } + + /** + * Displays the specified error using the ErrorHandler. + * @param e the exception to display + */ + public void displayError(Exception e) { + try { + getErrorHandler().error(new TranscoderException(e)); + } catch (TranscoderException ex) { + throw new RuntimeException(); + } + } + + /** + * Displays the specified message using the ErrorHandler. + * @param message the message to display + */ + public void displayMessage(String message) { + try { + getErrorHandler().warning(new TranscoderException(message)); + } catch (TranscoderException ex) { + throw new RuntimeException(); + } + } + + /** + * Returns the pixel to millimeter conversion factor specified in the + * TranscodingHints or 0.3528 if any. + * @return the pixel unit to millimeter factor + */ + public float getPixelUnitToMillimeter() { + Object key = ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER; + if (getTranscodingHints().containsKey(key)) { + return ((Float)getTranscodingHints().get(key)).floatValue(); + } else { + // return 0.3528f; // 72 dpi + return 0.26458333333333333333333333333333f; // 96dpi + } + } + + /** + * Returns the user language specified in the + * TranscodingHints or "en" (english) if any. + * @return the languages for the transcoder + */ + public String getLanguages() { + Object key = ImageTranscoder.KEY_LANGUAGE; + if (getTranscodingHints().containsKey(key)) { + return (String)getTranscodingHints().get(key); + } else { + return "en"; + } + } + + /** + * Get the media for this transcoder. Which is always print. + * @return PostScript media is "print" + */ + public String getMedia() { + return "print"; + } + + /** + * Returns the user stylesheet specified in the + * TranscodingHints or null if any. + * @return the user style sheet URI specified in the hints + */ + public String getUserStyleSheetURI() { + return (String)getTranscodingHints() + .get(ImageTranscoder.KEY_USER_STYLESHEET_URI); + } + + /** + * Returns the XML parser to use from the TranscodingHints. + * @return the XML parser class name + */ + public String getXMLParserClassName() { + Object key = KEY_XML_PARSER_CLASSNAME; + if (getTranscodingHints().containsKey(key)) { + return (String)getTranscodingHints().get(key); + } else { + return XMLResourceDescriptor.getXMLParserClassName(); + } + } + + /** + * Check if the XML parser is validating. + * @return true if the XML parser is validating + */ + public boolean isXMLParserValidating() { + return false; + } + + /** + * Unsupported operation. + * @return null since this is unsupported + */ + public AffineTransform getTransform() { + return null; + } + } +} -- 2.39.5