/* * Copyright 1999-2006 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.render.ps; //Java 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.fonts.FontInfo; import org.apache.fop.fonts.FontSetup; /** * This class is a wrapper for the PSGraphics2D that * is used to create a full document around the PostScript rendering from * PSGraphics2D. * * @author Keiron Liddle * @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 float viewportWidth; protected float viewportHeight; 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) { fontInfo = new FontInfo(); FontSetup.setup(fontInfo, null, 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); } /** * 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 { this.viewportWidth = w; this.viewportHeight = h; /* 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(); if ((this.viewportWidth != this.width || this.viewportHeight != this.height) && (this.viewportWidth > 0) && (this.viewportHeight > 0)){ gen.concatMatrix(this.width / this.viewportWidth, 0, 0, -1 * (this.height / this.viewportHeight), 0, this.height); } else { gen.concatMatrix(1, 0, 0, -1, 0, this.height); } 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); } }