aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java293
-rw-r--r--src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java195
-rw-r--r--src/java/org/apache/fop/render/ps/DSCConstants.java3
-rw-r--r--src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java124
-rw-r--r--src/java/org/apache/fop/render/ps/EPSTranscoder.java94
-rw-r--r--src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java199
-rw-r--r--src/java/org/apache/fop/render/ps/PSGenerator.java83
-rw-r--r--src/java/org/apache/fop/render/ps/PSGraphics2D.java684
-rw-r--r--src/java/org/apache/fop/render/ps/PSProcSets.java8
-rw-r--r--src/java/org/apache/fop/render/ps/PSRenderer.java79
-rw-r--r--src/java/org/apache/fop/render/ps/PSTextElementBridge.java39
-rw-r--r--src/java/org/apache/fop/render/ps/PSTextPainter.java413
-rw-r--r--src/java/org/apache/fop/render/ps/PSTranscoder.java102
-rw-r--r--src/java/org/apache/fop/render/ps/PSXMLHandler.java16
14 files changed, 1518 insertions, 814 deletions
diff --git a/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java
new file mode 100644
index 000000000..f28061249
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/AbstractPSDocumentGraphics2D.java
@@ -0,0 +1,293 @@
+/*
+ * $Id$
+ * ============================================================================
+ * 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 <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+//Java
+import java.awt.Graphics;
+import java.awt.Color;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.io.OutputStream;
+import java.io.IOException;
+
+//FOP
+import org.apache.fop.apps.Document;
+import org.apache.fop.fonts.Font;
+import org.apache.fop.render.pdf.FontSetup;
+
+/**
+ * This class is a wrapper for the <tt>PSGraphics2D</tt> that
+ * is used to create a full document around the PostScript rendering from
+ * <tt>PSGraphics2D</tt>.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id$
+ * @see org.apache.fop.render.ps.PSGraphics2D
+ */
+public abstract class AbstractPSDocumentGraphics2D extends PSGraphics2D {
+
+ protected static final Integer ZERO = new Integer(0);
+
+ protected int width;
+ protected int height;
+
+ protected int pagecount;
+ protected boolean pagePending;
+
+ protected Shape initialClip;
+ protected AffineTransform initialTransform;
+
+
+ /**
+ * Create a new AbstractPSDocumentGraphics2D.
+ * 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.
+ */
+ AbstractPSDocumentGraphics2D(boolean textAsShapes) {
+ super(textAsShapes);
+
+ if (!textAsShapes) {
+ this.document = new Document(null);
+ FontSetup.setup(this.document, null);
+ }
+ }
+
+ /**
+ * 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;
+ this.pagecount = 0;
+ this.pagePending = false;
+
+ //Setup for PostScript generation
+ setPSGenerator(new PSGenerator(stream));
+
+ writeFileHeader();
+ }
+
+ protected abstract void writeFileHeader() throws IOException;
+
+ /**
+ * Create a new AbstractPSDocumentGraphics2D.
+ * 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 AbstractPSDocumentGraphics2D(boolean textAsShapes, OutputStream stream,
+ int width, int height) throws IOException {
+ this(textAsShapes);
+ setupDocument(stream, width, height);
+ }
+
+ /**
+ * Get the context document.
+ * @return the context document
+ */
+ public Document getDocument() {
+ return this.document;
+ }
+
+ /**
+ * 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 {
+ if (w != this.width || h != this.height) {
+ 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");
+ */
+ }
+
+ public int getPageCount() {
+ return this.pagecount;
+ }
+
+ public void nextPage() throws IOException {
+ closePage();
+ }
+
+ protected void closePage() throws IOException {
+ if (!this.pagePending) {
+ return; //ignore
+ }
+ //Finish page
+ writePageTrailer();
+ this.pagePending = false;
+ }
+
+ /**
+ * Writes the page header for a page.
+ * @throws IOException In case an I/O error occurs
+ */
+ protected abstract void writePageHeader() throws IOException;
+
+ /**
+ * Writes the page trailer for a page.
+ * @throws IOException In case an I/O error occurs
+ */
+ protected abstract void writePageTrailer() throws IOException;
+
+
+ /** {@inheritDoc} */
+ protected void preparePainting() {
+ if (this.pagePending) {
+ return;
+ }
+ try {
+ startPage();
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+ }
+
+ protected void startPage() throws IOException {
+ if (this.pagePending) {
+ throw new IllegalStateException("Close page first before starting another");
+ }
+ //Start page
+ this.pagecount++;
+
+ if (this.initialTransform == null) {
+ //Save initial transformation matrix
+ this.initialTransform = getTransform();
+ this.initialClip = getClip();
+ } else {
+ //Reset transformation matrix
+ setTransform(this.initialTransform);
+ setClip(this.initialClip);
+ }
+
+ writePageHeader();
+ gen.writeln("0.001 0.001 scale");
+ gen.concatMatrix(1, 0, 0, -1, 0, this.height * 1000);
+ gen.writeDSCComment(DSCConstants.END_PAGE_SETUP);
+ this.pagePending = true;
+ }
+
+ /**
+ * 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 {
+ if (this.pagePending) {
+ closePage();
+ }
+
+ //Finish document
+ gen.writeDSCComment(DSCConstants.TRAILER);
+ gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.pagecount));
+ gen.writeDSCComment(DSCConstants.EOF);
+ gen.flush();
+ }
+
+ /**
+ * This constructor supports the create method
+ * @param g the PostScript document graphics to make a copy of
+ */
+ public AbstractPSDocumentGraphics2D(AbstractPSDocumentGraphics2D g) {
+ super(g);
+ }
+
+
+}
+
diff --git a/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java
new file mode 100644
index 000000000..a02b51c24
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/AbstractPSTranscoder.java
@@ -0,0 +1,195 @@
+/*
+ * $Id$
+ * ============================================================================
+ * 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 <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+
+import java.awt.Color;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import java.io.IOException;
+
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.BridgeException;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.bridge.ViewBox;
+
+import org.apache.batik.dom.svg.SVGOMDocument;
+
+import org.apache.batik.gvt.GraphicsNode;
+
+import org.apache.batik.transcoder.TranscoderException;
+import org.apache.batik.transcoder.TranscoderOutput;
+import org.apache.batik.transcoder.image.resources.Messages;
+
+import org.apache.batik.transcoder.image.ImageTranscoder;
+
+import org.apache.fop.svg.AbstractFOPTranscoder;
+
+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.
+ *
+ * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and
+ * <tt>KEY_HEIGHT</tt>) 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.
+ *
+ * <p>The <tt>KEY_BACKGROUND_COLOR</tt> 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.
+ *
+ * <p>The <tt>KEY_AOI</tt> represents the area of interest to paint
+ * in device space.
+ *
+ * <p>Three additional transcoding hints that act on the SVG
+ * processor can be specified:
+ *
+ * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be
+ * used by a &lt;switch> SVG element for example),
+ * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user
+ * stylesheet, and <tt>KEY_PIXEL_TO_MM</tt> to specify the pixel to
+ * millimeter conversion factor.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id$
+ */
+public abstract class AbstractPSTranscoder extends AbstractFOPTranscoder {
+
+ private Configuration cfg = null;
+ protected AbstractPSDocumentGraphics2D graphics = null;
+
+ /**
+ * Constructs a new <tt>AbstractPSTranscoder</tt>.
+ */
+ public AbstractPSTranscoder() {
+ super();
+ }
+
+ protected abstract AbstractPSDocumentGraphics2D createDocumentGraphics2D();
+
+ protected BridgeContext createBridgeContext() {
+ /*boolean stroke = true;
+ if (hints.containsKey(KEY_STROKE_TEXT)) {
+ stroke = ((Boolean)hints.get(KEY_STROKE_TEXT)).booleanValue();
+ }*/
+
+ BridgeContext ctx = new BridgeContext(userAgent);
+ PSTextPainter textPainter = new PSTextPainter(graphics.getDocument());
+ ctx.setTextPainter(textPainter);
+ ctx.putBridge(new PSTextElementBridge(textPainter));
+
+ //ctx.putBridge(new PSImageElementBridge());
+ return ctx;
+ }
+
+ /**
+ * 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 {
+
+ graphics = createDocumentGraphics2D();
+ ContainerUtil.enableLogging(graphics, getLogger());
+ try {
+ if (this.cfg != null) {
+ ContainerUtil.configure(graphics, this.cfg);
+ }
+ ContainerUtil.initialize(graphics);
+ } catch (Exception e) {
+ throw new TranscoderException(
+ "Error while setting up PDFDocumentGraphics2D", e);
+ }
+
+ super.transcode(document, uri, output);
+
+ // prepare the image to be painted
+ int w = (int)(width + 0.5);
+ int h = (int)(height + 0.5);
+
+ try {
+ graphics.setupDocument(output.getOutputStream(), w, h);
+ graphics.setSVGDimension(width, height);
+
+ 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(curTxf);
+
+ this.root.paint(graphics);
+
+ graphics.finish();
+ } catch (IOException ex) {
+ throw new TranscoderException(ex);
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/fop/render/ps/DSCConstants.java b/src/java/org/apache/fop/render/ps/DSCConstants.java
index 40da71313..fe8570975 100644
--- a/src/java/org/apache/fop/render/ps/DSCConstants.java
+++ b/src/java/org/apache/fop/render/ps/DSCConstants.java
@@ -64,6 +64,9 @@ public class DSCConstants {
/** Lead-in for a DSC-conformant PostScript file */
public static final String PS_ADOBE_30 = "%!PS-Adobe-3.0";
+ /** Lead-in for an EPS file */
+ public static final String EPSF_30 = "EPSF-3.0";
+
/** Bounding box for the document */
public static final String BBOX = "BoundingBox";
/** High-resolution bounding box for the document */
diff --git a/src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java
new file mode 100644
index 000000000..b38a4adae
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java
@@ -0,0 +1,124 @@
+/*
+ * $Id$
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 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 <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+import java.io.IOException;
+
+/**
+ * This class is a wrapper for the <tt>AbstractPSDocumentGraphics2D</tt> that
+ * is used to create EPS (Encapsulated PostScript) files instead of PS file.
+ *
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id$
+ * @see org.apache.fop.render.ps.PSGraphics2D
+ * @see org.apache.fop.render.ps.AbstractPSDocumentGraphics2D
+ */
+public class EPSDocumentGraphics2D extends AbstractPSDocumentGraphics2D {
+
+ /**
+ * Create a new EPSDocumentGraphics2D.
+ * This is used to create a new EPS 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.
+ */
+ public EPSDocumentGraphics2D(boolean textAsShapes) {
+ super(textAsShapes);
+ }
+
+ protected void writeFileHeader() throws IOException {
+ final Long pagewidth = new Long(this.width);
+ final Long pageheight = new Long(this.height);
+
+ //PostScript Header
+ gen.writeln(DSCConstants.PS_ADOBE_30 + " " + DSCConstants.EPSF_30);
+ gen.writeDSCComment(DSCConstants.CREATOR,
+ new String[] {"FOP EPS Transcoder for SVG"});
+ gen.writeDSCComment(DSCConstants.CREATION_DATE,
+ new Object[] {new java.util.Date()});
+ gen.writeDSCComment(DSCConstants.PAGES, new Integer(0));
+ gen.writeDSCComment(DSCConstants.BBOX, new Object[]
+ {ZERO, ZERO, pagewidth, pageheight});
+ gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(2));
+ gen.writeDSCComment(DSCConstants.END_COMMENTS);
+
+ //Prolog
+ gen.writeDSCComment(DSCConstants.BEGIN_PROLOG);
+ PSProcSets.writeFOPStdProcSet(gen);
+ PSProcSets.writeFOPEPSProcSet(gen);
+ if (document != null) {
+ PSProcSets.writeFontDict(gen, document);
+ }
+ gen.writeDSCComment(DSCConstants.END_PROLOG);
+ }
+
+ protected void writePageHeader() throws IOException {
+ Integer pageNumber = new Integer(this.pagecount);
+ gen.writeDSCComment(DSCConstants.PAGE, new Object[]
+ {pageNumber.toString(), pageNumber});
+ gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
+ {ZERO, ZERO, new Integer(width), new Integer(height)});
+ gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP);
+ if (this.document != null) {
+ gen.writeln("FOPFonts begin");
+ }
+ }
+
+ protected void writePageTrailer() throws IOException {
+ gen.writeDSCComment(DSCConstants.PAGE_TRAILER);
+ gen.writeDSCComment(DSCConstants.END_PAGE);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/EPSTranscoder.java b/src/java/org/apache/fop/render/ps/EPSTranscoder.java
new file mode 100644
index 000000000..602268b53
--- /dev/null
+++ b/src/java/org/apache/fop/render/ps/EPSTranscoder.java
@@ -0,0 +1,94 @@
+/*
+ * $Id$
+ * ============================================================================
+ * 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 <jtauber@jtauber.com>. For more information on the Apache
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.render.ps;
+
+/**
+ * This class enables to transcode an input to a EPS document.
+ *
+ * <p>Two transcoding hints (<tt>KEY_WIDTH</tt> and
+ * <tt>KEY_HEIGHT</tt>) 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.
+ *
+ * <p>The <tt>KEY_BACKGROUND_COLOR</tt> 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.
+ *
+ * <p>The <tt>KEY_AOI</tt> represents the area of interest to paint
+ * in device space.
+ *
+ * <p>Three additional transcoding hints that act on the SVG
+ * processor can be specified:
+ *
+ * <p><tt>KEY_LANGUAGE</tt> to set the default language to use (may be
+ * used by a &lt;switch> SVG element for example),
+ * <tt>KEY_USER_STYLESHEET_URI</tt> to fix the URI of a user
+ * stylesheet, and <tt>KEY_PIXEL_TO_MM</tt> to specify the pixel to
+ * millimeter conversion factor.
+ *
+ * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
+ * @version $Id$
+ */
+public class EPSTranscoder extends AbstractPSTranscoder {
+
+ /**
+ * Constructs a new <tt>EPSPSTranscoder</tt>.
+ */
+ public EPSTranscoder() {
+ super();
+ }
+
+ protected AbstractPSDocumentGraphics2D createDocumentGraphics2D() {
+ return new EPSDocumentGraphics2D(false);
+ }
+
+}
diff --git a/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
index 35c3fc7fd..3c811d476 100644
--- a/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
+++ b/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
@@ -1,5 +1,5 @@
/*
- * $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $
+ * $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
@@ -52,17 +52,12 @@ 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.apps.Document;
+import org.apache.fop.render.pdf.FontSetup;
/**
* This class is a wrapper for the <tt>PSGraphics2D</tt> that
@@ -71,16 +66,14 @@ import org.apache.fop.apps.Document;
*
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
* @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
- * @version $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $
+ * @version $Id$
* @see org.apache.fop.render.ps.PSGraphics2D
*/
-public class PSDocumentGraphics2D extends PSGraphics2D {
-
- private int width;
- private int height;
+public class PSDocumentGraphics2D extends AbstractPSDocumentGraphics2D {
+
/**
- * Create a new PSDocumentGraphics2D.
+ * Create a new AbstractPSDocumentGraphics2D.
* 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
@@ -94,158 +87,90 @@ public class PSDocumentGraphics2D extends PSGraphics2D {
super(textAsShapes);
if (!textAsShapes) {
- fontInfo = new Document(null);
- FontSetup.setup(fontInfo, null);
- //FontState fontState = new FontState("Helvetica", "normal",
- // FontInfo.NORMAL, 12, 0);
+ this.document = new Document(null);
+ FontSetup.setup(this.document, null);
}
-
- 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
+ * Create a new AbstractPSDocumentGraphics2D.
+ * 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 void setupDocument(OutputStream stream, int width, int height) throws IOException {
- this.width = width;
- this.height = height;
+ public PSDocumentGraphics2D(boolean textAsShapes, OutputStream stream,
+ int width, int height) throws IOException {
+ this(textAsShapes);
+ setupDocument(stream, width, height);
+ }
- final Integer zero = new Integer(0);
+ public void nextPage() throws IOException {
+ closePage();
+ }
+
+ protected void writeFileHeader() throws IOException {
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.PAGES, PSGenerator.ATEND);
gen.writeDSCComment(DSCConstants.BBOX, new Object[]
- {zero, zero, pagewidth, pageheight});
+ {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);
- PSProcSets.writeFontDict(gen, fontInfo);
+ if (document != null) {
+ PSProcSets.writeFontDict(gen, document);
+ }
gen.writeDSCComment(DSCConstants.END_SETUP);
+ }
- //Start page
- Integer pageNumber = new Integer(1);
- gen.writeDSCComment(DSCConstants.PAGE, new Object[]
+ protected void writePageHeader() throws IOException {
+ Integer pageNumber = new Integer(this.pagecount);
+ gen.writeDSCComment(DSCConstants.PAGE, new Object[]
{pageNumber.toString(), pageNumber});
gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[]
- {zero, zero, pagewidth, pageheight});
+ {ZERO, ZERO, new Integer(width), new Integer(height)});
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 Document 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");
- */
+ gen.writeln("<<");
+ gen.writeln("/PageSize [" + width + " " + height + "]");
+ gen.writeln("/ImagingBBox null");
+ gen.writeln(">> setpagedevice");
+ if (this.document != null) {
+ gen.writeln("FOPFonts begin");
+ }
}
-
- /**
- * 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");
+
+ protected void writePageTrailer() throws IOException {
+ 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
@@ -264,25 +189,5 @@ public class PSDocumentGraphics2D extends PSGraphics2D {
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/PSGenerator.java b/src/java/org/apache/fop/render/ps/PSGenerator.java
index 988d53bd6..156c77149 100644
--- a/src/java/org/apache/fop/render/ps/PSGenerator.java
+++ b/src/java/org/apache/fop/render/ps/PSGenerator.java
@@ -50,11 +50,11 @@
*/
package org.apache.fop.render.ps;
+import java.awt.geom.AffineTransform;
import java.io.OutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.DecimalFormat;
-import java.text.NumberFormat;
import java.util.Date;
import java.util.Stack;
@@ -71,13 +71,17 @@ public class PSGenerator {
* Indicator for the PostScript interpreter that the value is provided
* later in the document (mostly in the %%Trailer section).
*/
- public static final AtendIndicator ATEND = new AtendIndicator() {};
+ public static final AtendIndicator ATEND = new AtendIndicator() {
+ };
private OutputStream out;
+ private boolean commentsEnabled = true;
private Stack graphicsStateStack = new Stack();
private PSState currentState;
- private DecimalFormat df = new DecimalFormat("0.000");
+ private DecimalFormat df3 = new DecimalFormat("0.000");
+ private DecimalFormat df1 = new DecimalFormat("0.#");
+ private DecimalFormat df5 = new DecimalFormat("0.#####");
private StringBuffer tempBuffer = new StringBuffer(256);
@@ -87,6 +91,14 @@ public class PSGenerator {
this.currentState = new PSState();
this.graphicsStateStack.push(this.currentState);
}
+
+ /**
+ * Returns the OutputStream the PSGenerator writes to.
+ * @return the OutputStream
+ */
+ public OutputStream getOutputStream() {
+ return this.out;
+ }
/**
* Writes a newline character to the OutputStream.
@@ -104,8 +116,17 @@ public class PSGenerator {
* @return the formatted value
*/
public String formatDouble(double value) {
- NumberFormat nf = new java.text.DecimalFormat("0.#");
- return nf.format(value);
+ return df1.format(value);
+ }
+
+ /**
+ * Formats a double value for PostScript output (higher resolution).
+ *
+ * @param value value to format
+ * @return the formatted value
+ */
+ public String formatDouble5(double value) {
+ return df5.format(value);
}
/**
@@ -132,6 +153,12 @@ public class PSGenerator {
newLine();
}
+ public void commentln(String comment) throws IOException {
+ if (this.commentsEnabled) {
+ writeln(comment);
+ }
+ }
+
/**
* Writes encoded data to the PostScript stream.
*
@@ -290,12 +317,12 @@ public class PSGenerator {
} else if (params[i] instanceof AtendIndicator) {
tempBuffer.append("(atend)");
} else if (params[i] instanceof Double) {
- tempBuffer.append(df.format(params[i]));
+ tempBuffer.append(df3.format(params[i]));
} else if (params[i] instanceof Number) {
tempBuffer.append(params[i].toString());
} else if (params[i] instanceof Date) {
- DateFormat df = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- tempBuffer.append(convertStringToDSC(df.format((Date)params[i])));
+ DateFormat datef = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ tempBuffer.append(convertStringToDSC(datef.format((Date)params[i])));
} else {
throw new IllegalArgumentException("Unsupported parameter type: "
+ params[i].getClass().getName());
@@ -340,12 +367,12 @@ public class PSGenerator {
public void concatMatrix(double a, double b,
double c, double d,
double e, double f) throws IOException {
- writeln("[" + formatDouble(a) + " "
- + formatDouble(b) + " "
- + formatDouble(c) + " "
- + formatDouble(d) + " "
- + formatDouble(e) + " "
- + formatDouble(f) + "] concat");
+ writeln("[" + formatDouble5(a) + " "
+ + formatDouble5(b) + " "
+ + formatDouble5(c) + " "
+ + formatDouble5(d) + " "
+ + formatDouble5(e) + " "
+ + formatDouble5(f) + "] concat");
}
/**
@@ -360,6 +387,34 @@ public class PSGenerator {
}
/**
+ * Concats the transformations matric.
+ * @param at the AffineTransform whose matrix to use
+ * @exception IOException In case of an I/O problem
+ */
+ public void concatMatrix(AffineTransform at) throws IOException {
+ double[] matrix = new double[6];
+ at.getMatrix(matrix);
+ concatMatrix(matrix);
+ }
+
+ /**
+ * Adds a rectangle to the current path.
+ * @param x upper left corner
+ * @param y upper left corner
+ * @param w width
+ * @param h height
+ * @exception IOException In case of an I/O problem
+ */
+ public void defineRect(double x, double y, double w, double h)
+ throws IOException {
+ writeln(formatDouble(x)
+ + " " + formatDouble(y)
+ + " " + formatDouble(w)
+ + " " + formatDouble(h)
+ + " re");
+ }
+
+ /**
* Returns the current graphics state.
* @return the current graphics state
*/
diff --git a/src/java/org/apache/fop/render/ps/PSGraphics2D.java b/src/java/org/apache/fop/render/ps/PSGraphics2D.java
index 98aa6fdbf..b017c0ad7 100644
--- a/src/java/org/apache/fop/render/ps/PSGraphics2D.java
+++ b/src/java/org/apache/fop/render/ps/PSGraphics2D.java
@@ -51,15 +51,13 @@
package org.apache.fop.render.ps;
//Java
-import java.util.List;
import java.text.AttributedCharacterIterator;
-import java.text.CharacterIterator;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
-/* java.awt.Font is not imported to avoid confusion with
- org.apache.fop.fonts.Font */
+/* java.awt.Font is not imported to avoid confusion with
+ org.apache.fop.fonts.Font */
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
@@ -71,9 +69,11 @@ import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.TexturePaint;
+import java.awt.color.ColorSpace;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
@@ -83,14 +83,13 @@ import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderableImage;
import java.io.IOException;
-// FOP
-import org.apache.fop.apps.Document;
-import org.apache.fop.fonts.Font;
-
-// Batik
+//Batik
import org.apache.batik.ext.awt.g2d.AbstractGraphics2D;
import org.apache.batik.ext.awt.g2d.GraphicContext;
+//FOP
+import org.apache.fop.fonts.Font;
+import org.apache.fop.apps.Document;
/**
* This concrete implementation of <tt>AbstractGraphics2D</tt> is a
@@ -106,46 +105,30 @@ import org.apache.batik.ext.awt.g2d.GraphicContext;
*/
public class PSGraphics2D extends AbstractGraphics2D {
- private boolean standalone = false;
-
- /**
- * the PostScript genertaor being created
- */
+ /** the PostScript generator being created */
protected PSGenerator gen;
- /** Currently valid FontState */
- protected Font fontState;
+ private boolean clippingDisabled = true;
+ /** Currently valid FontState */
+ protected Font font;
+
/** Overriding FontState */
- protected Font overrideFontState = null;
-
- /**
- * the current (internal) font name
- */
+ protected Font overrideFont = null;
+
+ /** the current (internal) font name */
protected String currentFontName;
- /**
- * the current font size in millipoints
- */
+ /** the current font size in millipoints */
protected int currentFontSize;
/**
- * the current vertical position in millipoints from bottom
- */
- protected int currentYPosition = 0;
-
- /**
- * the current horizontal position in millipoints from left
- */
- protected int currentXPosition = 0;
-
- /**
* the current colour for use in svg
*/
protected Color currentColour = new Color(0, 0, 0);
/** FontInfo containing all available fonts */
- protected Document fontInfo;
+ protected Document document;
/**
* Create a new Graphics2D that generates PostScript code.
@@ -210,6 +193,14 @@ public class PSGraphics2D extends AbstractGraphics2D {
}
/**
+ * This method is used by AbstractPSDocumentGraphics2D to prepare a new page if
+ * necessary.
+ */
+ protected void preparePainting() {
+ //nop, used by AbstractPSDocumentGraphics2D
+ }
+
+ /**
* Draws as much of the specified image as is currently available.
* The image is drawn with its top-left corner at
* (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate
@@ -236,7 +227,8 @@ public class PSGraphics2D extends AbstractGraphics2D {
*/
public boolean drawImage(Image img, int x, int y,
ImageObserver observer) {
- // System.err.println("drawImage:x, y");
+ preparePainting();
+ System.out.println("drawImage: x, y " + img.getClass().getName());
final int width = img.getWidth(observer);
final int height = img.getHeight(observer);
@@ -289,23 +281,24 @@ public class PSGraphics2D extends AbstractGraphics2D {
// error
break;
}
-
- /*try {
+/*
+ try {
FopImage fopimg = new TempImage(width, height, result, mask);
AffineTransform at = getTransform();
double[] matrix = new double[6];
at.getMatrix(matrix);
- psRenderer.write("gsave");
+ gen.saveGraphicsState();
Shape imclip = getClip();
writeClip(imclip);
// psRenderer.write("" + matrix[0] + " " + matrix[1] +
// " " + matrix[2] + " " + matrix[3] + " " +
// matrix[4] + " " + matrix[5] + " cm\n");
//psRenderer.renderBitmap(fopimg, x, y, width, height);
- psRenderer.write("grestore");
- } catch (Exception e) {
- e.printStackTrace();
- }*/
+ gen.restoreGraphicsState();
+ } catch (IOException ioe) {
+ handleIOException(ioe);
+ }
+*/
return true;
}
@@ -319,26 +312,25 @@ public class PSGraphics2D extends AbstractGraphics2D {
BufferedImage.TYPE_INT_ARGB);
}
- /*class TempImage implements FopImage {
- int m_height;
- int m_width;
- int m_bitsPerPixel;
- PDFColorSpace m_colorSpace;
- int m_bitmapSiye;
- byte[] m_bitmaps;
- byte[] m_mask;
+/*
+ class TempImage implements FopImage {
+ int height;
+ int width;
+ int bitsPerPixel;
+ ColorSpace colorSpace;
+ int bitmapSiye;
+ byte[] bitmaps;
+ byte[] mask;
PDFColor transparent = new PDFColor(255, 255, 255);
TempImage(int width, int height, byte[] result,
byte[] mask) {
- this.m_height = height;
- this.m_width = width;
- this.m_bitsPerPixel = 8;
- this.m_colorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
- // this.m_isTransparent = false;
- // this.m_bitmapsSize = this.m_width * this.m_height * 3;
- this.m_bitmaps = result;
- this.m_mask = mask;
+ this.height = height;
+ this.width = width;
+ this.bitsPerPixel = 8;
+ this.colorSpace = ColorSpace.new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ this.bitmaps = result;
+ this.mask = mask;
}
public boolean load(int type, FOUserAgent ua) {
@@ -350,55 +342,55 @@ public class PSGraphics2D extends AbstractGraphics2D {
}
public String getURL() {
- return "" + m_bitmaps;
+ return "" + this.bitmaps;
}
// image size
public int getWidth() {
- return m_width;
+ return this.width;
}
public int getHeight() {
- return m_height;
+ return this.height;
}
// DeviceGray, DeviceRGB, or DeviceCMYK
- public PDFColorSpace getColorSpace() {
- return m_colorSpace;
+ public ColorSpace getColorSpace() {
+ return this.colorSpace;
}
// bits per pixel
public int getBitsPerPixel() {
- return m_bitsPerPixel;
+ return this.bitsPerPixel;
}
// For transparent images
public boolean isTransparent() {
- return transparent != null;
+ return this.transparent != null;
}
public PDFColor getTransparentColor() {
- return transparent;
+ return this.transparent;
}
public boolean hasSoftMask() {
- return m_mask != null;
+ return this.mask != null;
}
public byte[] getSoftMask() {
- return m_mask;
+ return this.mask;
}
// get the image bytes, and bytes properties
// get uncompressed image bytes
public byte[] getBitmaps() {
- return m_bitmaps;
+ return this.bitmaps;
}
// width * (bitsPerPixel / 8) * height, no ?
public int getBitmapsSize() {
- return m_width * m_height * 3;
+ return getWidth() * getHeight() * 3; //Assumes RGB!
}
// get compressed image bytes
@@ -418,10 +410,16 @@ public class PSGraphics2D extends AbstractGraphics2D {
}
// release memory
- public void close() {}
+ public void close() {
+ //nop
+ }
- }*/
+ public ICC_Profile getICCProfile() {
+ return null;
+ }
+ }
+*/
/**
* Draws as much of the specified image as has already been scaled
@@ -459,6 +457,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
*/
public boolean drawImage(Image img, int x, int y, int width, int height,
ImageObserver observer) {
+ preparePainting();
System.out.println("drawImage");
return true;
}
@@ -493,10 +492,54 @@ public class PSGraphics2D extends AbstractGraphics2D {
public void dispose() {
// System.out.println("dispose");
this.gen = null;
- fontState = null;
- currentFontName = null;
- currentColour = null;
- fontInfo = null;
+ this.font = null;
+ this.currentColour = null;
+ this.document = null;
+ }
+
+ /**
+ * Processes a path iterator generating the nexessary painting operations.
+ * @param iter PathIterator to process
+ * @throws IOException In case of an I/O problem.
+ */
+ public void processPathIterator(PathIterator iter) throws IOException {
+ double[] vals = new double[6];
+ while (!iter.isDone()) {
+ int type = iter.currentSegment(vals);
+ switch (type) {
+ case PathIterator.SEG_CUBICTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " "
+ + gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5])
+ + " curveto");
+ break;
+ case PathIterator.SEG_LINETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " lineto");
+ break;
+ case PathIterator.SEG_MOVETO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1])
+ + " M");
+ break;
+ case PathIterator.SEG_QUADTO:
+ gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
+ + gen.formatDouble(1000 * vals[1]) + " "
+ + gen.formatDouble(1000 * vals[2]) + " "
+ + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
+ break;
+ case PathIterator.SEG_CLOSE:
+ gen.writeln("closepath");
+ break;
+ default:
+ break;
+ }
+ iter.next();
+ }
}
/**
@@ -516,58 +559,20 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @see #setComposite
*/
public void draw(Shape s) {
+ preparePainting();
try {
// System.out.println("draw(Shape)");
gen.saveGraphicsState();
Shape imclip = getClip();
writeClip(imclip);
- Color c = getColor();
- gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
- + gen.formatDouble(c.getGreen() / 255.0) + " "
- + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
+ establishColor(getColor());
applyPaint(getPaint(), false);
applyStroke(getStroke());
gen.writeln("newpath");
PathIterator iter = s.getPathIterator(getTransform());
- while (!iter.isDone()) {
- double vals[] = new double[6];
- int type = iter.currentSegment(vals);
- switch (type) {
- case PathIterator.SEG_CUBICTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " "
- + gen.formatDouble(1000 * vals[4]) + " "
- + gen.formatDouble(1000 * vals[5])
- + " curveto");
- break;
- case PathIterator.SEG_LINETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " lineto");
- break;
- case PathIterator.SEG_MOVETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " M");
- break;
- case PathIterator.SEG_QUADTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
- break;
- case PathIterator.SEG_CLOSE:
- gen.writeln("closepath");
- break;
- default:
- break;
- }
- iter.next();
- }
+ processPathIterator(iter);
doDrawing(false, true, false);
gen.restoreGraphicsState();
} catch (IOException ioe) {
@@ -580,50 +585,20 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @param s Shape defining the clipping region
*/
protected void writeClip(Shape s) {
- try {
- PathIterator iter = s.getPathIterator(getTransform());
- gen.writeln("newpath");
- while (!iter.isDone()) {
- double vals[] = new double[6];
- int type = iter.currentSegment(vals);
- switch (type) {
- case PathIterator.SEG_CUBICTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " "
- + gen.formatDouble(1000 * vals[4]) + " "
- + gen.formatDouble(1000 * vals[5])
- + " curveto");
- break;
- case PathIterator.SEG_LINETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " lineto");
- break;
- case PathIterator.SEG_MOVETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " M");
- break;
- case PathIterator.SEG_QUADTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
- break;
- case PathIterator.SEG_CLOSE:
- gen.writeln("closepath");
- break;
- default:
- break;
- }
- iter.next();
+ if (s == null) {
+ return;
+ }
+ if (!this.clippingDisabled) {
+ preparePainting();
+ try {
+ gen.writeln("newpath");
+ PathIterator iter = s.getPathIterator(getTransform());
+ processPathIterator(iter);
+ // clip area
+ gen.writeln("clippath");
+ } catch (IOException ioe) {
+ handleIOException(ioe);
}
- // clip area
- gen.writeln("clippath");
- } catch (IOException ioe) {
- handleIOException(ioe);
}
}
@@ -633,52 +608,11 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @param fill True if to be applied for filling
*/
protected void applyPaint(Paint paint, boolean fill) {
+ preparePainting();
if (paint instanceof GradientPaint) {
- GradientPaint gp = (GradientPaint)paint;
- Color c1 = gp.getColor1();
- Color c2 = gp.getColor2();
- Point2D p1 = gp.getPoint1();
- Point2D p2 = gp.getPoint2();
- //boolean cyclic = gp.isCyclic();
-
- List theCoords = new java.util.ArrayList();
- theCoords.add(new Double(p1.getX()));
- theCoords.add(new Double(p1.getY()));
- theCoords.add(new Double(p2.getX()));
- theCoords.add(new Double(p2.getY()));
-
- List theExtend = new java.util.ArrayList();
- theExtend.add(new Boolean(true));
- theExtend.add(new Boolean(true));
-
- List theDomain = new java.util.ArrayList();
- theDomain.add(new Double(0));
- theDomain.add(new Double(1));
-
- List theEncode = new java.util.ArrayList();
- theEncode.add(new Double(0));
- theEncode.add(new Double(1));
- theEncode.add(new Double(0));
- theEncode.add(new Double(1));
-
- List theBounds = new java.util.ArrayList();
- theBounds.add(new Double(0));
- theBounds.add(new Double(1));
-
- //List theFunctions = new java.util.ArrayList();
-
- List someColors = new java.util.ArrayList();
-
- Color color1 = new Color(c1.getRed(), c1.getGreen(),
- c1.getBlue());
- someColors.add(color1);
- Color color2 = new Color(c2.getRed(), c2.getGreen(),
- c2.getBlue());
- someColors.add(color2);
-
- //PDFColorSpace aColorSpace = new PDFColorSpace(PDFColorSpace.DEVICE_RGB);
+ //NYI
} else if (paint instanceof TexturePaint) {
- //nop
+ //NYI
}
}
@@ -687,33 +621,34 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @param stroke Stroke object to use
*/
protected void applyStroke(Stroke stroke) {
+ preparePainting();
try {
if (stroke instanceof BasicStroke) {
BasicStroke bs = (BasicStroke)stroke;
float[] da = bs.getDashArray();
if (da != null) {
- gen.writeln("[");
+ gen.write("[");
for (int count = 0; count < da.length; count++) {
- gen.writeln("" + (1000 * (int)da[count]));
+ gen.write("" + (1000 * (int)da[count]));
if (count < da.length - 1) {
- gen.writeln(" ");
+ gen.write(" ");
}
}
- gen.writeln("] ");
+ gen.write("] ");
float offset = bs.getDashPhase();
gen.writeln((1000 * (int)offset) + " setdash");
}
int ec = bs.getEndCap();
switch (ec) {
case BasicStroke.CAP_BUTT:
- gen.writeln(0 + " setlinecap");
+ gen.writeln("0 setlinecap");
break;
case BasicStroke.CAP_ROUND:
- gen.writeln(1 + " setlinecap");
+ gen.writeln("1 setlinecap");
break;
case BasicStroke.CAP_SQUARE:
- gen.writeln(2 + " setlinecap");
+ gen.writeln("2 setlinecap");
break;
}
@@ -761,10 +696,10 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @see #setClip
*/
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ preparePainting();
System.out.println("drawRenderedImage");
}
-
/**
* Renders a
* {@link RenderableImage},
@@ -797,10 +732,59 @@ public class PSGraphics2D extends AbstractGraphics2D {
*/
public void drawRenderableImage(RenderableImage img,
AffineTransform xform) {
+ preparePainting();
System.out.println("drawRenderableImage");
}
/**
+ * Establishes the given color in the PostScript interpreter.
+ * @param c the color to set
+ * @throws IOException In case of an I/O problem
+ */
+ protected void establishColor(Color c) throws IOException {
+ StringBuffer p = new StringBuffer();
+ float[] comps = c.getColorComponents(null);
+
+ if (c.getColorSpace().getType() == ColorSpace.TYPE_RGB) {
+ // according to pdfspec 12.1 p.399
+ // if the colors are the same then just use the g or G operator
+ boolean same = (comps[0] == comps[1]
+ && comps[0] == comps[2]);
+ // output RGB
+ if (same) {
+ p.append(gen.formatDouble(comps[0]));
+ } else {
+ for (int i = 0; i < c.getColorSpace().getNumComponents(); i++) {
+ if (i > 0) {
+ p.append(" ");
+ }
+ p.append(gen.formatDouble(comps[i]));
+ }
+ }
+ if (same) {
+ p.append(" setgray");
+ } else {
+ p.append(" setrgbcolor");
+ }
+ } else if (c.getColorSpace().getType() == ColorSpace.TYPE_CMYK) {
+ // colorspace is CMYK
+ for (int i = 0; i < c.getColorSpace().getNumComponents(); i++) {
+ if (i > 0) {
+ p.append(" ");
+ }
+ p.append(gen.formatDouble(comps[i]));
+ }
+ p.append(" setcmykcolor");
+ } else {
+ // means we're in DeviceGray or Unknown.
+ // assume we're in DeviceGray, because otherwise we're screwed.
+ p.append(gen.formatDouble(comps[0]));
+ p.append(" setgray");
+ }
+ gen.writeln(p.toString());
+ }
+
+ /**
* Renders the text specified by the specified <code>String</code>,
* using the current <code>Font</code> and <code>Paint</code> attributes
* in the <code>Graphics2D</code> context.
@@ -825,73 +809,125 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @see #setClip
*/
public void drawString(String s, float x, float y) {
- try {
- if (overrideFontState == null) {
- java.awt.Font gFont = getFont();
- String n = gFont.getFamily();
- if (n.equals("sanserif")) {
- n = "sans-serif";
- }
- int siz = gFont.getSize();
- String style = gFont.isItalic() ? "italic" : "normal";
- String weight = gFont.isBold() ? "bold" : "normal";
-
- //try {
- //fontState = new FontState(n, fontState.getFontMetrics(),siz);
- //} catch (org.apache.fop.apps.FOPException fope) {
- //fope.printStackTrace();
- //}
+ if (this.textAsShapes) {
+ drawStringAsShapes(s, x, y);
} else {
- fontState = overrideFontState;
- overrideFontState = null;
+ drawStringAsText(s, x, y);
}
- Shape imclip = getClip();
- writeClip(imclip);
- Color c = getColor();
- gen.writeln(c.getRed() / 255.0 + " "
- + c.getGreen() / 255.0 + " "
- + c.getBlue() / 255.0 + " setrgbcolor");
-
- AffineTransform trans = getTransform();
- trans.translate(x, y);
- double[] vals = new double[6];
- trans.getMatrix(vals);
- gen.writeln(gen.formatDouble(1000 * vals[4]) + " "
- + gen.formatDouble(1000 * vals[5]) + " moveto ");
- //String fontWeight = fontState.getFontWeight();
- StringBuffer sb = new StringBuffer();
-
- int l = s.length();
-
- if ((currentFontName != fontState.getFontName())
- || (currentFontSize != fontState.getFontSize())) {
- gen.writeln(fontState.getFontName() + " " + fontState.getFontSize() + " F");
- currentFontName = fontState.getFontName();
- currentFontSize = fontState.getFontSize();
- }
- for (int i = 0; i < l; i++) {
- char ch = s.charAt(i);
- char mch = fontState.mapChar(ch);
- if (mch > 127) {
- sb = sb.append("\\" + Integer.toOctalString(mch));
+ }
+
+ /**
+ * Draw a string to the PostScript document. The text is painted as shapes.
+ * @param s the string to draw
+ * @param x the x position
+ * @param y the y position
+ */
+ public void drawStringAsShapes(String s, float x, float y) {
+ java.awt.Font awtFont = super.getFont();
+ FontRenderContext frc = super.getFontRenderContext();
+ GlyphVector gv = awtFont.createGlyphVector(frc, s);
+ Shape glyphOutline = gv.getOutline(x, y);
+ fill(glyphOutline);
+ }
+
+ /**
+ * Draw a string to the PostScript document. The text is painted using
+ * text operations.
+ * @param s the string to draw
+ * @param x the x position
+ * @param y the y position
+ */
+ public void drawStringAsText(String s, float x, float y) {
+ preparePainting();
+ //System.out.println("drawString('" + s + "', " + x + ", " + y + ")");
+ try {
+ if (this.overrideFont == null) {
+ java.awt.Font awtFont = getFont();
+ this.font = createFont(awtFont);
} else {
- String escape = "\\()[]{}";
- if (escape.indexOf(mch) >= 0) {
- sb.append("\\");
- }
- sb = sb.append(mch);
+ this.font = this.overrideFont;
+ this.overrideFont = null;
}
+
+ //Color and Font state
+ establishColor(getColor());
+ establishCurrentFont();
+
+ //Clip
+ Shape imclip = getClip();
+ writeClip(imclip);
+
+ gen.saveGraphicsState();
+
+ //Prepare correct transformation
+ AffineTransform trans = getTransform();
+ gen.writeln("[" + toArray(trans) + "] concat");
+ gen.writeln(gen.formatDouble(1000 * x) + " "
+ + gen.formatDouble(1000 * y) + " moveto ");
+ gen.writeln("1 -1 scale");
+
+ StringBuffer sb = new StringBuffer("(");
+ escapeText(s, sb);
+ sb.append(") t ");
+
+ gen.writeln(sb.toString());
+
+ gen.restoreGraphicsState();
+ } catch (IOException ioe) {
+ handleIOException(ioe);
}
+ }
- String psString = null;
- psString = " (" + sb.toString() + ") " + " t ";
+ /**
+ * Converts an AffineTransform to a value array.
+ * @param at AffineTransform to convert
+ * @return a String (array of six space-separated values)
+ */
+ protected String toArray(AffineTransform at) {
+ final double[] vals = new double[6];
+ at.getMatrix(vals);
+ return gen.formatDouble5(vals[0]) + " "
+ + gen.formatDouble5(vals[1]) + " "
+ + gen.formatDouble5(vals[2]) + " "
+ + gen.formatDouble5(vals[3]) + " "
+ + gen.formatDouble(1000 * vals[4]) + " "
+ + gen.formatDouble(1000 * vals[5]);
+ }
+
+ private void escapeText(final String text, StringBuffer target) {
+ final int l = text.length();
+ for (int i = 0; i < l; i++) {
+ final char ch = text.charAt(i);
+ final char mch = this.font.mapChar(ch);
+ PSGenerator.escapeChar(mch, target);
+ }
+ }
+
+ private Font createFont(java.awt.Font f) {
+ String fontFamily = f.getFamily();
+ if (fontFamily.equals("sanserif")) {
+ fontFamily = "sans-serif";
+ }
+ int fontSize = 1000 * f.getSize();
+ String style = f.isItalic() ? "italic" : "normal";
+ int weight = f.isBold() ? Font.BOLD : Font.NORMAL;
+
+ String fontKey = this.document.findAdjustWeight(fontFamily, style, weight);
+ if (fontKey == null) {
+ fontKey = this.document.findAdjustWeight("sans-serif", style, weight);
+ }
+ return new Font(fontKey,
+ this.document.getMetricsFor(fontKey),
+ fontSize);
+ }
- gen.writeln(" 1.0 -1.0 scale");
- gen.writeln(psString);
- gen.writeln(" 1.0 -1.0 scale");
- } catch (IOException ioe) {
- handleIOException(ioe);
- }
+ private void establishCurrentFont() throws IOException {
+ if ((currentFontName != this.font.getFontName())
+ || (currentFontSize != this.font.getFontSize())) {
+ gen.writeln(this.font.getFontName() + " " + this.font.getFontSize() + " F");
+ currentFontName = this.font.getFontName();
+ currentFontSize = this.font.getFontSize();
+ }
}
/**
@@ -921,18 +957,14 @@ public class PSGraphics2D extends AbstractGraphics2D {
*/
public void drawString(AttributedCharacterIterator iterator, float x,
float y) {
+ preparePainting();
+ System.err.println("drawString(AttributedCharacterIterator) NYI");
+ /*
try {
- System.err.println("drawString(AttributedCharacterIterator)");
-
gen.writeln("BT");
Shape imclip = getClip();
writeClip(imclip);
- Color c = getColor();
- currentColour = new Color(c.getRed(), c.getGreen(), c.getBlue());
- //gen.writeln(currentColour.getColorSpaceOut(true));
- c = getBackground();
- Color col = new Color(c.getRed(), c.getGreen(), c.getBlue());
- //gen.writeln(col.getColorSpaceOut(false));
+ establishColor(getColor());
AffineTransform trans = getTransform();
trans.translate(x, y);
@@ -952,11 +984,10 @@ public class PSGraphics2D extends AbstractGraphics2D {
+ gen.formatDouble(vals[6]) + " Tm [" + ch
+ "]");
}
-
gen.writeln("ET");
} catch (IOException ioe) {
handleIOException(ioe);
- }
+ }*/
}
/**
@@ -974,60 +1005,22 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @see #setClip
*/
public void fill(Shape s) {
+ preparePainting();
+ // System.err.println("fill");
try {
- // System.err.println("fill");
- gen.writeln("gsave");
+ gen.saveGraphicsState();
Shape imclip = getClip();
writeClip(imclip);
- Color c = getColor();
- gen.writeln(gen.formatDouble(c.getRed() / 255.0) + " "
- + gen.formatDouble(c.getGreen() / 255.0) + " "
- + gen.formatDouble(c.getBlue() / 255.0) + " setrgbcolor");
+ establishColor(getColor());
applyPaint(getPaint(), true);
gen.writeln("newpath");
PathIterator iter = s.getPathIterator(getTransform());
- while (!iter.isDone()) {
- double vals[] = new double[6];
- int type = iter.currentSegment(vals);
- switch (type) {
- case PathIterator.SEG_CUBICTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " "
- + gen.formatDouble(1000 * vals[4]) + " "
- + gen.formatDouble(1000 * vals[5])
- + " curveto");
- break;
- case PathIterator.SEG_LINETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " lineto");
- break;
- case PathIterator.SEG_MOVETO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1])
- + " M");
- break;
- case PathIterator.SEG_QUADTO:
- gen.writeln(gen.formatDouble(1000 * vals[0]) + " "
- + gen.formatDouble(1000 * vals[1]) + " "
- + gen.formatDouble(1000 * vals[2]) + " "
- + gen.formatDouble(1000 * vals[3]) + " QUADTO ");
- break;
- case PathIterator.SEG_CLOSE:
- gen.writeln("closepath");
- break;
- default:
- break;
- }
- iter.next();
- }
+ processPathIterator(iter);
doDrawing(true, false,
iter.getWindingRule() == PathIterator.WIND_EVEN_ODD);
- gen.writeln("grestore");
+ gen.restoreGraphicsState();
} catch (IOException ioe) {
handleIOException(ioe);
}
@@ -1040,8 +1033,9 @@ public class PSGraphics2D extends AbstractGraphics2D {
* @param nonzero ???
* @exception IOException In case of an I/O problem
*/
- protected void doDrawing(boolean fill, boolean stroke, boolean nonzero)
+ protected void doDrawing(boolean fill, boolean stroke, boolean nonzero)
throws IOException {
+ preparePainting();
if (fill) {
if (stroke) {
if (!nonzero) {
@@ -1086,13 +1080,13 @@ public class PSGraphics2D extends AbstractGraphics2D {
}
/**
- * Sets the overrideing font state.
- * @param infont FontState to set
+ * Sets the overriding font.
+ * @param font Font to set
*/
- public void setOverrideFontState(Font infont) {
- overrideFontState = infont;
+ public void setOverrideFont(Font font) {
+ this.overrideFont = font;
}
-
+
/**
* Gets the font metrics for the specified font.
* @return the font metrics for the specified font.
@@ -1149,4 +1143,26 @@ public class PSGraphics2D extends AbstractGraphics2D {
System.out.println("copyArea");
}
+ /* --- for debugging
+ public void transform(AffineTransform tx) {
+ System.out.println("transform(" + toArray(tx) + ")");
+ super.transform(zx);
+ }
+
+ public void scale(double sx, double sy) {
+ System.out.println("scale(" + sx + ", " + sy + ")");
+ super.scale(sx, sy);
+ }
+
+ public void translate(double tx, double ty) {
+ System.out.println("translate(double " + tx + ", " + ty + ")");
+ super.translate(tx, ty);
+ }
+
+ public void translate(int tx, int ty) {
+ System.out.println("translate(int " + tx + ", " + ty + ")");
+ super.translate(tx, ty);
+ }
+ */
+
}
diff --git a/src/java/org/apache/fop/render/ps/PSProcSets.java b/src/java/org/apache/fop/render/ps/PSProcSets.java
index f1b40156b..55c7947f5 100644
--- a/src/java/org/apache/fop/render/ps/PSProcSets.java
+++ b/src/java/org/apache/fop/render/ps/PSProcSets.java
@@ -85,6 +85,14 @@ public final class PSProcSets {
gen.writeln("/M/moveto ld");
gen.writeln("/RM/rmoveto ld");
gen.writeln("/t/show ld");
+ gen.writeln("/A/ashow ld");
+ gen.writeln("/cp/closepath ld");
+
+ gen.writeln("/re {4 2 roll M"); //define rectangle
+ gen.writeln("1 index 0 rlineto");
+ gen.writeln("0 exch rlineto");
+ gen.writeln("neg 0 rlineto");
+ gen.writeln("cp } bd");
gen.writeln("/_ctm matrix def"); //Holds the current matrix
gen.writeln("/_tm matrix def");
diff --git a/src/java/org/apache/fop/render/ps/PSRenderer.java b/src/java/org/apache/fop/render/ps/PSRenderer.java
index c8b55debb..3f216c921 100644
--- a/src/java/org/apache/fop/render/ps/PSRenderer.java
+++ b/src/java/org/apache/fop/render/ps/PSRenderer.java
@@ -259,13 +259,12 @@ public class PSRenderer extends AbstractRenderer {
/**
* Set up the font info
*
- * @param fontInfo the font info object to set up
+ * @param foTreeControl the font info object to set up
*/
public void setupFontInfo(FOTreeControl foTreeControl) {
/* use PDF's font setup to get PDF metrics */
org.apache.fop.render.pdf.FontSetup.setup((Document)foTreeControl, null);
- // TODO: what's this?
- this.fontInfo = fontInfo;
+ this.fontInfo = (Document)foTreeControl;
}
/**
@@ -276,10 +275,14 @@ public class PSRenderer extends AbstractRenderer {
* @param h height
* @param col color to fill with
*/
- protected void fillRect(int x, int y, int w, int h,
+ protected void fillRect(float x, float y, float w, float h,
ColorType col) {
useColor(col);
- writeln(x + " " + y + " " + w + " " + h + " rectfill");
+ writeln(gen.formatDouble(x)
+ + " " + gen.formatDouble(y)
+ + " " + gen.formatDouble(w)
+ + " " + gen.formatDouble(h)
+ + " rectfill");
}
/**
@@ -289,8 +292,12 @@ public class PSRenderer extends AbstractRenderer {
* @param w width
* @param h height
*/
- protected void drawRect(int x, int y, int w, int h) {
- writeln(x + " " + y + " " + w + " " + h + " rectstroke");
+ protected void drawRect(float x, float y, float w, float h) {
+ writeln(gen.formatDouble(x)
+ + " " + gen.formatDouble(y)
+ + " " + gen.formatDouble(w)
+ + " " + gen.formatDouble(h)
+ + " rectstroke");
}
/**
@@ -325,7 +332,10 @@ public class PSRenderer extends AbstractRenderer {
private void useColor(float red, float green, float blue) {
if ((red != currRed) || (green != currGreen) || (blue != currBlue)) {
- writeln(red + " " + green + " " + blue + " setrgbcolor");
+ writeln(gen.formatDouble(red)
+ + " " + gen.formatDouble(green)
+ + " " + gen.formatDouble(blue)
+ + " setrgbcolor");
currRed = red;
currGreen = green;
currBlue = blue;
@@ -480,7 +490,10 @@ public class PSRenderer extends AbstractRenderer {
int bl = currentBPPosition + area.getOffset();
useFont(fontname, fontsize);
-
+ ColorType ct = (ColorType)area.getTrait(Trait.COLOR);
+ if (ct != null) {
+ useColor(ct);
+ }
paintText(rx, bl, area.getTextArea(), f);
/*
@@ -713,9 +726,7 @@ public class PSRenderer extends AbstractRenderer {
//saveGraphicsState();
if (back.getColor() != null) {
- updateColor(back.getColor(), true, null);
- writeln(startx + " " + starty + " "
- + width + " " + height + " rectfill");
+ fillRect(startx, starty, width, height, back.getColor());
}
if (back.getURL() != null) {
ImageFactory fact = ImageFactory.getInstance();
@@ -748,7 +759,7 @@ public class PSRenderer extends AbstractRenderer {
}
float bwidth = bps.width;
- updateColor(bps.color, false, null);
+ useColor(bps.color);
writeln(bwidth + " setlinewidth");
drawLine(startx, starty + bwidth / 2, endx, starty + bwidth / 2);
@@ -765,7 +776,7 @@ public class PSRenderer extends AbstractRenderer {
}
float bwidth = bps.width;
- updateColor(bps.color, false, null);
+ useColor(bps.color);
writeln(bwidth + " setlinewidth");
drawLine(startx + bwidth / 2, starty, startx + bwidth / 2, endy);
@@ -783,7 +794,7 @@ public class PSRenderer extends AbstractRenderer {
}
float bwidth = bps.width;
- updateColor(bps.color, false, null);
+ useColor(bps.color);
writeln(bwidth + " setlinewidth");
drawLine(startx, sy - bwidth / 2, endx, sy - bwidth / 2);
@@ -801,7 +812,7 @@ public class PSRenderer extends AbstractRenderer {
}
float bwidth = bps.width;
- updateColor(bps.color, false, null);
+ useColor(bps.color);
writeln(bwidth + " setlinewidth");
drawLine(sx - bwidth / 2, starty, sx - bwidth / 2, endy);
}
@@ -825,13 +836,7 @@ public class PSRenderer extends AbstractRenderer {
writeln(startx + " " + starty + " M ");
writeln(endx + " " + endy + " lineto");
}
-
- private void updateColor(ColorType col, boolean fill, StringBuffer pdf) {
- writeln(gen.formatDouble(col.getRed()) + " "
- + gen.formatDouble(col.getGreen()) + " "
- + gen.formatDouble(col.getBlue()) + " setrgbcolor");
- }
-
+
/**
* @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D)
*/
@@ -863,34 +868,8 @@ public class PSRenderer extends AbstractRenderer {
context.setProperty(PSXMLHandler.PS_YPOS,
new Integer(currentBPPosition + (int) pos.getY()));
//context.setProperty("strokeSVGText", options.get("strokeSVGText"));
-
- /*
- context.setProperty(PDFXMLHandler.PDF_DOCUMENT, pdfDoc);
- context.setProperty(PDFXMLHandler.OUTPUT_STREAM, ostream);
- context.setProperty(PDFXMLHandler.PDF_STATE, currentState);
- context.setProperty(PDFXMLHandler.PDF_PAGE, currentPage);
- context.setProperty(PDFXMLHandler.PDF_CONTEXT,
- currentContext == null ? currentPage: currentContext);
- context.setProperty(PDFXMLHandler.PDF_CONTEXT, currentContext);
- context.setProperty(PDFXMLHandler.PDF_STREAM, currentStream);
- context.setProperty(PDFXMLHandler.PDF_XPOS,
- new Integer(currentBlockIPPosition + (int) pos.getX()));
- context.setProperty(PDFXMLHandler.PDF_YPOS,
- new Integer(currentBPPosition + (int) pos.getY()));
- context.setProperty(PDFXMLHandler.PDF_FONT_INFO, fontInfo);
- context.setProperty(PDFXMLHandler.PDF_FONT_NAME, currentFontName);
- context.setProperty(PDFXMLHandler.PDF_FONT_SIZE,
- new Integer(currentFontSize));
- context.setProperty(PDFXMLHandler.PDF_WIDTH,
- new Integer((int) pos.getWidth()));
- context.setProperty(PDFXMLHandler.PDF_HEIGHT,
- new Integer((int) pos.getHeight()));
- */
+
renderXML(userAgent, context, doc, ns);
-
}
-
-
-
}
diff --git a/src/java/org/apache/fop/render/ps/PSTextElementBridge.java b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java
index 3a4604839..515822413 100644
--- a/src/java/org/apache/fop/render/ps/PSTextElementBridge.java
+++ b/src/java/org/apache/fop/render/ps/PSTextElementBridge.java
@@ -50,13 +50,10 @@
*/
package org.apache.fop.render.ps;
-//import org.apache.batik.gvt.TextNode;
import org.apache.batik.bridge.SVGTextElementBridge;
import org.apache.batik.bridge.BridgeContext;
-//import org.apache.batik.bridge.TextUtilities;
import org.apache.batik.gvt.GraphicsNode;
-
-import org.apache.fop.apps.Document;
+import org.apache.batik.gvt.TextNode;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -70,15 +67,15 @@ import org.w3c.dom.Node;
* @version $Id: PSTextElementBridge.java,v 1.2 2003/03/07 09:46:30 jeremias Exp $
*/
public class PSTextElementBridge extends SVGTextElementBridge {
-
- //private PSTextPainter textPainter;
+
+ private PSTextPainter textPainter;
/**
* Constructs a new bridge for the &lt;text> element.
- * @param fi the font infomration
+ * @param textPainter the text painter to use
*/
- public PSTextElementBridge(Document fi) {
- //textPainter = new PSTextPainter(fi);
+ public PSTextElementBridge(PSTextPainter textPainter) {
+ this.textPainter = textPainter;
}
/**
@@ -90,18 +87,17 @@ public class PSTextElementBridge extends SVGTextElementBridge {
*/
public GraphicsNode createGraphicsNode(BridgeContext ctx, Element e) {
GraphicsNode node = super.createGraphicsNode(ctx, e);
- /*
- if (node != null && isSimple(ctx, e, node)) {
+ /* this code is worthless I think. PSTextPainter does a much better job
+ * at determining whether to stroke or not. */
+ if (true/*node != null && isSimple(ctx, e, node)*/) {
((TextNode)node).setTextPainter(getTextPainter());
- }*/
+ }
return node;
}
- /*
private PSTextPainter getTextPainter() {
- return textPainter;
+ return this.textPainter;
}
- */
/**
* Check if text element contains simple text.
@@ -118,16 +114,6 @@ public class PSTextElementBridge extends SVGTextElementBridge {
* easily rendered using normal drawString on the PDFGraphics2D
*/
private boolean isSimple(BridgeContext ctx, Element element, GraphicsNode node) {
- /*
- // Font size, in user space units.
- float fs = TextUtilities.convertFontSize(element).floatValue();
- // PDF cannot display fonts over 36pt
- if (fs > 36) {
- return false;
- }
- */
-
-
for (Node n = element.getFirstChild();
n != null;
n = n.getNextSibling()) {
@@ -136,7 +122,7 @@ public class PSTextElementBridge extends SVGTextElementBridge {
case Node.ELEMENT_NODE:
if (n.getLocalName().equals(SVG_TSPAN_TAG)
- || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) {
+ || n.getLocalName().equals(SVG_ALT_GLYPH_TAG)) {
return false;
} else if (n.getLocalName().equals(SVG_TEXT_PATH_TAG)) {
return false;
@@ -146,6 +132,7 @@ public class PSTextElementBridge extends SVGTextElementBridge {
break;
case Node.TEXT_NODE:
case Node.CDATA_SECTION_NODE:
+ default:
}
}
diff --git a/src/java/org/apache/fop/render/ps/PSTextPainter.java b/src/java/org/apache/fop/render/ps/PSTextPainter.java
index ca12f70ed..5cb30e9d9 100644
--- a/src/java/org/apache/fop/render/ps/PSTextPainter.java
+++ b/src/java/org/apache/fop/render/ps/PSTextPainter.java
@@ -57,6 +57,7 @@ import java.awt.geom.Rectangle2D;
org.apache.fop.fonts.Font */
import java.text.AttributedCharacterIterator;
+import java.text.CharacterIterator;
import java.awt.font.TextAttribute;
import java.awt.Shape;
import java.awt.Paint;
@@ -65,17 +66,18 @@ import java.awt.Color;
import java.util.List;
import java.util.Iterator;
+import org.apache.batik.dom.svg.SVGOMTextElement;
import org.apache.batik.gvt.text.Mark;
import org.apache.batik.gvt.TextPainter;
import org.apache.batik.gvt.TextNode;
import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
import org.apache.batik.gvt.text.TextPaintInfo;
import org.apache.batik.gvt.font.GVTFontFamily;
-import org.apache.batik.bridge.SVGFontFamily;
import org.apache.batik.gvt.renderer.StrokingTextPainter;
import org.apache.fop.fonts.FontMetrics;
import org.apache.fop.fonts.Font;
+import org.apache.fop.svg.ACIUtils;
import org.apache.fop.apps.Document;
/**
@@ -90,24 +92,26 @@ import org.apache.fop.apps.Document;
* (todo) use drawString(AttributedCharacterIterator iterator...) for some
*
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+ * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
* @version $Id: PSTextPainter.java,v 1.15 2003/01/08 14:03:55 jeremias Exp $
*/
public class PSTextPainter implements TextPainter {
- private Document fontInfo;
+
+ private Document document;
/**
* Use the stroking text painter to get the bounds and shape.
* Also used as a fallback to draw the string with strokes.
*/
- protected static final TextPainter PROXY_PAINTER =
- StrokingTextPainter.getInstance();
+ protected static final TextPainter
+ PROXY_PAINTER = StrokingTextPainter.getInstance();
/**
* Create a new PS text painter with the given font information.
- * @param fi the fint info
+ * @param document the context document
*/
- public PSTextPainter(Document fi) {
- fontInfo = fi;
+ public PSTextPainter(Document document) {
+ this.document = document;
}
/**
@@ -120,137 +124,188 @@ public class PSTextPainter implements TextPainter {
// System.out.println("PSText paint");
String txt = node.getText();
Point2D loc = node.getLocation();
-
- AttributedCharacterIterator aci =
- node.getAttributedCharacterIterator();
- // reset position to start of char iterator
- if (aci.getBeginIndex() == aci.getEndIndex()) {
- return;
+
+ if (hasUnsupportedAttributes(node)) {
+ PROXY_PAINTER.paint(node, g2d);
+ } else {
+ paintTextRuns(node.getTextRuns(), g2d, loc);
}
- char ch = aci.first();
- if (ch == AttributedCharacterIterator.DONE) {
- return;
+ }
+
+
+ private boolean hasUnsupportedAttributes(TextNode node) {
+ Iterator i = node.getTextRuns().iterator();
+ while (i.hasNext()) {
+ StrokingTextPainter.TextRun
+ run = (StrokingTextPainter.TextRun)i.next();
+ AttributedCharacterIterator aci = run.getACI();
+ boolean hasUnsupported = hasUnsupportedAttributes(aci);
+ if (hasUnsupported) {
+ return true;
+ }
}
+ return false;
+ }
+ private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
+ boolean hasunsupported = false;
+
TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
-
- if (tpi == null) {
- return;
- }
-
- TextNode.Anchor anchor;
- anchor = (TextNode.Anchor) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+ if ((tpi != null)
+ && ((tpi.strokeStroke != null && tpi.strokePaint != null)
+ || (tpi.strikethroughStroke != null)
+ || (tpi.underlineStroke != null)
+ || (tpi.overlineStroke != null))) {
+ hasunsupported = true;
+ }
- List gvtFonts;
- gvtFonts = (List) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
- Paint forg = tpi.fillPaint;
- Paint strokePaint = tpi.strokePaint;
- Float size = (Float) aci.getAttribute(TextAttribute.SIZE);
- if (size == null) {
- return;
+ //Alpha is not supported
+ Paint foreground = (Paint) aci.getAttribute(TextAttribute.FOREGROUND);
+ if (foreground instanceof Color) {
+ Color col = (Color)foreground;
+ if (col.getAlpha() != 255) {
+ hasunsupported = true;
+ }
}
- Stroke stroke = tpi.strokeStroke;
- /*
- Float xpos = (Float) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.X);
- Float ypos = (Float) aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.Y);
- */
- Float posture = (Float) aci.getAttribute(TextAttribute.POSTURE);
- Float taWeight = (Float) aci.getAttribute(TextAttribute.WEIGHT);
+ Object letSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
+ if (letSpace != null) {
+ hasunsupported = true;
+ }
- boolean useStrokePainter = false;
+ Object wordSpace = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
+ if (wordSpace != null) {
+ hasunsupported = true;
+ }
+
+ Object lengthAdjust = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST);
+ if (lengthAdjust != null) {
+ hasunsupported = true;
+ }
- if (forg instanceof Color) {
- Color col = (Color) forg;
- if (col.getAlpha() != 255) {
- useStrokePainter = true;
- }
- g2d.setColor(col);
+ Object writeMod = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE);
+ if (writeMod != null
+ && !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
+ writeMod)) {
+ hasunsupported = true;
}
- g2d.setPaint(forg);
- g2d.setStroke(stroke);
- if (strokePaint != null) {
- // need to draw using AttributedCharacterIterator
- useStrokePainter = true;
+ Object vertOr = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
+ if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
+ vertOr)) {
+ hasunsupported = true;
}
+
+ Object rcDel = aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER);
+ if (!(rcDel instanceof SVGOMTextElement)) {
+ hasunsupported = true; //Filter spans
+ }
+
+ return hasunsupported;
+ }
- if (hasUnsupportedAttributes(aci)) {
- useStrokePainter = true;
+ /**
+ * Paint a list of text runs on the Graphics2D at a given location.
+ * @param textRuns the list of text runs
+ * @param g2d the Graphics2D to paint to
+ * @param loc the current location of the "cursor"
+ */
+ protected void paintTextRuns(List textRuns, Graphics2D g2d, Point2D loc) {
+ Point2D currentloc = loc;
+ Iterator i = textRuns.iterator();
+ while (i.hasNext()) {
+ StrokingTextPainter.TextRun
+ run = (StrokingTextPainter.TextRun)i.next();
+ currentloc = paintTextRun(run, g2d, currentloc);
}
+ }
- // text contains unsupported information
- if (useStrokePainter) {
- PROXY_PAINTER.paint(node, g2d);
- return;
+ /**
+ * Paint a single text run on the Graphics2D at a given location.
+ * @param run the text run to paint
+ * @param g2d the Graphics2D to paint to
+ * @param loc the current location of the "cursor"
+ * @return the new location of the "cursor" after painting the text run
+ */
+ protected Point2D paintTextRun(StrokingTextPainter.TextRun run, Graphics2D g2d, Point2D loc) {
+ AttributedCharacterIterator aci = run.getACI();
+ return paintACI(aci, g2d, loc);
+ }
+
+ /**
+ * Extract the raw text from an ACI.
+ * @param aci ACI to inspect
+ * @return the extracted text
+ */
+ protected String getText(AttributedCharacterIterator aci) {
+ StringBuffer sb = new StringBuffer(aci.getEndIndex() - aci.getBeginIndex());
+ for (char c = aci.first(); c != CharacterIterator.DONE; c = aci.next()) {
+ sb.append(c);
}
+ return sb.toString();
+ }
- String style = ((posture != null) && (posture.floatValue() > 0.0))
- ? "italic" : "normal";
- int weight = ((taWeight != null)
- && (taWeight.floatValue() > 1.0)) ? Font.BOLD
- : Font.NORMAL;
+ /**
+ * Paint an ACI on a Graphics2D at a given location. The method has to
+ * update the location after painting.
+ * @param aci ACI to paint
+ * @param g2d Graphics2D to paint on
+ * @param loc start location
+ * @return new current location
+ */
+ protected Point2D paintACI(AttributedCharacterIterator aci, Graphics2D g2d, Point2D loc) {
+ //System.out.println("==============================================");
+ //ACIUtils.dumpAttrs(aci);
+
+ aci.first();
- Font fontState = null;
- Document fi = fontInfo;
- boolean found = false;
- String fontFamily = null;
- if (gvtFonts != null) {
- Iterator i = gvtFonts.iterator();
- while (i.hasNext()) {
- GVTFontFamily fam = (GVTFontFamily) i.next();
- if (fam instanceof SVGFontFamily) {
- PROXY_PAINTER.paint(node, g2d);
- return;
- }
- fontFamily = fam.getFamilyName();
- if (fi.hasFont(fontFamily, style, weight)) {
- String fname = fontInfo.fontLookup(fontFamily, style,
- weight);
- FontMetrics metrics = fontInfo.getMetricsFor(fname);
- int fsize = (int)(size.floatValue() * 1000);
- fontState = new Font(fname, metrics, fsize);
- found = true;
- break;
- }
- }
+ updateLocationFromACI(aci, loc);
+
+ TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO);
+
+ if (tpi == null) {
+ return loc;
}
- if (!found) {
- String fname =
- fontInfo.fontLookup("any", style, Font.NORMAL);
- FontMetrics metrics = fontInfo.getMetricsFor(fname);
- int fsize = (int)(size.floatValue() * 1000);
- fontState = new Font(fname, metrics, fsize);
- } else {
- if (g2d instanceof PSGraphics2D) {
- ((PSGraphics2D) g2d).setOverrideFontState(fontState);
- }
+
+ TextNode.Anchor anchor = (TextNode.Anchor)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.ANCHOR_TYPE);
+
+ //Set up font
+ List gvtFonts = (List)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+ Paint foreground = tpi.fillPaint;
+ Paint strokePaint = tpi.strokePaint;
+ Stroke stroke = tpi.strokeStroke;
+
+ Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE);
+ if (fontSize == null) {
+ return loc;
}
- int fStyle = java.awt.Font.PLAIN;
- if (weight == Font.BOLD) {
- if (style.equals("italic")) {
- fStyle = java.awt.Font.BOLD | java.awt.Font.ITALIC;
- } else {
- fStyle = java.awt.Font.BOLD;
- }
- } else {
- if (style.equals("italic")) {
- fStyle = java.awt.Font.ITALIC;
- } else {
- fStyle = java.awt.Font.PLAIN;
- }
+ Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
+ Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT);
+
+ if (foreground instanceof Color) {
+ Color col = (Color)foreground;
+ g2d.setColor(col);
}
- java.awt.Font font = new java.awt.Font(fontFamily, fStyle,
- (int)(fontState.getFontSize() / 1000));
+ g2d.setPaint(foreground);
+ g2d.setStroke(stroke);
+
+ Font font = makeFont(aci);
+ java.awt.Font awtFont = makeAWTFont(aci, font);
- g2d.setFont(font);
+ g2d.setFont(awtFont);
- float advance = getStringWidth(txt, fontState);
+ String txt = getText(aci);
+ float advance = getStringWidth(txt, font);
float tx = 0;
if (anchor != null) {
switch (anchor.getType()) {
@@ -259,51 +314,124 @@ public class PSTextPainter implements TextPainter {
break;
case TextNode.Anchor.ANCHOR_END:
tx = -advance;
+ break;
+ default: //nop
+ }
+ }
+
+ //Finally draw text
+ if (g2d instanceof PSGraphics2D) {
+ ((PSGraphics2D) g2d).setOverrideFont(font);
+ }
+ try {
+ g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
+ } finally {
+ if (g2d instanceof PSGraphics2D) {
+ ((PSGraphics2D) g2d).setOverrideFont(null);
}
}
- g2d.drawString(txt, (float)(loc.getX() + tx), (float)(loc.getY()));
+ loc.setLocation(loc.getX() + (double)advance, loc.getY());
+ return loc;
}
- private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) {
- boolean hasunsupported = false;
- Object letSpace = aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING);
- if (letSpace != null) {
- hasunsupported = true;
+ private void updateLocationFromACI(
+ AttributedCharacterIterator aci,
+ Point2D loc) {
+ //Adjust position of span
+ Float xpos = (Float)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.X);
+ Float ypos = (Float)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.Y);
+ Float dxpos = (Float)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.DX);
+ Float dypos = (Float)aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.DY);
+ if (xpos != null) {
+ loc.setLocation(xpos.doubleValue(), loc.getY());
}
+ if (ypos != null) {
+ loc.setLocation(loc.getX(), ypos.doubleValue());
+ }
+ if (dxpos != null) {
+ loc.setLocation(loc.getX() + dxpos.doubleValue(), loc.getY());
+ }
+ if (dypos != null) {
+ loc.setLocation(loc.getX(), loc.getY() + dypos.doubleValue());
+ }
+ }
- Object wordSpace = aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING);
- if (wordSpace != null) {
- hasunsupported = true;
- }
+ private String getStyle(AttributedCharacterIterator aci) {
+ Float posture = (Float)aci.getAttribute(TextAttribute.POSTURE);
+ return ((posture != null) && (posture.floatValue() > 0.0))
+ ? "italic"
+ : "normal";
+ }
- AttributedCharacterIterator.Attribute key;
- key = GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE;
- Object writeMod = aci.getAttribute(key);
- if (!GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
- writeMod)) {
- hasunsupported = true;
+ private int getWeight(AttributedCharacterIterator aci) {
+ Float taWeight = (Float)aci.getAttribute(TextAttribute.WEIGHT);
+ return ((taWeight != null) && (taWeight.floatValue() > 1.0))
+ ? Font.BOLD
+ : Font.NORMAL;
+ }
+
+ private Font makeFont(AttributedCharacterIterator aci) {
+ Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE);
+ String style = getStyle(aci);
+ int weight = getWeight(aci);
+
+ boolean found = false;
+ String fontFamily = null;
+ List gvtFonts = (List) aci.getAttribute(
+ GVTAttributedCharacterIterator.TextAttribute.GVT_FONT_FAMILIES);
+ if (gvtFonts != null) {
+ Iterator i = gvtFonts.iterator();
+ while (i.hasNext()) {
+ GVTFontFamily fam = (GVTFontFamily) i.next();
+ /* (todo) Enable SVG Font painting
+ if (fam instanceof SVGFontFamily) {
+ PROXY_PAINTER.paint(node, g2d);
+ return;
+ }*/
+ fontFamily = fam.getFamilyName();
+ if (document.hasFont(fontFamily, style, weight)) {
+ String fname = document.fontLookup(
+ fontFamily, style, weight);
+ FontMetrics metrics = document.getMetricsFor(fname);
+ int fsize = (int)(fontSize.floatValue() * 1000);
+ return new Font(fname, metrics, fsize);
+ }
+ }
}
+ String fname = document.fontLookup(
+ "any", style, Font.NORMAL);
+ FontMetrics metrics = document.getMetricsFor(fname);
+ int fsize = (int)(fontSize.floatValue() * 1000);
+ return new Font(fname, metrics, fsize);
+ }
- Object vertOr = aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION);
- if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals(
- vertOr)) {
- hasunsupported = true;
+ private java.awt.Font makeAWTFont(AttributedCharacterIterator aci, Font font) {
+ final String style = getStyle(aci);
+ final int weight = getWeight(aci);
+ int fStyle = java.awt.Font.PLAIN;
+ if (weight == Font.BOLD) {
+ fStyle |= java.awt.Font.BOLD;
}
- return hasunsupported;
+ if ("italic".equals(style)) {
+ fStyle |= java.awt.Font.ITALIC;
+ }
+ return new java.awt.Font(font.getFontName(), fStyle,
+ (int)(font.getFontSize() / 1000));
}
- private float getStringWidth(String str, Font fontState) {
+ private float getStringWidth(String str, Font font) {
float wordWidth = 0;
- float whitespaceWidth = fontState.getWidth(fontState.mapChar(' '));
+ float whitespaceWidth = font.getWidth(font.mapChar(' '));
for (int i = 0; i < str.length(); i++) {
float charWidth;
char c = str.charAt(i);
if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) {
- charWidth = fontState.getWidth(fontState.mapChar(c));
+ charWidth = font.getWidth(font.mapChar(c));
if (charWidth <= 0) {
charWidth = whitespaceWidth;
}
@@ -336,6 +464,9 @@ public class PSTextPainter implements TextPainter {
* @return the bounds of the text
*/
public Rectangle2D getBounds2D(TextNode node) {
+ /* (todo) getBounds2D() is too slow
+ * because it uses the StrokingTextPainter. We should implement this
+ * method ourselves. */
return PROXY_PAINTER.getBounds2D(node);
}
diff --git a/src/java/org/apache/fop/render/ps/PSTranscoder.java b/src/java/org/apache/fop/render/ps/PSTranscoder.java
index 76f2771c9..d85d8d189 100644
--- a/src/java/org/apache/fop/render/ps/PSTranscoder.java
+++ b/src/java/org/apache/fop/render/ps/PSTranscoder.java
@@ -1,5 +1,5 @@
/*
- * $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $
+ * $Id$
* ============================================================================
* The Apache Software License, Version 1.1
* ============================================================================
@@ -51,41 +51,6 @@
package org.apache.fop.render.ps;
-import java.awt.geom.AffineTransform;
-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.ViewBox;
-
-import org.apache.batik.dom.svg.SVGOMDocument;
-
-import org.apache.batik.gvt.GraphicsNode;
-
-import org.apache.batik.transcoder.TranscoderException;
-import org.apache.batik.transcoder.TranscoderOutput;
-import org.apache.batik.transcoder.image.resources.Messages;
-
-import org.apache.batik.transcoder.image.ImageTranscoder;
-
-import org.apache.fop.svg.AbstractFOPTranscoder;
-
-import org.apache.batik.gvt.TextPainter;
-import org.apache.batik.gvt.renderer.StrokingTextPainter;
-
-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.
*
@@ -112,11 +77,9 @@ import org.w3c.dom.svg.SVGSVGElement;
*
* @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
* @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
- * @version $Id: PDFTranscoder.java,v 1.24 2003/03/07 09:51:26 jeremias Exp $
+ * @version $Id$
*/
-public class PSTranscoder extends AbstractFOPTranscoder {
-
- protected PSDocumentGraphics2D graphics = null;
+public class PSTranscoder extends AbstractPSTranscoder {
/**
* Constructs a new <tt>PSTranscoder</tt>.
@@ -125,63 +88,8 @@ public class PSTranscoder extends AbstractFOPTranscoder {
super();
}
- /**
- * 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 {
-
- graphics = new PSDocumentGraphics2D(false);
-
- super.transcode(document, uri, output);
-
- // prepare the image to be painted
- int w = (int)(width+.5);
- int h = (int)(height+.5);
-
- try {
- graphics.setupDocument(output.getOutputStream(), w, h);
- graphics.setSVGDimension(width, height);
-
- 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(curTxf);
-
- this.root.paint(graphics);
-
- graphics.finish();
- } catch (IOException ex) {
- throw new TranscoderException(ex);
- }
- }
-
- protected BridgeContext createBridgeContext() {
- 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());
- return ctx;
+ protected AbstractPSDocumentGraphics2D createDocumentGraphics2D() {
+ return new PSDocumentGraphics2D(false);
}
}
diff --git a/src/java/org/apache/fop/render/ps/PSXMLHandler.java b/src/java/org/apache/fop/render/ps/PSXMLHandler.java
index c500fe9c4..6197c3864 100644
--- a/src/java/org/apache/fop/render/ps/PSXMLHandler.java
+++ b/src/java/org/apache/fop/render/ps/PSXMLHandler.java
@@ -137,6 +137,7 @@ public class PSXMLHandler implements XMLHandler {
SVGHandler svghandler = new SVGHandler();
svghandler.renderSVGDocument(context, doc, psi);
} else {
+ //nop
}
}
@@ -295,7 +296,9 @@ public class PSXMLHandler implements XMLHandler {
GVTBuilder builder = new GVTBuilder();
BridgeContext ctx = new BridgeContext(ua);
- PSTextElementBridge tBridge = new PSTextElementBridge(psInfo.getFontInfo());
+ PSTextPainter textPainter = new PSTextPainter(psInfo.getFontInfo());
+ ctx.setTextPainter(textPainter);
+ PSTextElementBridge tBridge = new PSTextElementBridge(textPainter);
ctx.putBridge(tBridge);
//PSAElementBridge aBridge = new PSAElementBridge();
@@ -305,8 +308,6 @@ public class PSXMLHandler implements XMLHandler {
//aBridge.setCurrentTransform(transform);
//ctx.putBridge(aBridge);
- TextPainter textPainter = new PSTextPainter(psInfo.getFontInfo());
- ctx.setTextPainter(textPainter);
GraphicsNode root;
try {
root = builder.build(ctx, doc);
@@ -327,12 +328,16 @@ public class PSXMLHandler implements XMLHandler {
try {
gen.writeln("%SVG graphic start ---");
+ gen.saveGraphicsState();
/*
* Clip to the svg area.
* Note: To have the svg overlay (under) a text area then use
* an fo:block-container
*/
- gen.saveGraphicsState();
+ gen.writeln("newpath");
+ gen.defineRect(xOffset, yOffset, w, h);
+ gen.writeln("clip");
+
// transform so that the coordinates (0,0) is from the top left
// and positive is down and to the right. (0,0) is where the
// viewBox puts it.
@@ -351,7 +356,8 @@ public class PSXMLHandler implements XMLHandler {
if (psInfo.pdfContext == null) {
psInfo.pdfContext = psInfo.pdfPage;
}*/
- PSGraphics2D graphics = new PSGraphics2D(true, gen);
+ final boolean textAsShapes = false;
+ PSGraphics2D graphics = new PSGraphics2D(textAsShapes, gen);
graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext());
//psInfo.pdfState.push();
transform = new AffineTransform();