Addition of an EPS transcoder git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196990 13f79535-47bb-0310-9956-ffa450edef68pull/30/head
@@ -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); | |||
} | |||
} | |||
@@ -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 <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); | |||
} | |||
} | |||
} |
@@ -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 */ |
@@ -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); | |||
} | |||
} |
@@ -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 <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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
@@ -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"); | |||
} | |||
/** | |||
@@ -359,6 +386,34 @@ public class PSGenerator { | |||
matrix[4], matrix[5]); | |||
} | |||
/** | |||
* 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 |
@@ -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"); |
@@ -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); | |||
} | |||
} |
@@ -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 <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: | |||
} | |||
} | |||
@@ -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); | |||
} | |||
@@ -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); | |||
} | |||
} |
@@ -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(); |