From: Jeremias Maerki Date: Mon, 27 Jan 2003 09:17:04 +0000 (+0000) Subject: First step at bringing back the PostScript renderer. Basic text works to a X-Git-Tag: Alt-Design-integration-base~148 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=822751b4776a30a796faa68af8adc89c5a0a60ba;p=xmlgraphics-fop.git First step at bringing back the PostScript renderer. Basic text works to a certain degree. Well, it compiles. :-) Started to factor out PS generation for cleaner separation of PS transcoder and PS renderer Separation of PostScript procsets so they don't clutter the code of PSRenderer. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@195894 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/org/apache/fop/render/ps/DSCConstants.java b/src/org/apache/fop/render/ps/DSCConstants.java new file mode 100644 index 000000000..49825896d --- /dev/null +++ b/src/org/apache/fop/render/ps/DSCConstants.java @@ -0,0 +1,158 @@ +/* + * $Id$ + * Copyright (C) 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; + +/** + * This class defines constants with Strings for the DSC specification. + * + * @author Apache XML FOP Development Team + * @author Jeremias Maerki + * @version $Id$ + */ +public class DSCConstants { + + // ----==== General Header Comments ====---- + + /** Lead-in for a DSC-conformant PostScript file */ + public static final String PS_ADOBE_30 = "%!PS-Adobe-3.0"; + + /** Bounding box for the document */ + public static final String BBOX = "BoundingBox"; + /** Copyright information associated with the document or resource */ + public static final String COPYRIGHT = "Copyright"; + /** Creator of the document */ + public static final String CREATOR = "Creator"; + /** Date and time when the document was created */ + public static final String CREATION_DATE = "CreationDate"; + /** Type of data */ + public static final String DOCUMENT_DATA = "BoundingBox"; + /** Use for inidicating an emulator being invoked in the document */ + public static final String EMULATION = "Emulation"; + /** Explicit end of comments */ + public static final String END_COMMENTS = "EndComments"; + /** Required PostScript Level 1 extension for this document */ + public static final String EXTENSIONS = "Extensions"; + /** Indicates who is this document printed for */ + public static final String FOR = "For"; + /** Indicates the PostScript language level used in the document */ + public static final String LANGUAGE_LEVEL = "LanguageLevel"; + /** Indicates the orientation of the document */ + public static final String ORIENTATION = "Orientation"; + /** Number of pages in the document */ + public static final String PAGES = "Pages"; + /** Indicates the order of the pages */ + public static final String PAGE_ORDER = "PageOrder"; + /** Indicates how the document should be routed back to its owner */ + public static final String ROUTING = "Routing"; + /** Title of the document */ + public static final String TITLE = "Title"; + /** Version of the document */ + public static final String VERSION = "Version"; + + // ----==== General Body Comments ====---- + + /** Indicates a continued line */ + public static final String NEXT_LINE = "+ "; + + //Skipping BeginBinary/EndBinary. They are deprecated. + + /** Indicates the start of a data section*/ + public static final String BEGIN_DATA = "BeginData"; + /** Indicates the end of a data section*/ + public static final String END_DATA = "EndData"; + + /** Indicates the start of the defaults section */ + public static final String BEGIN_DEFAULTS = "BeginDefaults"; + /** Indicates the end of the defaults section */ + public static final String END_DEFAULTS = "EndDefaults"; + + /** Indicates the start of a non-PostScript section */ + public static final String BEGIN_EMULATION = "BeginEmulation"; + /** Indicates the end of a non-PostScript section */ + public static final String END_EMULATION = "EndEmulation"; + + /** Indicates the start of a preview section (EPS only)*/ + public static final String BEGIN_PREVIEW = "BeginPreview"; + /** Indicates the end of a preview section (EPS only)*/ + public static final String END_PREVIEW = "EndPreview"; + + /** Indicates the start of the prolog */ + public static final String BEGIN_PROLOG = "BeginProlog"; + /** Indicates the end of the prolog */ + public static final String END_PROLOG = "EndProlog"; + + /** Indicates the start of the document setup */ + public static final String BEGIN_SETUP = "BeginSetup"; + /** Indicates the end of the document setup */ + public static final String END_SETUP = "EndSetup"; + + + // ----==== General Page Comments ====---- + + /** Indicates the start of a graphic object */ + public static final String BEGIN_OBJECT = "BeginObject"; + /** Indicates the end of a graphic object */ + public static final String END_OBJECT = "EndObject"; + + /** Indicates the start of the page setup section */ + public static final String BEGIN_PAGE_SETUP = "BeginPageSetup"; + /** Indicates the end of the page setup section */ + public static final String END_PAGE_SETUP = "EndPageSetup"; + + /** Indicates a page number */ + public static final String PAGE = "Page"; + /** Bounding box for a page */ + public static final String PAGE_BBOX = "PageBoundingBox"; + /** Bounding box for a page */ + public static final String PAGE_ORIENTATION = "PageOrientation"; + + + // ----==== General Trailer Comments ====---- + + /** Indicates the start of the page trailer */ + public static final String PAGE_TRAILER = "PageTrailer"; + /** Indicates the start of the document trailer */ + public static final String TRAILER = "Trailer"; + /** Indicates the end of a page (NON-STANDARD!) */ + public static final String END_PAGE = "EndPage"; + /** Indicates the end of the document */ + public static final String EOF = "EOF"; + + + // ----==== Requirements Conventions ====---- + + /**@todo Add the missing comments */ + + // ----==== Requirement Body Comments ====---- + + /** Indicates the start of an embedded document */ + public static final String BEGIN_DOCUMENT = "BeginDocument"; + /** Indicates the end of an embedded document */ + public static final String END_DOCUMENT = "EndDocument"; + /** Indicates a referenced embedded document */ + public static final String INCLUDE_DOCUMENT = "IncludeDocument"; + + /** Indicates the start of a PPD feature */ + public static final String BEGIN_FEATURE = "BeginFeature"; + /** Indicates the end of a PPD feature */ + public static final String END_FEATURE = "EndFeature"; + /** Indicates a referenced a PPD feature */ + public static final String INCLUDE_FEATURE = "IncludeFeature"; + + //Skipping BeginFile/EndFile/IncludeFile. They are deprecated. + //Skipping BeginFont/EndFont/IncludeFont. They are deprecated. + //Skipping BeginProcSet/EndProcSet/IncludeProcSet. They are deprecated. + + /** Indicates the start of a resource (font, file, procset) */ + public static final String BEGIN_RESOURCE = "BeginResource"; + /** Indicates the end of a resource (font, file, procset) */ + public static final String END_RESOURCE = "EndResource"; + /** Indicates a referenced a resource (font, file, procset) */ + public static final String INCLUDE_RESOURCE = "IncludeResource"; + + +} diff --git a/src/org/apache/fop/render/ps/PSGenerator.java b/src/org/apache/fop/render/ps/PSGenerator.java new file mode 100644 index 000000000..3181f203d --- /dev/null +++ b/src/org/apache/fop/render/ps/PSGenerator.java @@ -0,0 +1,259 @@ +/* + * $Id$ + * Copyright (C) 2001-2002 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 java.io.OutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; + +/** + * This class is used to output PostScript code to an OutputStream. + * + * @author Apache XML FOP Development Team + * @author Jeremias Maerki + * @version $Id$ + */ +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() {}; + + private OutputStream out; + + private StringBuffer tempBuffer = new StringBuffer(256); + + /** @see java.io.FilterOutputStream **/ + public PSGenerator(OutputStream out) { + this.out = out; + } + + /** + * Writes a newline character to the OutputStream. + * + * @throws IOException In case of an I/O problem + */ + public final void newLine() throws IOException { + out.write('\n'); + } + + /** + * Formats a double value for PostScript output. + * + * @param value value to format + * @return the formatted value + */ + public String formatDouble(double value) { + NumberFormat nf = new java.text.DecimalFormat("0.#"); + return nf.format(value); + } + + /** + * Writes a PostScript command to the stream. + * + * @param cmd The PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void write(String cmd) throws IOException { + if (cmd.length() > 255) { + throw new RuntimeException("PostScript command exceeded limit of 255 characters"); + } + out.write(cmd.getBytes("US-ASCII")); + } + + /** + * Writes a PostScript command to the stream and ends the line. + * + * @param cmd The PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void writeln(String cmd) throws IOException { + write(cmd); + newLine(); + } + + /** + * Writes encoded data to the PostScript stream. + * + * @param cmd The encoded PostScript code to be written. + * @exception IOException In case of an I/O problem + */ + public void writeByteArr(byte[] cmd) throws IOException { + out.write(cmd); + newLine(); + } + + + /** + * Flushes the OutputStream. + * + * @exception IOException In case of an I/O problem + */ + public void flush() throws IOException { + out.flush(); + } + + + /** + * Escapes a character conforming to the rules established in the PostScript + * Language Reference (Search for "Literal Text Strings"). + * @param c character to escape + * @param target target StringBuffer to write the escaped character to + */ + public static final void escapeChar(char c, StringBuffer target) { + if (c > 127) { + target.append("\\"); + target.append(Integer.toOctalString(c)); + } else { + switch (c) { + case '\n': + target.append("\\n"); + break; + case '\r': + target.append("\\r"); + break; + case '\t': + target.append("\\t"); + break; + case '\b': + target.append("\\b"); + break; + case '\f': + target.append("\\f"); + break; + case '\\': + target.append("\\\\"); + break; + case '(': + target.append("\\("); + break; + case ')': + target.append("\\)"); + break; + default: + target.append(c); + } + } + } + + + /** + * Converts text by applying escaping rules established in the DSC specs. + * @param text Text to convert + * @return String The resulting String + */ + public static final String convertStringToDSC(String text) { + return convertStringToDSC(text, false); + } + + + /** + * Converts text by applying escaping rules established in the DSC specs. + * @param text Text to convert + * @param forceParentheses Force the use of parentheses + * @return String The resulting String + */ + public static final String convertStringToDSC(String text, + boolean forceParentheses) { + if ((text == null) || (text.length() == 0)) { + return "()"; + } else { + int initialSize = text.length(); + initialSize += initialSize / 2; + StringBuffer sb = new StringBuffer(initialSize); + if ((Long.getLong(text) != null) + || (text.indexOf(" ") >= 0) + || forceParentheses) { + + sb.append("("); + for (int i = 0; i < text.length(); i++) { + final char c = text.charAt(i); + escapeChar(c, sb); + } + sb.append(")"); + return sb.toString(); + } else { + return text; + } + } + } + + + /** + * Writes a DSC comment to the output stream. + * @param name Name of the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name) throws IOException { + writeln("%%" + name); + } + + + /** + * Writes a DSC comment to the output stream. The parameter to the DSC + * comment can be any object. The object is converted to a String as + * necessary. + * @param name Name of the DSC comment + * @param param Single parameter to the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name, Object param) throws IOException { + writeDSCComment(name, new Object[] {param}); + } + + + /** + * Writes a DSC comment to the output stream. The parameters to the DSC + * comment can be any object. The objects are converted to Strings as + * necessary. Please see the source code to find out what parameters are + * currently supported. + * @param name Name of the DSC comment + * @param params Array of parameters to the DSC comment + * @exception IOException In case of an I/O problem + * @see org.apache.fop.render.ps.DSCConstants + */ + public void writeDSCComment(String name, Object[] params) throws IOException { + tempBuffer.setLength(0); + tempBuffer.append("%%"); + tempBuffer.append(name); + if ((params != null) && (params.length > 0)) { + tempBuffer.append(": "); + for (int i = 0; i < params.length; i++) { + if (i > 0) { + tempBuffer.append(" "); + } + + if (params[i] instanceof String) { + tempBuffer.append(convertStringToDSC((String)params[i])); + } else if (params[i] instanceof AtendIndicator) { + tempBuffer.append("(atend)"); + } 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]))); + } else { + throw new IllegalArgumentException("Unsupported parameter type: " + + params[i].getClass().getName()); + } + } + } + writeln(tempBuffer.toString()); + } + + + /** Used for the ATEND constant. See there. */ + private static interface AtendIndicator { + } + +} diff --git a/src/org/apache/fop/render/ps/PSGraphics2D.java b/src/org/apache/fop/render/ps/PSGraphics2D.java index 58d732f25..93b2d78f0 100644 --- a/src/org/apache/fop/render/ps/PSGraphics2D.java +++ b/src/org/apache/fop/render/ps/PSGraphics2D.java @@ -37,13 +37,11 @@ import java.awt.image.ImageObserver; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; +import java.io.IOException; // FOP import org.apache.fop.layout.FontInfo; import org.apache.fop.layout.FontState; -import org.apache.fop.pdf.PDFColor; -//import org.apache.fop.pdf.PDFColorSpace; -import org.apache.fop.pdf.PDFNumber; // Batik import org.apache.batik.ext.awt.g2d.AbstractGraphics2D; @@ -67,9 +65,9 @@ public class PSGraphics2D extends AbstractGraphics2D { private boolean standalone = false; /** - * the PDF Document being created + * the PostScript genertaor being created */ - protected PSRenderer psRenderer; + protected PSGenerator gen; /** Currently valid FontState */ protected FontState fontState; @@ -97,7 +95,7 @@ public class PSGraphics2D extends AbstractGraphics2D { /** * the current colour for use in svg */ - protected PDFColor currentColour = new PDFColor(0, 0, 0); + protected Color currentColour = new Color(0, 0, 0); /** FontInfo containing all available fonts */ protected FontInfo fontInfo; @@ -106,17 +104,17 @@ public class PSGraphics2D extends AbstractGraphics2D { * Create a new Graphics2D that generates PostScript code. * @param textAsShapes True if text should be rendered as graphics * @param fs currently valid FontState object - * @param ren PostScript renderer + * @param gen PostScript generator to use for output * @param font current font name * @param size current font size * @param xpos current x pos * @param ypos current y pos * @see org.apache.batik.ext.awt.g2d.AbstractGraphics2D#AbstractGraphics2D(boolean) */ - public PSGraphics2D(boolean textAsShapes, FontState fs, PSRenderer ren, + public PSGraphics2D(boolean textAsShapes, FontState fs, PSGenerator gen, String font, int size, int xpos, int ypos) { super(textAsShapes); - psRenderer = ren; + this.gen = gen; currentFontName = font; currentFontSize = size; currentYPosition = ypos; @@ -158,6 +156,14 @@ public class PSGraphics2D extends AbstractGraphics2D { return new PSGraphics2D(this); } + /** + * Central handler for IOExceptions for this class. + * @param ioe IOException to handle + */ + protected void handleIOException(IOException ioe) { + ioe.printStackTrace(); + } + /** * Draws as much of the specified image as is currently available. * The image is drawn with its top-left corner at @@ -441,7 +447,7 @@ public class PSGraphics2D extends AbstractGraphics2D { */ public void dispose() { // System.out.println("dispose"); - psRenderer = null; + this.gen = null; fontState = null; currentFontName = null; currentColour = null; @@ -465,58 +471,62 @@ public class PSGraphics2D extends AbstractGraphics2D { * @see #setComposite */ public void draw(Shape s) { - // System.out.println("draw(Shape)"); - psRenderer.write("gsave"); - Shape imclip = getClip(); - writeClip(imclip); - Color c = getColor(); - psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); - - applyPaint(getPaint(), false); - applyStroke(getStroke()); - - psRenderer.write("newpath"); - PathIterator iter = s.getPathIterator(getTransform()); - while (!iter.isDone()) { - double vals[] = new double[6]; - int type = iter.currentSegment(vals); - switch (type) { - case PathIterator.SEG_CUBICTO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) + " " - + PDFNumber.doubleOut(1000 * vals[2]) + " " - + PDFNumber.doubleOut(1000 * vals[3]) + " " - + PDFNumber.doubleOut(1000 * vals[4]) + " " - + PDFNumber.doubleOut(1000 * vals[5]) - + " curveto"); - break; - case PathIterator.SEG_LINETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " lineto"); - break; - case PathIterator.SEG_MOVETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " M"); - break; - case PathIterator.SEG_QUADTO: - // psRenderer.write((1000 * PDFNumber.doubleOut(vals[0])) + - // " " + (1000 * PDFNumber.doubleOut(vals[1])) + " " + - // (1000 * PDFNumber.doubleOut(vals[2])) + " " + - // (1000 * PDFNumber.doubleOut(vals[3])) + " y\n"); - break; - case PathIterator.SEG_CLOSE: - psRenderer.write("closepath"); - break; - default: - break; + try { + // System.out.println("draw(Shape)"); + gen.writeln("gsave"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + + " setrgbcolor"); + + applyPaint(getPaint(), false); + applyStroke(getStroke()); + + gen.writeln("newpath"); + PathIterator iter = s.getPathIterator(getTransform()); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + // psRenderer.write((1000 * PDFNumber.doubleOut(vals[0])) + + // " " + (1000 * PDFNumber.doubleOut(vals[1])) + " " + + // (1000 * PDFNumber.doubleOut(vals[2])) + " " + + // (1000 * PDFNumber.doubleOut(vals[3])) + " y\n"); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); } - iter.next(); + doDrawing(false, true, false); + gen.writeln("grestore"); + } catch (IOException ioe) { + handleIOException(ioe); } - doDrawing(false, true, false); - psRenderer.write("grestore"); } /** @@ -524,47 +534,51 @@ public class PSGraphics2D extends AbstractGraphics2D { * @param s Shape defining the clipping region */ protected void writeClip(Shape s) { - PathIterator iter = s.getPathIterator(getTransform()); - psRenderer.write("newpath"); - while (!iter.isDone()) { - double vals[] = new double[6]; - int type = iter.currentSegment(vals); - switch (type) { - case PathIterator.SEG_CUBICTO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) + " " - + PDFNumber.doubleOut(1000 * vals[2]) + " " - + PDFNumber.doubleOut(1000 * vals[3]) + " " - + PDFNumber.doubleOut(1000 * vals[4]) + " " - + PDFNumber.doubleOut(1000 * vals[5]) - + " curveto"); - break; - case PathIterator.SEG_LINETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " lineto"); - break; - case PathIterator.SEG_MOVETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " M"); - break; - case PathIterator.SEG_QUADTO: - // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + - // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + - // 1000 * PDFNumber.doubleOut(vals[2]) + " " + - // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); - break; - case PathIterator.SEG_CLOSE: - psRenderer.write("closepath"); - break; - default: - break; + try { + PathIterator iter = s.getPathIterator(getTransform()); + gen.writeln("newpath"); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + + // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + + // 1000 * PDFNumber.doubleOut(vals[2]) + " " + + // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); } - iter.next(); + // clip area + gen.writeln("clippath"); + } catch (IOException ioe) { + handleIOException(ioe); } - // clip area - psRenderer.write("clippath"); } /** @@ -609,10 +623,10 @@ public class PSGraphics2D extends AbstractGraphics2D { List someColors = new java.util.ArrayList(); - PDFColor color1 = new PDFColor(c1.getRed(), c1.getGreen(), + Color color1 = new Color(c1.getRed(), c1.getGreen(), c1.getBlue()); someColors.add(color1); - PDFColor color2 = new PDFColor(c2.getRed(), c2.getGreen(), + Color color2 = new Color(c2.getRed(), c2.getGreen(), c2.getBlue()); someColors.add(color2); @@ -627,54 +641,56 @@ public class PSGraphics2D extends AbstractGraphics2D { * @param stroke Stroke object to use */ protected void applyStroke(Stroke stroke) { - if (stroke instanceof BasicStroke) { - BasicStroke bs = (BasicStroke)stroke; - - float[] da = bs.getDashArray(); - if (da != null) { - psRenderer.write("["); - for (int count = 0; count < da.length; count++) { - psRenderer.write("" + (1000 * (int)da[count])); - if (count < da.length - 1) { - psRenderer.write(" "); + try { + if (stroke instanceof BasicStroke) { + BasicStroke bs = (BasicStroke)stroke; + + float[] da = bs.getDashArray(); + if (da != null) { + gen.writeln("["); + for (int count = 0; count < da.length; count++) { + gen.writeln("" + (1000 * (int)da[count])); + if (count < da.length - 1) { + gen.writeln(" "); + } } + gen.writeln("] "); + float offset = bs.getDashPhase(); + gen.writeln((1000 * (int)offset) + " setdash"); } - psRenderer.write("] "); - float offset = bs.getDashPhase(); - psRenderer.write((1000 * (int)offset) + " setdash"); - } - int ec = bs.getEndCap(); - switch (ec) { - case BasicStroke.CAP_BUTT: - psRenderer.write(0 + " setlinecap"); - break; - case BasicStroke.CAP_ROUND: - psRenderer.write(1 + " setlinecap"); - break; - case BasicStroke.CAP_SQUARE: - psRenderer.write(2 + " setlinecap"); - break; - } - - int lj = bs.getLineJoin(); - switch (lj) { - case BasicStroke.JOIN_MITER: - psRenderer.write(0 + " setlinejoin"); - break; - case BasicStroke.JOIN_ROUND: - psRenderer.write(1 + " setlinejoin"); - break; - case BasicStroke.JOIN_BEVEL: - psRenderer.write(2 + " setlinejoin"); - break; + int ec = bs.getEndCap(); + switch (ec) { + case BasicStroke.CAP_BUTT: + gen.writeln(0 + " setlinecap"); + break; + case BasicStroke.CAP_ROUND: + gen.writeln(1 + " setlinecap"); + break; + case BasicStroke.CAP_SQUARE: + gen.writeln(2 + " setlinecap"); + break; + } + + int lj = bs.getLineJoin(); + switch (lj) { + case BasicStroke.JOIN_MITER: + gen.writeln("0 setlinejoin"); + break; + case BasicStroke.JOIN_ROUND: + gen.writeln("1 setlinejoin"); + break; + case BasicStroke.JOIN_BEVEL: + gen.writeln("2 setlinejoin"); + break; + } + float lw = bs.getLineWidth(); + gen.writeln(gen.formatDouble(1000 * lw) + " setlinewidth"); + + float ml = bs.getMiterLimit(); + gen.writeln(gen.formatDouble(1000 * ml) + " setmiterlimit"); } - float lw = bs.getLineWidth(); - psRenderer.write(PDFNumber.doubleOut(1000 * lw) - + " setlinewidth"); - - float ml = bs.getMiterLimit(); - psRenderer.write(PDFNumber.doubleOut(1000 * ml) - + " setmiterlimit"); + } catch (IOException ioe) { + handleIOException(ioe); } } @@ -763,28 +779,32 @@ public class PSGraphics2D extends AbstractGraphics2D { * @see #setClip */ public void drawString(String s, float x, float y) { - System.out.println("drawString(String)"); - psRenderer.write("BT"); - Shape imclip = getClip(); - writeClip(imclip); - Color c = getColor(); - psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); - - AffineTransform trans = getTransform(); - trans.translate(x, y); - double[] vals = new double[6]; - trans.getMatrix(vals); - - psRenderer.write(PDFNumber.doubleOut(vals[0]) + " " - + PDFNumber.doubleOut(vals[1]) + " " - + PDFNumber.doubleOut(vals[2]) + " " - + PDFNumber.doubleOut(vals[3]) + " " - + PDFNumber.doubleOut(vals[4]) + " " - + PDFNumber.doubleOut(vals[5]) + " " - + PDFNumber.doubleOut(vals[6]) + " Tm [" + s + "]"); - - psRenderer.write("ET"); + try { + System.out.println("drawString(String)"); + gen.writeln("BT"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + + " setrgbcolor"); + + AffineTransform trans = getTransform(); + trans.translate(x, y); + double[] vals = new double[6]; + trans.getMatrix(vals); + + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " " + + gen.formatDouble(vals[2]) + " " + + gen.formatDouble(vals[3]) + " " + + gen.formatDouble(vals[4]) + " " + + gen.formatDouble(vals[5]) + " " + + gen.formatDouble(vals[6]) + " Tm [" + s + "]"); + + gen.writeln("ET"); + } catch (IOException ioe) { + handleIOException(ioe); + } } /** @@ -814,38 +834,42 @@ public class PSGraphics2D extends AbstractGraphics2D { */ public void drawString(AttributedCharacterIterator iterator, float x, float y) { - System.err.println("drawString(AttributedCharacterIterator)"); - - psRenderer.write("BT"); - Shape imclip = getClip(); - writeClip(imclip); - Color c = getColor(); - currentColour = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); - psRenderer.write(currentColour.getColorSpaceOut(true)); - c = getBackground(); - PDFColor col = new PDFColor(c.getRed(), c.getGreen(), c.getBlue()); - psRenderer.write(col.getColorSpaceOut(false)); - - AffineTransform trans = getTransform(); - trans.translate(x, y); - double[] vals = new double[6]; - trans.getMatrix(vals); - - for (char ch = iterator.first(); ch != CharacterIterator.DONE; - ch = iterator.next()) { - //Map attr = iterator.getAttributes(); - - psRenderer.write(PDFNumber.doubleOut(vals[0]) + " " - + PDFNumber.doubleOut(vals[1]) + " " - + PDFNumber.doubleOut(vals[2]) + " " - + PDFNumber.doubleOut(vals[3]) + " " - + PDFNumber.doubleOut(vals[4]) + " " - + PDFNumber.doubleOut(vals[5]) + " " - + PDFNumber.doubleOut(vals[6]) + " Tm [" + ch - + "]"); + try { + System.err.println("drawString(AttributedCharacterIterator)"); + + gen.writeln("BT"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + currentColour = new Color(c.getRed(), c.getGreen(), c.getBlue()); + //gen.writeln(currentColour.getColorSpaceOut(true)); + c = getBackground(); + Color col = new Color(c.getRed(), c.getGreen(), c.getBlue()); + //gen.writeln(col.getColorSpaceOut(false)); + + AffineTransform trans = getTransform(); + trans.translate(x, y); + double[] vals = new double[6]; + trans.getMatrix(vals); + + for (char ch = iterator.first(); ch != CharacterIterator.DONE; + ch = iterator.next()) { + //Map attr = iterator.getAttributes(); + + gen.writeln(gen.formatDouble(vals[0]) + " " + + gen.formatDouble(vals[1]) + " " + + gen.formatDouble(vals[2]) + " " + + gen.formatDouble(vals[3]) + " " + + gen.formatDouble(vals[4]) + " " + + gen.formatDouble(vals[5]) + " " + + gen.formatDouble(vals[6]) + " Tm [" + ch + + "]"); + } + + gen.writeln("ET"); + } catch (IOException ioe) { + handleIOException(ioe); } - - psRenderer.write("ET"); } /** @@ -863,83 +887,90 @@ public class PSGraphics2D extends AbstractGraphics2D { * @see #setClip */ public void fill(Shape s) { - // System.err.println("fill"); - psRenderer.write("gsave"); - Shape imclip = getClip(); - writeClip(imclip); - Color c = getColor(); - psRenderer.write(c.getRed() + " " + c.getGreen() + " " + c.getBlue() - + " setrgbcolor"); - - applyPaint(getPaint(), true); - - psRenderer.write("newpath"); - PathIterator iter = s.getPathIterator(getTransform()); - while (!iter.isDone()) { - double vals[] = new double[6]; - int type = iter.currentSegment(vals); - switch (type) { - case PathIterator.SEG_CUBICTO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) + " " - + PDFNumber.doubleOut(1000 * vals[2]) + " " - + PDFNumber.doubleOut(1000 * vals[3]) + " " - + PDFNumber.doubleOut(1000 * vals[4]) + " " - + PDFNumber.doubleOut(1000 * vals[5]) - + " curveto"); - break; - case PathIterator.SEG_LINETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " lineto"); - break; - case PathIterator.SEG_MOVETO: - psRenderer.write(PDFNumber.doubleOut(1000 * vals[0]) + " " - + PDFNumber.doubleOut(1000 * vals[1]) - + " M"); - break; - case PathIterator.SEG_QUADTO: - // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + - // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + - // 1000 * PDFNumber.doubleOut(vals[2]) + " " + - // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); - break; - case PathIterator.SEG_CLOSE: - psRenderer.write("closepath"); - break; - default: - break; + try { + // System.err.println("fill"); + gen.writeln("gsave"); + Shape imclip = getClip(); + writeClip(imclip); + Color c = getColor(); + gen.writeln(c.getRed() + " " + c.getGreen() + " " + c.getBlue() + + " setrgbcolor"); + + applyPaint(getPaint(), true); + + gen.writeln("newpath"); + PathIterator iter = s.getPathIterator(getTransform()); + while (!iter.isDone()) { + double vals[] = new double[6]; + int type = iter.currentSegment(vals); + switch (type) { + case PathIterator.SEG_CUBICTO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + " " + + gen.formatDouble(1000 * vals[2]) + " " + + gen.formatDouble(1000 * vals[3]) + " " + + gen.formatDouble(1000 * vals[4]) + " " + + gen.formatDouble(1000 * vals[5]) + + " curveto"); + break; + case PathIterator.SEG_LINETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " lineto"); + break; + case PathIterator.SEG_MOVETO: + gen.writeln(gen.formatDouble(1000 * vals[0]) + " " + + gen.formatDouble(1000 * vals[1]) + + " M"); + break; + case PathIterator.SEG_QUADTO: + // psRenderer.write(1000 * PDFNumber.doubleOut(vals[0]) + + // " " + 1000 * PDFNumber.doubleOut(vals[1]) + " " + + // 1000 * PDFNumber.doubleOut(vals[2]) + " " + + // 1000 * PDFNumber.doubleOut(vals[3]) + " y\n"); + break; + case PathIterator.SEG_CLOSE: + gen.writeln("closepath"); + break; + default: + break; + } + iter.next(); } - iter.next(); + doDrawing(true, false, + iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); + gen.writeln("grestore"); + } catch (IOException ioe) { + handleIOException(ioe); } - doDrawing(true, false, - iter.getWindingRule() == PathIterator.WIND_EVEN_ODD); - psRenderer.write("grestore"); } /** * Commits a painting operation. * @param fill filling * @param stroke stroking + * @param nonzero ??? + * @exception IOException In case of an I/O problem */ - protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) { + protected void doDrawing(boolean fill, boolean stroke, boolean nonzero) + throws IOException { if (fill) { if (stroke) { if (!nonzero) { - psRenderer.write("stroke"); + gen.writeln("stroke"); } else { - psRenderer.write("stroke"); + gen.writeln("stroke"); } } else { if (!nonzero) { - psRenderer.write("fill"); + gen.writeln("fill"); } else { - psRenderer.write("fill"); + gen.writeln("fill"); } } } else { // if(stroke) - psRenderer.write("stroke"); + gen.writeln("stroke"); } } diff --git a/src/org/apache/fop/render/ps/PSProcSets.java b/src/org/apache/fop/render/ps/PSProcSets.java new file mode 100644 index 000000000..03e457149 --- /dev/null +++ b/src/org/apache/fop/render/ps/PSProcSets.java @@ -0,0 +1,143 @@ +/* + * $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 java.io.IOException; + +/** + * This class defines the basic resources (procsets) used by FOP's PostScript + * renderer and SVG transcoder. + * + * @author Apache XML FOP Development Team + * @author Jeremias Maerki + * @version $Id$ + */ +public final class PSProcSets { + + /** + * Generates a resource defining standard procset for FOP. + * @param gen PSGenerator to use for output + * @throws IOException In case of an I/O problem + */ + public static final void writeFOPStdProcSet(PSGenerator gen) throws IOException { + gen.writeln("%%BeginResource: procset (Apache FOP Std ProcSet) 1.0 0"); + gen.writeln("%%Version: 1.0 0"); + gen.writeln("%%Copyright: Copyright (C) 2001-2003 " + + "The Apache Software Foundation. All rights reserved."); + gen.writeln("%%Title: Basic set of procedures used by FOP"); + + gen.writeln("/bd{bind def}bind def"); + gen.writeln("/ld{load def}bd"); + gen.writeln("/M/moveto ld"); + gen.writeln("/RM/rmoveto ld"); + gen.writeln("/t/show ld"); + + gen.writeln("/_ctm matrix def"); //Holds the current matrix + gen.writeln("/_tm matrix def"); + //BT: save currentmatrix, set _tm to identitymatrix and move to 0/0 + gen.writeln("/BT { _ctm currentmatrix pop matrix _tm copy pop 0 0 moveto } bd"); + //ET: restore last currentmatrix + gen.writeln("/ET { _ctm setmatrix } bd"); + gen.writeln("/iTm { _ctm setmatrix _tm concat } bd"); + gen.writeln("/Tm { _tm astore pop iTm 0 0 moveto } bd"); + + gen.writeln("/ux 0.0 def"); + gen.writeln("/uy 0.0 def"); + + // F + gen.writeln("/F {"); + gen.writeln(" /Tp exch def"); + // gen.writeln(" currentdict exch get"); + gen.writeln(" /Tf exch def"); + gen.writeln(" Tf findfont Tp scalefont setfont"); + gen.writeln(" /cf Tf def /cs Tp def /cw ( ) stringwidth pop def"); + gen.writeln("} bd"); + + gen.writeln("/ULS {currentpoint /uy exch def /ux exch def} bd"); + gen.writeln("/ULE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add moveto Tcx uy To add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("/OLE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add cs add moveto Tcx uy To add cs add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("/SOE {"); + gen.writeln(" /Tcx currentpoint pop def"); + gen.writeln(" gsave"); + gen.writeln(" newpath"); + gen.writeln(" cf findfont cs scalefont dup"); + gen.writeln(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); + gen.writeln(" /UnderlinePosition get Ts mul /To exch def"); + gen.writeln(" /UnderlineThickness get Ts mul /Tt exch def"); + gen.writeln(" ux uy To add cs 10 mul 26 idiv add moveto " + + "Tcx uy To add cs 10 mul 26 idiv add lineto"); + gen.writeln(" Tt setlinewidth stroke"); + gen.writeln(" grestore"); + gen.writeln("} bd"); + + gen.writeln("%%EndResource"); + } + + + /** + * Generates a resource defining a procset for including EPS graphics. + * @param gen PSGenerator to use for output + * @throws IOException In case of an I/O problem + */ + public static final void writeFOPEPSProcSet(PSGenerator gen) throws IOException { + gen.writeln("%%BeginResource: procset (Apache FOP EPS ProcSet) 1.0 0"); + gen.writeln("%%Version: 1.0 0"); + gen.writeln("%%Copyright: Copyright (C) 2002-2003 " + + "The Apache Software Foundation. All rights reserved."); + gen.writeln("%%Title: EPS procedures used by FOP"); + + gen.writeln("/BeginEPSF { %def"); + gen.writeln("/b4_Inc_state save def % Save state for cleanup"); + gen.writeln("/dict_count countdictstack def % Count objects on dict stack"); + gen.writeln("/op_count count 1 sub def % Count objects on operand stack"); + gen.writeln("userdict begin % Push userdict on dict stack"); + gen.writeln("/showpage { } def % Redefine showpage, { } = null proc"); + gen.writeln("0 setgray 0 setlinecap % Prepare graphics state"); + gen.writeln("1 setlinewidth 0 setlinejoin"); + gen.writeln("10 setmiterlimit [ ] 0 setdash newpath"); + gen.writeln("/languagelevel where % If level not equal to 1 then"); + gen.writeln("{pop languagelevel % set strokeadjust and"); + gen.writeln("1 ne % overprint to their defaults."); + gen.writeln("{false setstrokeadjust false setoverprint"); + gen.writeln("} if"); + gen.writeln("} if"); + gen.writeln("} bd"); + + gen.writeln("/EndEPSF { %def"); + gen.writeln("count op_count sub {pop} repeat % Clean up stacks"); + gen.writeln("countdictstack dict_count sub {end} repeat"); + gen.writeln("b4_Inc_state restore"); + gen.writeln("} bd"); + + gen.writeln("%%EndResource"); + } + +} diff --git a/src/org/apache/fop/render/ps/PSRenderer.java b/src/org/apache/fop/render/ps/PSRenderer.java index 9a84a08c6..b3d1a3711 100644 --- a/src/org/apache/fop/render/ps/PSRenderer.java +++ b/src/org/apache/fop/render/ps/PSRenderer.java @@ -8,16 +8,28 @@ package org.apache.fop.render.ps; // Java +import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.OutputStream; import java.util.Iterator; +import java.util.List; import java.util.Map; // FOP +import org.apache.fop.apps.FOPException; +import org.apache.fop.area.Block; +import org.apache.fop.area.BlockViewport; +import org.apache.fop.area.CTM; +import org.apache.fop.area.PageViewport; +import org.apache.fop.area.Trait; +import org.apache.fop.area.inline.ForeignObject; +import org.apache.fop.area.inline.Word; import org.apache.fop.datatypes.ColorType; import org.apache.fop.fonts.Font; import org.apache.fop.layout.FontInfo; import org.apache.fop.render.AbstractRenderer; +import org.apache.fop.render.RendererContext; +import org.w3c.dom.Document; /** @@ -32,21 +44,27 @@ import org.apache.fop.render.AbstractRenderer; * sure to also follow the DSC to make it simpler to programmatically modify * the generated Postscript files (ex. extract pages etc.). *
+ * The PS renderer operates in millipoints as the layout engine. Since PostScript + * initially uses points, scaling is applied as needed. * @todo Rebuild the PostScript renderer + * + * @author Apache XML FOP Development Team + * @author Jeremias Maerki + * @version $Id$ */ public class PSRenderer extends AbstractRenderer { - /** - * the application producing the PostScript - */ + /** The MIME type for PostScript */ + public static final String MIME_TYPE = "application/postscript"; + + /** The application producing the PostScript */ protected String producer; + private int currentPageNumber = 0; private boolean enableComments = true; - /** - * the stream used to output the PostScript - */ - protected PSStream out; + /** The PostScript generator used to output the PostScript */ + protected PSGenerator gen; private boolean ioTrouble = false; private String currentFontName; @@ -72,13 +90,17 @@ public class PSRenderer extends AbstractRenderer { * Write out a command * @param cmd PostScript command */ - protected void write(String cmd) { + protected void writeln(String cmd) { try { - out.write(cmd); - } catch (IOException e) { - if (!ioTrouble) { - e.printStackTrace(); - } + gen.writeln(cmd); + } catch (IOException ioe) { + handleIOTrouble(ioe); + } + } + + protected void handleIOTrouble(IOException ioe) { + if (!ioTrouble) { + getLogger().error("Error while writing to target file", ioe); ioTrouble = true; } } @@ -89,7 +111,7 @@ public class PSRenderer extends AbstractRenderer { */ protected void comment(String comment) { if (this.enableComments) { - write(comment); + writeln(comment); } } @@ -98,71 +120,9 @@ public class PSRenderer extends AbstractRenderer { * @param fontInfo available fonts */ protected void writeFontDict(FontInfo fontInfo) { - write("%%BeginResource: procset FOPFonts"); - write("%%Title: Font setup (shortcuts) for this file"); - write("/FOPFonts 100 dict dup begin"); - write("/bd{bind def}bind def"); - write("/ld{load def}bd"); - write("/M/moveto ld"); - write("/RM/rmoveto ld"); - write("/t/show ld"); - - write("/ux 0.0 def"); - write("/uy 0.0 def"); - // write("/cf /Helvetica def"); - // write("/cs 12000 def"); - - // F - write("/F {"); - write(" /Tp exch def"); - // write(" currentdict exch get"); - write(" /Tf exch def"); - write(" Tf findfont Tp scalefont setfont"); - write(" /cf Tf def /cs Tp def /cw ( ) stringwidth pop def"); - write("} bd"); - - write("/ULS {currentpoint /uy exch def /ux exch def} bd"); - write("/ULE {"); - write(" /Tcx currentpoint pop def"); - write(" gsave"); - write(" newpath"); - write(" cf findfont cs scalefont dup"); - write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); - write(" /UnderlinePosition get Ts mul /To exch def"); - write(" /UnderlineThickness get Ts mul /Tt exch def"); - write(" ux uy To add moveto Tcx uy To add lineto"); - write(" Tt setlinewidth stroke"); - write(" grestore"); - write("} bd"); - - write("/OLE {"); - write(" /Tcx currentpoint pop def"); - write(" gsave"); - write(" newpath"); - write(" cf findfont cs scalefont dup"); - write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); - write(" /UnderlinePosition get Ts mul /To exch def"); - write(" /UnderlineThickness get Ts mul /Tt exch def"); - write(" ux uy To add cs add moveto Tcx uy To add cs add lineto"); - write(" Tt setlinewidth stroke"); - write(" grestore"); - write("} bd"); - - write("/SOE {"); - write(" /Tcx currentpoint pop def"); - write(" gsave"); - write(" newpath"); - write(" cf findfont cs scalefont dup"); - write(" /FontMatrix get 0 get /Ts exch def /FontInfo get dup"); - write(" /UnderlinePosition get Ts mul /To exch def"); - write(" /UnderlineThickness get Ts mul /Tt exch def"); - write(" ux uy To add cs 10 mul 26 idiv add moveto " - + "Tcx uy To add cs 10 mul 26 idiv add lineto"); - write(" Tt setlinewidth stroke"); - write(" grestore"); - write("} bd"); - - + writeln("%%BeginResource: procset FOPFonts"); + writeln("%%Title: Font setup (shortcuts) for this file"); + writeln("/FOPFonts 100 dict dup begin"); // write("/gfF1{/Helvetica findfont} bd"); // write("/gfF3{/Helvetica-Bold findfont} bd"); @@ -171,21 +131,21 @@ public class PSRenderer extends AbstractRenderer { while (enum.hasNext()) { String key = (String)enum.next(); Font fm = (Font)fonts.get(key); - write("/" + key + " /" + fm.getFontName() + " def"); + writeln("/" + key + " /" + fm.getFontName() + " def"); } - write("end def"); - write("%%EndResource"); + writeln("end def"); + writeln("%%EndResource"); enum = fonts.keySet().iterator(); while (enum.hasNext()) { String key = (String)enum.next(); Font fm = (Font)fonts.get(key); - write("/" + fm.getFontName() + " findfont"); - write("dup length dict begin"); - write(" {1 index /FID ne {def} {pop pop} ifelse} forall"); - write(" /Encoding ISOLatin1Encoding def"); - write(" currentdict"); - write("end"); - write("/" + fm.getFontName() + " exch definefont pop"); + writeln("/" + fm.getFontName() + " findfont"); + writeln("dup length dict begin"); + writeln(" {1 index /FID ne {def} {pop pop} ifelse} forall"); + writeln(" /Encoding ISOLatin1Encoding def"); + writeln(" currentdict"); + writeln("end"); + writeln("/" + fm.getFontName() + " exch definefont pop"); } } @@ -193,9 +153,38 @@ public class PSRenderer extends AbstractRenderer { * Make sure the cursor is in the right place. */ protected void movetoCurrPosition() { - write(this.currentIPPosition + " " + this.currentBPPosition + " M"); + moveTo(this.currentIPPosition, this.currentBPPosition); } + /** + * Moves the cursor. + * @param x X coordinate + * @param y Y coordinate + */ + protected void moveTo(int x, int y) { + writeln(x + " " + y + " M"); + } + + /** Saves the graphics state of the rendering engine. */ + protected void saveGraphicsState() { + writeln("gsave"); + } + + /** Restores the last graphics state of the rendering engine. */ + protected void restoreGraphicsState() { + writeln("grestore"); + } + + /** Indicates the beginning of a text object. */ + protected void beginTextObject() { + writeln("BT"); + } + + /** Indicates the end of a text object. */ + protected void endTextObject() { + writeln("ET"); + } + /** * Set up the font info * @@ -215,17 +204,27 @@ public class PSRenderer extends AbstractRenderer { * @param h height * @param col color to fill with */ - protected void addFilledRect(int x, int y, int w, int h, + protected void fillRect(int x, int y, int w, int h, ColorType col) { - write("newpath"); - write(x + " " + y + " M"); - write(w + " 0 rlineto"); - write("0 " + (-h) + " rlineto"); - write((-w) + " 0 rlineto"); - write("0 " + h + " rlineto"); - write("closepath"); useColor(col); - write("fill"); + writeln(x + " " + y + " " + w + " " + h + " rectfill"); + } + + protected void drawRect(int x, int y, int w, int h) { + writeln(x + " " + y + " " + w + " " + h + " rectstroke"); + } + + /** + * Clip an area. + * Write a clipping operation given coordinates in the current + * transform. + * @param x the x coordinate + * @param y the y coordinate + * @param width the width of the area + * @param height the height of the area + */ + protected void clip(float x, float y, float width, float height) { + writeln(x + " " + y + " " + width + " " + height + " rectclip"); } /** @@ -235,7 +234,7 @@ public class PSRenderer extends AbstractRenderer { */ public void useFont(String name, int size) { if ((currentFontName != name) || (currentFontSize != size)) { - write(name + " " + size + " F"); + writeln(name + " " + size + " F"); currentFontName = name; currentFontSize = size; } @@ -247,7 +246,7 @@ public class PSRenderer extends AbstractRenderer { private void useColor(float red, float green, float blue) { if ((red != currRed) || (green != currGreen) || (blue != currBlue)) { - write(red + " " + green + " " + blue + " setrgbcolor"); + writeln(red + " " + green + " " + blue + " setrgbcolor"); currRed = red; currGreen = green; currBlue = blue; @@ -258,61 +257,327 @@ public class PSRenderer extends AbstractRenderer { * @see org.apache.fop.render.Renderer#startRenderer(OutputStream) */ public void startRenderer(OutputStream outputStream) - throws IOException { + throws IOException { getLogger().debug("rendering areas to PostScript"); - this.out = new PSStream(outputStream); - write("%!PS-Adobe-3.0"); - write("%%Creator: " + this.producer); - write("%%DocumentProcessColors: Black"); - write("%%DocumentSuppliedResources: procset FOPFonts"); - write("%%EndComments"); - write("%%BeginDefaults"); - write("%%EndDefaults"); - write("%%BeginProlog"); - write("%%EndProlog"); - write("%%BeginSetup"); + //Setup for PostScript generation + this.gen = new PSGenerator(outputStream); + this.currentPageNumber = 0; + + //PostScript Header + writeln(DSCConstants.PS_ADOBE_30); + gen.writeDSCComment(DSCConstants.CREATOR, new String[] {"FOP " + this.producer}); + gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); + gen.writeDSCComment(DSCConstants.PAGES, new Object[] {PSGenerator.ATEND}); + 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); writeFontDict(fontInfo); - - /* Write proc for including EPS */ - write("%%BeginResource: procset EPSprocs"); - write("%%Title: EPS encapsulation procs"); - - write("/BeginEPSF { %def"); - write("/b4_Inc_state save def % Save state for cleanup"); - write("/dict_count countdictstack def % Count objects on dict stack"); - write("/op_count count 1 sub def % Count objects on operand stack"); - write("userdict begin % Push userdict on dict stack"); - write("/showpage { } def % Redefine showpage, { } = null proc"); - write("0 setgray 0 setlinecap % Prepare graphics state"); - write("1 setlinewidth 0 setlinejoin"); - write("10 setmiterlimit [ ] 0 setdash newpath"); - write("/languagelevel where % If level not equal to 1 then"); - write("{pop languagelevel % set strokeadjust and"); - write("1 ne % overprint to their defaults."); - write("{false setstrokeadjust false setoverprint"); - write("} if"); - write("} if"); - write("} bind def"); - - write("/EndEPSF { %def"); - write("count op_count sub {pop} repeat % Clean up stacks"); - write("countdictstack dict_count sub {end} repeat"); - write("b4_Inc_state restore"); - write("} bind def"); - write("%%EndResource"); - - write("%%EndSetup"); - write("FOPFonts begin"); + gen.writeDSCComment(DSCConstants.END_SETUP); } /** * @see org.apache.fop.render.Renderer#stopRenderer() */ public void stopRenderer() throws IOException { - write("%%Trailer"); - write("%%EOF"); - this.out.flush(); + gen.writeDSCComment(DSCConstants.TRAILER); + gen.writeDSCComment(DSCConstants.PAGES, new Integer(this.currentPageNumber)); + gen.writeDSCComment(DSCConstants.EOF); + gen.flush(); + } + + /** + * @see org.apache.fop.render.Renderer#renderPage(PageViewport) + */ + public void renderPage(PageViewport page) + throws IOException, FOPException { + getLogger().debug("renderPage(): " + page); + + this.currentPageNumber++; + gen.writeDSCComment(DSCConstants.PAGE, new Object[] + {page.getPageNumber(), + new Integer(this.currentPageNumber)}); + final Integer zero = new Integer(0); + final Long pagewidth = new Long(Math.round(page.getViewArea().getWidth() / 1000f)); + final Long pageheight = new Long(Math.round(page.getViewArea().getHeight() / 1000f)); + gen.writeDSCComment(DSCConstants.PAGE_BBOX, new Object[] + {zero, zero, pagewidth, pageheight}); + gen.writeDSCComment(DSCConstants.BEGIN_PAGE_SETUP); + gen.writeln("FOPFonts begin"); + gen.writeln("[1 0 0 -1 0 " + pageheight + "] concat"); + gen.writeln("0.001 0.001 scale"); + gen.writeDSCComment(DSCConstants.END_PAGE_SETUP); + + //Process page + super.renderPage(page); + + writeln("showpage"); + gen.writeDSCComment(DSCConstants.PAGE_TRAILER); + gen.writeDSCComment(DSCConstants.END_PAGE); + } + + protected void paintText(int rx, int bl, String text, Font font) { + saveGraphicsState(); + writeln("1 0 0 -1 " + rx + " " + bl + " Tm"); + + int initialSize = text.length(); + initialSize += initialSize / 2; + StringBuffer sb = new StringBuffer(initialSize); + sb.append("("); + for (int i = 0; i < text.length(); i++) { + final char c = text.charAt(i); + final char mapped = font.mapChar(c); + gen.escapeChar(mapped, sb); + } + sb.append(") t"); + writeln(sb.toString()); + restoreGraphicsState(); + } + + /** + * @see org.apache.fop.render.Renderer#renderWord(Word) + */ + public void renderWord(Word area) { + String fontname = (String)area.getTrait(Trait.FONT_NAME); + int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE); + + // This assumes that *all* CIDFonts use a /ToUnicode mapping + Font f = (Font)fontInfo.getFonts().get(fontname); + + //Determine position + int rx = currentBlockIPPosition; + int bl = currentBPPosition + area.getOffset(); + + useFont(fontname, fontsize); + + paintText(rx, bl, area.getWord(), f); + +/* + String psString = null; + if (area.getFontState().getLetterSpacing() > 0) { + //float f = area.getFontState().getLetterSpacing() * 1000 / this.currentFontSize; + float f = area.getFontState().getLetterSpacing(); + psString = (new StringBuffer().append(f).append(" 0.0 (") + .append(sb.toString()).append(") A")).toString(); + } else { + psString = (new StringBuffer("(").append(sb.toString()) + .append(") t")).toString(); + } + + + // System.out.println("["+s+"] --> ["+sb.toString()+"]"); + + // comment("% --- InlineArea font-weight="+fontWeight+": " + sb.toString()); + useFont(fs.getFontName(), fs.getFontSize()); + useColor(area.getRed(), area.getGreen(), area.getBlue()); + if (area.getUnderlined() || area.getLineThrough() + || area.getOverlined()) + write("ULS"); + write(psString); + if (area.getUnderlined()) + write("ULE"); + if (area.getLineThrough()) + write("SOE"); + if (area.getOverlined()) + write("OLE"); + this.currentXPosition += area.getContentWidth(); + */ + super.renderWord(area); //Updates IPD } + + /** + * @see org.apache.fop.render.AbstractRenderer#renderBlockViewport(BlockViewport, List) + */ + protected void renderBlockViewport(BlockViewport bv, List children) { + // clip and position viewport if necessary + + // save positions + int saveIP = currentIPPosition; + int saveBP = currentBPPosition; + String saveFontName = currentFontName; + + CTM ctm = bv.getCTM(); + + if (bv.getPositioning() == Block.ABSOLUTE) { + + currentIPPosition = 0; + currentBPPosition = 0; + + //closeText(); + endTextObject(); + + if (bv.getClip()) { + saveGraphicsState(); + int x = bv.getXOffset() + containingIPPosition; + int y = bv.getYOffset() + containingBPPosition; + int width = bv.getWidth(); + int height = bv.getHeight(); + clip(x, y, width, height); + } + + CTM tempctm = new CTM(containingIPPosition, containingBPPosition); + ctm = tempctm.multiply(ctm); + + startVParea(ctm); + handleBlockTraits(bv); + renderBlocks(children); + endVParea(); + + if (bv.getClip()) { + restoreGraphicsState(); + } + beginTextObject(); + + // clip if necessary + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + } else { + + if (ctm != null) { + currentIPPosition = 0; + currentBPPosition = 0; + + //closeText(); + endTextObject(); + + double[] vals = ctm.toArray(); + //boolean aclock = vals[2] == 1.0; + if (vals[2] == 1.0) { + ctm = ctm.translate(-saveBP - bv.getHeight(), -saveIP); + } else if (vals[0] == -1.0) { + ctm = ctm.translate(-saveIP - bv.getWidth(), -saveBP - bv.getHeight()); + } else { + ctm = ctm.translate(saveBP, saveIP - bv.getWidth()); + } + } + + // clip if necessary + if (bv.getClip()) { + if (ctm == null) { + //closeText(); + endTextObject(); + } + saveGraphicsState(); + int x = bv.getXOffset(); + int y = bv.getYOffset(); + int width = bv.getWidth(); + int height = bv.getHeight(); + clip(x, y, width, height); + } + + if (ctm != null) { + startVParea(ctm); + } + handleBlockTraits(bv); + renderBlocks(children); + if (ctm != null) { + endVParea(); + } + + if (bv.getClip()) { + restoreGraphicsState(); + if (ctm == null) { + beginTextObject(); + } + } + if (ctm != null) { + beginTextObject(); + } + + currentIPPosition = saveIP; + currentBPPosition = saveBP; + currentBPPosition += (int)(bv.getHeight()); + } + currentFontName = saveFontName; + } + + /** + * @see org.apache.fop.render.AbstractRenderer#startVParea(CTM) + */ + protected void startVParea(CTM ctm) { + // Set the given CTM in the graphics state + //currentState.push(); + //currentState.setTransform(new AffineTransform(CTMHelper.toPDFArray(ctm))); + + saveGraphicsState(); + // multiply with current CTM + //currentStream.add(CTMHelper.toPDFString(ctm) + " cm\n"); + final double matrix[] = ctm.toArray(); + writeln("[" + gen.formatDouble(matrix[0]) + + " " + gen.formatDouble(matrix[1]) + + " " + gen.formatDouble(matrix[2]) + + " " + gen.formatDouble(matrix[3]) + + " " + gen.formatDouble(matrix[4]) + + " " + gen.formatDouble(matrix[5]) + "] concat"); + + // Set clip? + beginTextObject(); + } + + /** + * @see org.apache.fop.render.AbstractRenderer#endVParea() + */ + protected void endVParea() { + endTextObject(); + restoreGraphicsState(); + //currentState.pop(); + } + + + /** + * @see org.apache.fop.render.AbstractRenderer#renderForeignObject(ForeignObject, Rectangle2D) + */ + public void renderForeignObject(ForeignObject fo, Rectangle2D pos) { + Document doc = fo.getDocument(); + String ns = fo.getNameSpace(); + renderDocument(doc, ns, pos); + } + + public void renderDocument(Document doc, String ns, Rectangle2D pos) { + RendererContext context; + context = new RendererContext(MIME_TYPE); + context.setUserAgent(userAgent); + + /* + 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())); + */ + userAgent.renderXML(context, doc, ns); + + } + + + + } diff --git a/src/org/apache/fop/render/ps/PSStream.java b/src/org/apache/fop/render/ps/PSStream.java deleted file mode 100644 index 2e1c624ab..000000000 --- a/src/org/apache/fop/render/ps/PSStream.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * $Id$ - * Copyright (C) 2001-2002 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 java.io.OutputStream; -import java.io.FilterOutputStream; -import java.io.IOException; - -/** - * PSStream is used to to output PostScript code from the PostScript renderer. - */ -public class PSStream extends FilterOutputStream { - - /** @see java.io.FilterOutputStream **/ - public PSStream(OutputStream out) { - super(out); - } - - - /** - * Writes a PostScript command to the stream. - * - * @param cmd The PostScript code to be written. - * @exception IOException In case of an I/O problem - */ - public void write(String cmd) throws IOException { - if (cmd.length() > 255) { - throw new RuntimeException("PostScript command exceeded limit of 255 characters"); - } - write(cmd.getBytes("US-ASCII")); - write('\n'); - } - - - /** - * Writes encoded data to the PostScript stream. - * - * @param cmd The encoded PostScript code to be written. - * @exception IOException In case of an I/O problem - */ - public void writeByteArr(byte[] cmd) throws IOException { - write(cmd); - write('\n'); - } - -}