diff options
-rw-r--r-- | src/org/apache/fop/render/ps/PSXMLHandler.java | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/org/apache/fop/render/ps/PSXMLHandler.java b/src/org/apache/fop/render/ps/PSXMLHandler.java new file mode 100644 index 000000000..6601a43bd --- /dev/null +++ b/src/org/apache/fop/render/ps/PSXMLHandler.java @@ -0,0 +1,301 @@ +/* + * $Id$ + * Copyright (C) 2001-2003 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + */ + +package org.apache.fop.render.ps; + +import org.apache.fop.render.XMLHandler; +import org.apache.fop.render.RendererContext; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFPage; +import org.apache.fop.pdf.PDFState; +import org.apache.fop.pdf.PDFStream; +import org.apache.fop.pdf.PDFNumber; +import org.apache.fop.pdf.PDFResourceContext; +import org.apache.fop.svg.PDFTextElementBridge; +import org.apache.fop.svg.PDFAElementBridge; +import org.apache.fop.svg.PDFGraphics2D; +import org.apache.fop.svg.SVGUserAgent; +import org.apache.fop.layout.FontInfo; + +import org.w3c.dom.Document; + +import java.io.OutputStream; + +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.ViewBox; + +import org.apache.batik.gvt.GraphicsNode; + +import org.w3c.dom.svg.SVGDocument; +import org.w3c.dom.svg.SVGSVGElement; + +import java.awt.geom.AffineTransform; + +/** + * PostScript XML handler. + * This handler handles XML for foreign objects when rendering to PostScript. + * It renders SVG to the PostScript document using the PSGraphics2D. + * The properties from the PostScript renderer are subject to change. + * + * @author <a href="mailto:fop-dev@xml.apache.org">Apache XML FOP Development Team</a> + * @version $Id$ + */ +public class PSXMLHandler implements XMLHandler { + /** + * The PDF document that is being drawn into. + */ + public static final String PDF_DOCUMENT = "pdfDoc"; + + /** + * The output stream that the document is being sent to. + */ + public static final String OUTPUT_STREAM = "outputStream"; + + /** + * The current pdf state. + */ + public static final String PDF_STATE = "pdfState"; + + /** + * The current PDF page for page renference and as a resource context. + */ + public static final String PDF_PAGE = "pdfPage"; + + /** + * The current PDF page for page renference and as a resource context. + */ + public static final String PDF_CONTEXT = "pdfContext"; + + /** + * The current PDF stream to draw directly to. + */ + public static final String PDF_STREAM = "pdfStream"; + + /** + * The width of the current pdf page. + */ + public static final String PDF_WIDTH = "width"; + + /** + * The height of the current pdf page. + */ + public static final String PDF_HEIGHT = "height"; + + /** + * The current font information for the pdf renderer. + */ + public static final String PDF_FONT_INFO = "fontInfo"; + + /** + * The current pdf font name. + */ + public static final String PDF_FONT_NAME = "fontName"; + + /** + * The current pdf font size. + */ + public static final String PDF_FONT_SIZE = "fontSize"; + + /** + * The x position that this is being drawn at. + */ + public static final String PDF_XPOS = "xpos"; + + /** + * The y position that this is being drawn at. + */ + public static final String PDF_YPOS = "ypos"; + + /** + * Create a new PDF XML handler for use by the PDF renderer. + */ + public PSXMLHandler() { + } + + /** + * Handle the XML. + * This checks the type of XML and handles appropraitely. + * + * @param context the renderer context + * @param doc the XML document to render + * @param ns the namespace of the XML document + * @throws Exception any sort of exception could be thrown and shuld be handled + */ + public void handleXML(RendererContext context, Document doc, + String ns) throws Exception { + PSInfo psi = getPSInfo(context); + + String svg = "http://www.w3.org/2000/svg"; + if (svg.equals(ns)) { + SVGHandler svghandler = new SVGHandler(); + svghandler.renderSVGDocument(context, doc, psi); + } else { + } + } + + /** + * Get the pdf information from the render context. + * + * @param context the renderer context + * @return the pdf information retrieved from the context + */ + public static PSInfo getPSInfo(RendererContext context) { + PSInfo psi = new PSInfo(); + /* + pdfi.pdfDoc = (PDFDocument)context.getProperty(PDF_DOCUMENT); + pdfi.outputStream = (OutputStream)context.getProperty(OUTPUT_STREAM); + pdfi.pdfState = (PDFState)context.getProperty(PDF_STATE); + pdfi.pdfPage = (PDFPage)context.getProperty(PDF_PAGE); + pdfi.pdfContext = (PDFResourceContext)context.getProperty(PDF_CONTEXT); + pdfi.currentStream = (PDFStream)context.getProperty(PDF_STREAM); + pdfi.width = ((Integer)context.getProperty(PDF_WIDTH)).intValue(); + pdfi.height = ((Integer)context.getProperty(PDF_HEIGHT)).intValue(); + pdfi.fi = (FontInfo)context.getProperty(PDF_FONT_INFO); + pdfi.currentFontName = (String)context.getProperty(PDF_FONT_NAME); + pdfi.currentFontSize = ((Integer)context.getProperty(PDF_FONT_SIZE)).intValue(); + pdfi.currentXPosition = ((Integer)context.getProperty(PDF_XPOS)).intValue(); + pdfi.currentYPosition = ((Integer)context.getProperty(PDF_YPOS)).intValue(); + */ + return psi; + } + + /** + * PostScript information structure for drawing the XML document. + */ + public static class PSInfo { + + /** see PDF_DOCUMENT */ + public PDFDocument pdfDoc; + /** see OUTPUT_STREAM */ + public OutputStream outputStream; + /** see PDF_STATE */ + public PDFState pdfState; + /** see PDF_PAGE */ + public PDFPage pdfPage; + /** see PDF_CONTEXT */ + public PDFResourceContext pdfContext; + /** see PDF_STREAM */ + public PDFStream currentStream; + /** see PDF_WIDTH */ + public int width; + /** see PDF_HEIGHT */ + public int height; + /** see PDF_FONT_INFO */ + public FontInfo fi; + /** see PDF_FONT_NAME */ + public String currentFontName; + /** see PDF_FONT_SIZE */ + public int currentFontSize; + /** see PDF_XPOS */ + public int currentXPosition; + /** see PDF_YPOS */ + public int currentYPosition; + } + + /** + * This method is placed in an inner class so that we don't get class + * loading errors if batik is not present. + */ + protected class SVGHandler { + /** + * Render the svg document. + * @param context the renderer context + * @param doc the svg document + * @param pdfInfo the pdf information of the current context + */ + protected void renderSVGDocument(RendererContext context, Document doc, PSInfo psInfo) { + int xOffset = psInfo.currentXPosition; + int yOffset = psInfo.currentYPosition; + + SVGUserAgent ua + = new SVGUserAgent(context.getUserAgent(), new AffineTransform()); + + GVTBuilder builder = new GVTBuilder(); + BridgeContext ctx = new BridgeContext(ua); + PDFTextElementBridge tBridge = new PDFTextElementBridge(psInfo.fi); + ctx.putBridge(tBridge); + + PDFAElementBridge aBridge = new PDFAElementBridge(); + // to get the correct transform we need to use the PDFState + AffineTransform transform = psInfo.pdfState.getTransform(); + transform.translate(xOffset / 1000f, yOffset / 1000f); + aBridge.setCurrentTransform(transform); + ctx.putBridge(aBridge); + + GraphicsNode root; + try { + root = builder.build(ctx, doc); + } catch (Exception e) { + context.getUserAgent().getLogger().error("svg graphic could not be built: " + + e.getMessage(), e); + return; + } + // get the 'width' and 'height' attributes of the SVG document + float w = (float)ctx.getDocumentSize().getWidth() * 1000f; + float h = (float)ctx.getDocumentSize().getHeight() * 1000f; + + float sx = psInfo.width / (float)w; + float sy = psInfo.height / (float)h; + + ctx = null; + builder = null; + + /* + * Clip to the svg area. + * Note: To have the svg overlay (under) a text area then use + * an fo:block-container + */ + psInfo.currentStream.add("q\n"); + // 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. + psInfo.currentStream.add(sx + " 0 0 " + sy + " " + xOffset / 1000f + " " + + yOffset / 1000f + " cm\n"); + + SVGSVGElement svg = ((SVGDocument)doc).getRootElement(); + AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg, w / 1000f, h / 1000f); + if (!at.isIdentity()) { + double[] vals = new double[6]; + at.getMatrix(vals); + psInfo.currentStream.add(PDFNumber.doubleOut(vals[0], 5) + " " + + PDFNumber.doubleOut(vals[1], 5) + " " + + PDFNumber.doubleOut(vals[2], 5) + " " + + PDFNumber.doubleOut(vals[3], 5) + " " + + PDFNumber.doubleOut(vals[4]) + " " + + PDFNumber.doubleOut(vals[5]) + " cm\n"); + } + + if (psInfo.pdfContext == null) { + psInfo.pdfContext = psInfo.pdfPage; + } + PDFGraphics2D graphics = new PDFGraphics2D(true, psInfo.fi, psInfo.pdfDoc, + psInfo.pdfContext, psInfo.pdfPage.referencePDF(), + psInfo.currentFontName, + psInfo.currentFontSize); + graphics.setGraphicContext(new org.apache.batik.ext.awt.g2d.GraphicContext()); + psInfo.pdfState.push(); + transform = new AffineTransform(); + // scale to viewbox + transform.translate(xOffset / 1000f, yOffset / 1000f); + psInfo.pdfState.setTransform(transform); + graphics.setPDFState(psInfo.pdfState); + graphics.setOutputStream(psInfo.outputStream); + try { + root.paint(graphics); + psInfo.currentStream.add(graphics.getString()); + } catch (Exception e) { + context.getUserAgent().getLogger().error("svg graphic could not be rendered: " + + e.getMessage(), e); + } + + psInfo.currentStream.add("Q\n"); + psInfo.pdfState.pop(); + } + } +} + |