浏览代码

Substantial refactoring of the PS transcoder (especially the text painting, less painting using the StrokingTextPainter, therefore more speed and smaller output files)

Addition of an EPS transcoder


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@196990 13f79535-47bb-0310-9956-ffa450edef68
pull/30/head
Jeremias Maerki 20 年前
父节点
当前提交
eeb5c41112

+ 293
- 0
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);
}

}


+ 195
- 0
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);
}
}


}

+ 3
- 0
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 */

+ 124
- 0
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);
}

}

+ 94
- 0
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);
}

}

+ 52
- 147
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);
}
}

}


+ 69
- 14
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");
}
/**
@@ -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

+ 350
- 334
src/java/org/apache/fop/render/ps/PSGraphics2D.java
文件差异内容过多而无法显示
查看文件


+ 8
- 0
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");

+ 29
- 50
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);

}




}

+ 13
- 26
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:
}
}


+ 272
- 141
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);
}


+ 5
- 97
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);
}

}

+ 11
- 5
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();

正在加载...
取消
保存