/* * Copyright 1999-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.svg; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilterList; import org.apache.fop.pdf.PDFPage; import org.apache.fop.pdf.PDFStream; import org.apache.fop.pdf.PDFState; import org.apache.fop.pdf.PDFNumber; import org.apache.fop.pdf.PDFResources; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFAnnotList; import org.apache.fop.fonts.FontSetup; import org.apache.fop.fonts.FontInfo; import org.apache.avalon.framework.CascadingRuntimeException; import org.apache.avalon.framework.activity.Initializable; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.commons.logging.impl.SimpleLog; import org.apache.commons.logging.Log; 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.awt.geom.AffineTransform; import java.io.OutputStream; import java.io.IOException; import java.util.List; /** * This class is a wrapper for the PDFGraphics2D that * is used to create a full document around the pdf rendering from * PDFGraphics2D. * * @author Keiron Liddle * @version $Id: PDFDocumentGraphics2D.java,v 1.27 2003/03/07 09:51:26 jeremias Exp $ * @see org.apache.fop.svg.PDFGraphics2D */ public class PDFDocumentGraphics2D extends PDFGraphics2D implements Configurable, Initializable { private PDFPage currentPage; private PDFStream pdfStream; private int width; private int height; private List fontList; private Log logger; //Avalon component private Configuration cfg; /** * Create a new PDFDocumentGraphics2D. * This is used to create a new pdf 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 PDFDocumentGraphics2D(boolean textAsShapes) { super(textAsShapes); if (!textAsShapes) { fontInfo = new FontInfo(); FontSetup.setup(fontInfo, null); //FontState fontState = new FontState("Helvetica", "normal", // FontInfo.NORMAL, 12, 0); } try { initialize(); } catch (Exception e) { //Should never happen throw new CascadingRuntimeException("Internal error", e); } } /** * Create a new PDFDocumentGraphics2D. * This is used to create a new pdf 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 PDFDocumentGraphics2D(boolean textAsShapes, OutputStream stream, int width, int height) throws IOException { this(textAsShapes); setupDocument(stream, width, height); } /** * Create a new PDFDocumentGraphics2D. * This is used to create a new pdf document. * 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. * This constructor is Avalon-style. */ public PDFDocumentGraphics2D() { super(false); } public void setLogger(Log logger) { this.logger = logger; } /** * Returns the logger. * @return Logger the logger */ protected final Log getLogger() { if (this.logger == null) { this.logger = new SimpleLog("FOP/PDF"); ((SimpleLog) logger).setLevel(SimpleLog.LOG_LEVEL_INFO); } return this.logger; } /** * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration) */ public void configure(Configuration cfg) throws ConfigurationException { this.cfg = cfg; this.fontList = FontSetup.buildFontListFromConfiguration(cfg); } /** * @see org.apache.avalon.framework.activity.Initializable#initialize() */ public void initialize() throws Exception { if (this.fontInfo == null) { fontInfo = new FontInfo(); FontSetup.setup(fontInfo, this.fontList); //FontState fontState = new FontState("Helvetica", "normal", // FontInfo.NORMAL, 12, 0); } this.pdfDoc = new PDFDocument("Apache FOP: SVG to PDF Transcoder"); if (this.cfg != null) { this.pdfDoc.setFilterMap( PDFFilterList.buildFilterMapFromConfiguration(cfg)); } graphicsState = new PDFState(); currentFontName = ""; currentFontSize = 0; pdfStream = this.pdfDoc.getFactory().makeStream(PDFFilterList.CONTENT_FILTER, false); } /** * 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; PDFResources pdfResources = this.pdfDoc.getResources(); currentPage = this.pdfDoc.getFactory().makePage(pdfResources, width, height); resourceContext = currentPage; pageRef = currentPage.referencePDF(); currentStream.write("1 0 0 -1 0 " + height + " cm\n"); graphicsState.setTransform(new AffineTransform(1.0, 0.0, 0.0, -1.0, 0.0, (double)height)); pdfDoc.outputHeader(stream); setOutputStream(stream); } /** * Get the font info for this pdf document. * @return the font information */ public FontInfo getFontInfo() { return fontInfo; } /** * Get the pdf document created by this class. * @return the pdf document */ public PDFDocument getPDFDocument() { return this.pdfDoc; } /** * 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 pdf document that is to be created. * The result is scaled so that the svg fits correctly inside the * pdf document. * @param w the width of the page * @param h the height of the page */ public void setSVGDimension(float w, float h) { currentStream.write("" + PDFNumber.doubleOut(width / w) + " 0 0 " + PDFNumber.doubleOut(height / h) + " 0 0 cm\n"); } /** * Set the background of the pdf document. * This is used to set the background for the pdf document * Rather than leaving it as the default white. * @param col the background colour to fill */ public void setBackgroundColor(Color col) { Color c = col; PDFColor currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); currentStream.write("q\n"); currentStream.write(currentColour.getColorSpaceOut(true)); currentStream.write("0 0 " + width + " " + height + " re\n"); currentStream.write("f\n"); currentStream.write("Q\n"); } /** * The rendering process has finished. * This should be called after the rendering has completed as there is * no other indication it is complete. * This will then write the results to the output stream. * @throws IOException an io exception if there is a problem * writing to the output stream */ public void finish() throws IOException { // restorePDFState(); pdfStream.add(getString()); this.pdfDoc.registerObject(pdfStream); currentPage.setContents(pdfStream); PDFAnnotList annots = currentPage.getAnnotations(); if (annots != null) { this.pdfDoc.addObject(annots); } this.pdfDoc.addObject(currentPage); if (fontInfo != null) { pdfDoc.getResources().addFonts(pdfDoc, fontInfo); } this.pdfDoc.output(outputStream); pdfDoc.outputTrailer(outputStream); outputStream.flush(); } /** * This constructor supports the create method * @param g the pdf document graphics to make a copy of */ public PDFDocumentGraphics2D(PDFDocumentGraphics2D g) { super(g); } /** * Creates a new Graphics object that is * a copy of this Graphics object. * @return a new graphics context that is a copy of * this graphics context. */ public Graphics create() { return new PDFDocumentGraphics2D(this); } /** * Draw a string to the pdf 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); } } }