jeremias 2002/08/12 10:05:09
Modified: src/org/apache/fop/render/ps Tag: fop-0_20_2-maintain
PSRenderer.java
Added: src/org/apache/fop/render/ps Tag: fop-0_20_2-maintain
RunLengthEncodeOutputStream.java
Log:
Added a RunLengthEncode filter for the PostScript renderer.
Submitted by: Stephen Wolke <[EMAIL PROTECTED]>
Added a property on the PostScript renderer for switching between PostScript
Level 2 and 3. Default is Level 3. (Jeremias Maerki)
Revision Changes Path
No revision
No revision
1.15.2.9 +1095 -1062xml-fop/src/org/apache/fop/render/ps/PSRenderer.java
Index: PSRenderer.java
===================================================================
RCS file: /home/cvs/xml-fop/src/org/apache/fop/render/ps/PSRenderer.java,v
retrieving revision 1.15.2.8
retrieving revision 1.15.2.9
diff -u -r1.15.2.8 -r1.15.2.9
--- PSRenderer.java 2 Aug 2002 20:28:57 -0000 1.15.2.8
+++ PSRenderer.java 12 Aug 2002 17:05:09 -0000 1.15.2.9
@@ -1,1062 +1,1095 @@
-/*
- * $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;
-
-// FOP
-import org.apache.fop.svg.SVGArea;
-import org.apache.fop.render.AbstractRenderer;
-import org.apache.fop.render.Renderer;
-import org.apache.fop.image.ImageArea;
-import org.apache.fop.image.FopImage;
-import org.apache.fop.image.FopImageException;
-import org.apache.fop.image.JpegImage;
-import org.apache.fop.layout.*;
-import org.apache.fop.layout.inline.*;
-import org.apache.fop.datatypes.*;
-import org.apache.fop.fo.properties.*;
-import org.apache.fop.render.pdf.Font;
-import org.apache.fop.image.*;
-import org.apache.fop.apps.FOPException;
-
-import org.apache.batik.bridge.*;
-import org.apache.batik.swing.svg.*;
-import org.apache.batik.swing.gvt.*;
-import org.apache.batik.gvt.*;
-import org.apache.batik.gvt.renderer.*;
-import org.apache.batik.gvt.filter.*;
-import org.apache.batik.gvt.event.*;
-
-// SVG
-import org.w3c.dom.svg.SVGSVGElement;
-import org.w3c.dom.svg.SVGDocument;
-import org.w3c.dom.*;
-import org.w3c.dom.svg.*;
-
-// Java
-import java.io.*;
-import java.util.*;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Iterator;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Dimension2D;
-import java.awt.Point;
-import java.awt.RenderingHints;
-import java.awt.Dimension;
-
-/*
-PostScript renderer
-
-Remarks:
-- If anyone modifies this renderer please make sure to also follow the DSC to
- make it simpler to programmatically modify the generated Postscript files
- (ex. extract pages etc.).
-- The filters in use are hardcoded at the moment.
-- Modified by Mark Lillywhite [EMAIL PROTECTED], to use the new
- Renderer interface. This PostScript renderer appears to be the
- most efficient at producing output.
-
-TODO-List:
-- Character size/spacing
-- SVG Transcoder for Batik
-- configuration
-- move to PrintRenderer
-- maybe improve filters (I'm not very proud of them)
-- add a RunLengthEncode filter (useful for Level 2 Postscript)
-- Improve DocumentProcessColors stuff (probably needs to be configurable, then
maybe
- add a color to grayscale conversion for bitmaps to make output smaller (See
- PCLRenderer)
-- enhanced font support and font embedding
-- support different character encodings
-- try to implement image transparency
-- Add PPD support
-- fix border painting (see table.fo)
-
-*/
-
-/**
- * Renderer that renders to PostScript.
- * <br>
- * This class currently generates PostScript Level 2 code. The only exception
- * is the FlateEncode filter which is a Level 3 feature. The PostScript code
- * generated follows the Document Structuring Conventions (DSC) version 3.0.
- *
- * @author Jeremias M�rki
- */
-public class PSRenderer extends AbstractRenderer {
-
- /**
- * the application producing the PostScript
- */
- protected String producer;
-
- int imagecount = 0; // DEBUG
- int pagecount = 0;
-
- private boolean enableComments = true;
-
- /**
- * the stream used to output the PostScript
- */
- protected PSStream out;
- private boolean ioTrouble = false;
-
- private String currentFontName;
- private int currentFontSize;
- private int pageHeight;
- private int pageWidth;
- private float currRed;
- private float currGreen;
- private float currBlue;
-
- private FontInfo fontInfo;
-
- protected IDReferences idReferences;
-
- protected java.util.HashMap options;
-
-
- /**
- * set the document's producer
- *
- * @param producer string indicating application producing the PostScript
- */
- public void setProducer(String producer) {
- this.producer = producer;
- }
-
-
- /**
- * set up renderer options
- */
- public void setOptions(java.util.HashMap options) {
- this.options = options;
- }
-
- /**
- * write out a command
- */
- protected void write(String cmd) {
- try {
- out.write(cmd);
- } catch (IOException e) {
- if (!ioTrouble)
- e.printStackTrace();
- ioTrouble = true;
- }
- }
-
- /**
- * write out a comment
- */
- protected void comment(String comment) {
- if (this.enableComments)
- write(comment);
- }
-
- protected void writeProcs() {
- write("%%BeginResource: procset FOPprocs");
- write("%%Title: Utility procedures");
- write("/FOPprocs 20 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("/A/ashow ld");
- write("/cp/closepath ld");
- write("/re {4 2 roll M"); //define rectangle
- write("1 index 0 rlineto");
- write("0 exch rlineto");
- write("neg 0 rlineto");
- write("cp } bd");
-
- write("/ux 0.0 def");
- write("/uy 0.0 def");
-
- // <font> <size> 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");
- write("end def");
- write("%%EndResource");
- }
-
- protected void writeFontDict(FontInfo fontInfo) {
- write("%%BeginResource: procset FOPFonts");
- write("%%Title: Font setup (shortcuts) for this file");
- write("/FOPFonts 100 dict dup begin");
- // write("/gfF1{/Helvetica findfont} bd");
- // write("/gfF3{/Helvetica-Bold findfont} bd");
- HashMap fonts = fontInfo.getFonts();
- Iterator enum = fonts.keySet().iterator();
- while (enum.hasNext()) {
- String key = (String)enum.next();
- Font fm = (Font)fonts.get(key);
- write("/" + key + " /" + fm.fontName() + " def");
- }
- write("end def");
- write("%%EndResource");
-
- //Rewrite font encodings
- enum = fonts.keySet().iterator();
- while (enum.hasNext()) {
- String key = (String)enum.next();
- Font fm = (Font)fonts.get(key);
- write("/" + fm.fontName() + " 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.fontName() + " exch definefont pop");
- }
- }
-
- protected void movetoCurrPosition() {
- write(this.currentXPosition + " " + this.currentYPosition + " M");
- }
-
- /**
- * set up the font info
- *
- * @param fontInfo the font info object to set up
- */
- public void setupFontInfo(FontInfo fontInfo)
- throws FOPException {
- /* use PDF's font setup to get PDF metrics */
- org.apache.fop.render.pdf.FontSetup.setup(fontInfo);
- this.fontInfo = fontInfo;
- }
-
- protected void addFilledRect(int x, int y, int w, int h,
- ColorType col) {
- // XXX: cater for braindead, legacy -ve heights
- if (h < 0) {
- h = -h;
- }
-
- write("newpath");
- write(x + " " + y + " " + w + " " + -h + " re");
- /*
- 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");
- }
-
- /**
- * render a display space to PostScript
- *
- * @param space the space to render
- */
- public void renderDisplaySpace(DisplaySpace space) {
- // write("% --- DisplaySpace size="+space.getSize());
- this.currentYPosition -= space.getSize();
- movetoCurrPosition();
- }
-
- /**
- * render a foreign object area
- */
- public void renderForeignObjectArea(ForeignObjectArea area) {
- // if necessary need to scale and align the content
- this.currentXPosition = this.currentXPosition + area.getXOffset();
- int plOffset = 0;
- Area parent = area.getParent();
- if (parent instanceof LineArea) {
- plOffset = ((LineArea)parent).getPlacementOffset();
- }
- this.currentYPosition += plOffset;
- area.getObject().render(this);
- this.currentXPosition += area.getEffectiveWidth();
- this.currentYPosition -= plOffset;
- movetoCurrPosition();
- }
-
- /**
- * render an SVG area to PostScript
- *
- * @param area the area to render
- */
- public void renderSVGArea(SVGArea area) {
- int x = this.currentXPosition;
- int y = this.currentYPosition;
- renderSVGDocument(area.getSVGDocument(), x, y, area.getFontState());
- }
-
-
- /**
- * render SVG document to PostScript
- *
- * @param doc the document to render
- * @param x the x offset
- * @param y the y offset
- * @param fs the fontstate to use
- */
- protected void renderSVGDocument(Document doc, int x, int y,
- FontState fs) {
- org.apache.fop.svg.SVGUserAgent userAgent
- = new org.apache.fop.svg.SVGUserAgent(new AffineTransform());
- userAgent.setLogger(log);
-
- GVTBuilder builder = new GVTBuilder();
- BridgeContext ctx = new BridgeContext(userAgent);
-
- GraphicsNode root;
- try {
- root = builder.build(ctx, doc);
- } catch (Exception e) {
- log.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;
-
- //log.debug("drawing SVG image: "+x+"/"+y+" "+w+"/"+h);
-
- ctx = null;
- builder = null;
-
- float sx = 1, sy = -1;
- int xOffset = x, yOffset = y;
-
- comment("% --- SVG Area");
- write("gsave");
- if (w != 0 && h != 0) {
- write("newpath");
- write(x + " " + y + " M");
- write((x + w) + " " + y + " rlineto");
- write((x + w) + " " + (y - h) + " rlineto");
- write(x + " " + (y - h) + " rlineto");
- write("closepath");
- write("clippath");
- }
- // 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.
- write(xOffset + " " + yOffset + " translate");
- write(sx + " " + sy + " scale");
-
- PSGraphics2D graphics = new PSGraphics2D(false, fs,
- this, currentFontName,
- currentFontSize,
- currentXPosition,
- currentYPosition);
- graphics.setGraphicContext(new
org.apache.batik.ext.awt.g2d.GraphicContext());
- try {
- root.paint(graphics);
- } catch (Exception e) {
- log.error("svg graphic could not be rendered: "
- + e.getMessage(), e);
- }
-
- write("grestore");
-
- comment("% --- SVG Area end");
- }
-
- /**
- * Renders an image, scaling it to the given width and height.
- * If the scaled width and height is the same intrinsic size
- * of the image, the image is not scaled.
- *
- * @param x the x position of left edge in millipoints
- * @param y the y position of top edge in millipoints
- * @param w the width in millipoints
- * @param h the height in millipoints
- * @param image the image to be rendered
- * @param fs the font state to use when rendering text
- * in non-bitmapped images.
- */
- protected void drawImageScaled(int x, int y, int w, int h,
- FopImage image,
- FontState fs) {
- //log.debug("drawing scaled image: "+x+"/"+y+" "+w+"/"+h);
- if (image instanceof SVGImage) {
- try {
- renderSVGDocument(((SVGImage)image).getSVGDocument(), x, y, fs);
- } catch (FopImageException e) {
- log.error("Error rendering SVG image", e);
- }
- } else if (image instanceof EPSImage) {
- renderEPS(image, x, y, w, h);
- } else {
- renderBitmap(image, x, y, w, h);
- }
- }
-
- /**
- * Renders an image, clipping it as specified.
- *
- * @param x the x position of left edge in millipoints.
- * @param y the y position of top edge in millipoints.
- * @param clipX the left edge of the clip in millipoints
- * @param clipY the top edge of the clip in millipoints
- * @param clipW the clip width in millipoints
- * @param clipH the clip height in millipoints
- * @param image the image to be rendered
- * @param fs the font state to use when rendering text
- * in non-bitmapped images.
- */
- protected void drawImageClipped(int x, int y,
- int clipX, int clipY,
- int clipW, int clipH,
- FopImage image,
- FontState fs) {
- //log.debug("drawing clipped image: "+x+"/"+y+" "+clipX+"/"+clipY+"
"+clipW+"/"+clipH);
- write("gsave");
- write(clipX + " " + clipY + " " + clipW + " " + clipH + " re");
- write("clippath");
-
- try {
- int w = image.getWidth() * 1000;
- int h = image.getHeight() * 1000;
-
- drawImageScaled(x, y, w, h, image, fs);
- } catch (FopImageException e) {
- log.error("Error getting image extents", e);
- }
- write("grestore");
- }
-
- public void renderEPS(FopImage img, int x, int y, int w, int h) {
- try {
- EPSImage eimg = (EPSImage)img;
- int[] bbox = eimg.getBBox();
- int bboxw = bbox[2] - bbox[0];
- int bboxh = bbox[3] - bbox[1];
-
-
- write("%%BeginDocument: " + eimg.getDocName());
- write("BeginEPSF");
-
- write(x + " " + (y - h) + " translate");
- write("0.0 rotate");
- write((long)(w/bboxw) + " " + (long)(h/bboxh) + " scale");
- write(-bbox[0] + " " + (-bbox[1]) + " translate");
- write(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + "
rectclip");
- write("newpath");
- out.writeByteArr(img.getBitmaps());
- write("%%EndDocument");
- write("EndEPSF");
- write("");
- } catch (Exception e) {
- e.printStackTrace();
- log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
- + e.getMessage() + ")", e);
- }
- }
-
- public void renderBitmap(FopImage img, int x, int y, int w, int h) {
- try {
- boolean iscolor = img.getColorSpace().getColorSpace()
- != ColorSpace.DEVICE_GRAY;
- byte[] imgmap = img.getBitmaps();
-
- write("gsave");
- if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK)
- write("/DeviceCMYK setcolorspace");
- else
- write("/DeviceRGB setcolorspace");
-
- write(x + " " + (y - h) + " translate");
- write(w + " " + h + " scale");
- write("<<");
- write(" /ImageType 1");
- write(" /Width " + img.getWidth());
- write(" /Height " + img.getHeight());
- write(" /BitsPerComponent 8");
- if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) {
- if (img.invertImage())
- write(" /Decode [1 0 1 0 1 0 1 0]");
- else
- write(" /Decode [0 1 0 1 0 1 0 1]");
- } else if (iscolor) {
- write(" /Decode [0 1 0 1 0 1]");
- } else {
- write(" /Decode [0 1]");
- }
- // Setup scanning for left-to-right and top-to-bottom
- write(" /ImageMatrix [" + img.getWidth() + " 0 0 -"
- + img.getHeight() + " 0 " + img.getHeight() + "]");
-
- if (img instanceof JpegImage)
- write(" /DataSource currentfile /ASCII85Decode filter /DCTDecode
filter");
- else
- write(" /DataSource currentfile /ASCII85Decode filter /FlateDecode
filter");
- // write(" /DataSource currentfile /ASCIIHexDecode filter /FlateDecode
filter");
- // write(" /DataSource currentfile /ASCII85Decode filter
/RunLengthDecode filter");
- // write(" /DataSource currentfile /ASCIIHexDecode filter
/RunLengthDecode filter");
- // write(" /DataSource currentfile /ASCIIHexDecode filter");
- // write(" /DataSource currentfile /ASCII85Decode filter");
- // write(" /DataSource currentfile /RunLengthDecode filter");
- write(">>");
- write("image");
-
- /*
- * for (int y=0; y<img.getHeight(); y++) {
- * int indx = y * img.getWidth();
- * if (iscolor) indx*= 3;
- * for (int x=0; x<img.getWidth(); x++) {
- * if (iscolor) {
- * writeASCIIHex(imgmap[indx++] & 0xFF);
- * writeASCIIHex(imgmap[indx++] & 0xFF);
- * writeASCIIHex(imgmap[indx++] & 0xFF);
- * } else {
- * writeASCIIHex(imgmap[indx++] & 0xFF);
- * }
- * }
- * }
- */
- try {
- // imgmap[0] = 1;
- OutputStream out = this.out;
- out = new ASCII85OutputStream(out);
- if (!(img instanceof JpegImage)) {
- out = new FlateEncodeOutputStream(out);
- }
- out.write(imgmap);
- ((Finalizable)out).finalizeStream();
- } catch (IOException e) {
- if (!ioTrouble)
- e.printStackTrace();
- ioTrouble = true;
- }
-
- write("");
- write("grestore");
- } catch (FopImageException e) {
- log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
- + e.getMessage() + ")", e);
- }
- }
-
- /**
- * Render an image area.
- *
- * @param area the image area to render
- */
- public void renderImageArea(ImageArea area) {
- // adapted from contribution by BoBoGi
- int x = this.currentXPosition + area.getXOffset();
- int ploffset = 0;
- if (area.getParent() instanceof LineArea) {
- ploffset = ((LineArea)area.getParent()).getPlacementOffset();
- }
- int y = this.currentYPosition + ploffset;
- int w = area.getContentWidth();
- int h = area.getHeight();
-
- //this.currentYPosition -= h;
- this.currentXPosition += w;
-
- FopImage img = area.getImage();
-
- if (img == null) {
- log.error("Error while loading image: area.getImage() is null");
- } else {
- drawImageScaled(x, y, w, h, img, area.getFontState());
- }
- movetoCurrPosition();
- }
-
-
- /**
- * render an image area to PostScript
- *
- * @param area the area to render
- */
- /*
- public void renderImageArea(ImageArea area) {
- int x = this.currentXPosition + area.getXOffset();
- int ploffset = 0;
- if (area.getParent() instanceof LineArea) {
- ploffset = ((LineArea)area.getParent()).getPlacementOffset();
- }
- int y = this.currentYPosition + ploffset;
- int w = area.getContentWidth();
- int h = area.getHeight();
- this.currentYPosition -= area.getHeight();
-
- imagecount++;
- // if (imagecount!=4) return;
-
- comment("% --- ImageArea");
- if (area.getImage() instanceof SVGImage) {
- renderSVGDocument(((SVGImage)area.getImage()).getSVGDocument(), x, y,
area.getFontState());
- } else if (area.getImage() instanceof EPSImage) {
- renderEPS(area.getImage(), x, y, w, h);
- } else {
- renderBitmap(area.getImage(), x, y, w, h);
- }
- comment("% --- ImageArea end");
- }*/
-
- /**
- * render an inline area to PostScript
- *
- * @param area the area to render
- */
- public void renderWordArea(WordArea area) {
- movetoCurrPosition();
- FontState fs = area.getFontState();
- String fontWeight = fs.getFontWeight();
- StringBuffer sb = new StringBuffer();
- String s;
- if (area.getPageNumberID()
- != null) { // this text is a page number, so resolve it
- s = idReferences.getPageNumber(area.getPageNumberID());
- if (s == null) {
- s = "";
- }
- } else {
- s = area.getText();
- }
- int l = s.length();
-
- for (int i = 0; i < l; i++) {
- char ch = s.charAt(i);
- char mch = fs.mapChar(ch);
- if (mch > 127) {
- sb = sb.append("\\" + Integer.toOctalString(mch));
- } else {
- String escape = "\\()[]{}";
- if (escape.indexOf(mch) >= 0) {
- sb.append("\\");
- }
- sb = sb.append(mch);
- }
- }
-
- 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).
- append(") A")).toString();
- } else {
- psString = (new StringBuffer("(").append(sb).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();
- }
-
- public void useFont(String name, int size) {
- if ((currentFontName != name) || (currentFontSize != size)) {
- write(name + " " + size + " F");
- currentFontName = name;
- currentFontSize = size;
- }
- }
-
- /**
- * render an inline space to PostScript
- *
- * @param space the space to render
- */
- public void renderInlineSpace(InlineSpace space) {
- // write("% --- InlineSpace size="+space.getSize());
- if (space.getUnderlined() || space.getLineThrough()
- || space.getOverlined()) {
- //start textdeko
- movetoCurrPosition();
- write("ULS");
-
- write(space.getSize() + " 0 RM");
-
- //end textdeko
- if (space.getUnderlined())
- write("ULE");
- if (space.getLineThrough())
- write("SOE");
- if (space.getOverlined())
- write("OLE");
- }
- this.currentXPosition += space.getSize();
- }
-
- /**
- * render a line area to PostScript
- *
- * @param area the area to render
- */
- public void renderLineArea(LineArea area) {
- int rx = this.currentAreaContainerXPosition + area.getStartIndent();
- int ry = this.currentYPosition;
- int w = area.getContentWidth();
- int h = area.getHeight();
-
- this.currentYPosition -= area.getPlacementOffset();
- this.currentXPosition = rx;
-
- int bl = this.currentYPosition;
- // method is identical to super method except next line
- movetoCurrPosition();
-
- String fontWeight = area.getFontState().getFontWeight();
- //comment("% --- LineArea begin font-weight="+fontWeight);
- ArrayList children = area.getChildren();
- for (int i = 0; i < children.size(); i++) {
- Box b = (Box)children.get(i);
- this.currentYPosition = ry - area.getPlacementOffset();
- b.render(this);
- }
- //comment("% --- LineArea end");
-
- this.currentYPosition = ry - h;
- this.currentXPosition = rx;
- }
-
- /**
- * render a page to PostScript
- *
- * @param page the page to render
- */
- public void renderPage(Page page) {
- this.pagecount++;
- this.idReferences = page.getIDReferences();
-
- write("%%Page: " + page.getNumber() + " " + page.getNumber());
- write("%%PageBoundingBox: 0 0 " +
- Math.round(page.getWidth() / 1000f) + " " +
- Math.round(page.getHeight() / 1000f));
- write("%%BeginPageSetup");
- write("FOPprocs begin");
- write("FOPFonts begin");
- write("0.001 0.001 scale");
- write("%%EndPageSetup");
- renderRegions(page);
- write("showpage");
- write("%%PageTrailer");
- write("%%EndPage"); //This is non-standard, but used by Adobe.
- }
-
- /**
- * render a leader area to PostScript
- *
- * @param area the area to render
- */
- public void renderLeaderArea(LeaderArea area) {
- int rx = this.currentXPosition;
- int ry = this.currentYPosition;
- int w = area.getContentWidth();
- int th = area.getRuleThickness();
- int th2 = th / 2;
- int th3 = th / 3;
- int th4 = th / 4;
-
- switch (area.getLeaderPattern()) {
- case LeaderPattern.SPACE:
- // NOP
-
- break;
- case LeaderPattern.RULE:
- if (area.getRuleStyle() == RuleStyle.NONE)
- break;
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("gsave");
- write("0 setlinecap");
- switch (area.getRuleStyle()) {
- case RuleStyle.DOTTED:
- write("newpath");
- write("[1000 3000] 0 setdash");
- write(th + " setlinewidth");
- write(rx + " " + ry + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- break;
- case RuleStyle.DASHED:
- write("newpath");
- write("[3000 3000] 0 setdash");
- write(th + " setlinewidth");
- write(rx + " " + ry + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- break;
- case RuleStyle.SOLID:
- write("newpath");
- write(th + " setlinewidth");
- write(rx + " " + ry + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- break;
- case RuleStyle.DOUBLE:
- write("newpath");
- write(th3 + " setlinewidth");
- write(rx + " " + (ry - th3) + " M");
- write(w + " 0 rlineto");
- write(rx + " " + (ry + th3) + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- break;
- case RuleStyle.GROOVE:
- write(th2 + " setlinewidth");
- write("newpath");
- write(rx + " " + (ry - th4) + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- write("newpath");
- write(rx + " " + (ry + th4) + " M");
- write(w + " 0 rlineto");
- useColor(1, 1, 1); // white
- write("stroke");
- break;
- case RuleStyle.RIDGE:
- write(th2 + " setlinewidth");
- write("newpath");
- write(rx + " " + (ry - th4) + " M");
- write(w + " 0 rlineto");
- useColor(1, 1, 1); // white
- write("stroke");
- write("newpath");
- write(rx + " " + (ry + th4) + " M");
- write(w + " 0 rlineto");
- useColor(area.getRed(), area.getGreen(), area.getBlue());
- write("stroke");
- break;
- }
- write("grestore");
- break;
- case LeaderPattern.DOTS:
- comment("% --- Leader dots NYI");
- log.error("Leader dots: Not yet implemented");
- break;
- case LeaderPattern.USECONTENT:
- comment("% --- Leader use-content NYI");
- log.error("Leader use-content: Not yet implemented");
- break;
- }
- this.currentXPosition += area.getContentWidth();
- write(area.getContentWidth() + " 0 RM");
- }
-
- protected void doFrame(Area area) {
- int w, h;
- int rx = this.currentAreaContainerXPosition;
- w = area.getContentWidth();
- BorderAndPadding bap = area.getBorderAndPadding();
-
- if (area instanceof BlockArea)
- rx += ((BlockArea)area).getStartIndent();
-
- h = area.getContentHeight();
- int ry = this.currentYPosition;
-
- rx = rx - area.getPaddingLeft();
- ry = ry + area.getPaddingTop();
- w = w + area.getPaddingLeft() + area.getPaddingRight();
- h = h + area.getPaddingTop() + area.getPaddingBottom();
-
- rx = rx - area.getBorderLeftWidth();
- ry = ry + area.getBorderTopWidth();
- w = w + area.getBorderLeftWidth() + area.getBorderRightWidth();
- h = h + area.getBorderTopWidth() + area.getBorderBottomWidth();
-
- doBackground(area, rx, ry, w, h);
-
- if (area.getBorderTopWidth() != 0) {
- write("newpath");
- write(rx + " " + ry + " M");
- write(w + " 0 rlineto");
- write(area.getBorderTopWidth() + " setlinewidth");
- write("0 setlinecap");
- useColor(bap.getBorderColor(BorderAndPadding.TOP));
- write("stroke");
- }
- if (area.getBorderLeftWidth() != 0) {
- write("newpath");
- write(rx + " " + ry + " M");
- write("0 " + (-h) + " rlineto");
- write(area.getBorderLeftWidth() + " setlinewidth");
- write("0 setlinecap");
- useColor(bap.getBorderColor(BorderAndPadding.LEFT));
- write("stroke");
- }
- if (area.getBorderRightWidth() != 0) {
- write("newpath");
- write((rx + w) + " " + ry + " M");
- write("0 " + (-h) + " rlineto");
- write(area.getBorderRightWidth() + " setlinewidth");
- write("0 setlinecap");
- useColor(bap.getBorderColor(BorderAndPadding.RIGHT));
- write("stroke");
- }
- if (area.getBorderBottomWidth() != 0) {
- write("newpath");
- write(rx + " " + (ry - h) + " M");
- write(w + " 0 rlineto");
- write(area.getBorderBottomWidth() + " setlinewidth");
- write("0 setlinecap");
- useColor(bap.getBorderColor(BorderAndPadding.BOTTOM));
- write("stroke");
- }
- }
-
- private void useColor(ColorType col) {
- useColor(col.red(), col.green(), col.blue());
- }
-
- private void useColor(float red, float green, float blue) {
- if ((red != currRed) || (green != currGreen) || (blue != currBlue)) {
- write(red + " " + green + " " + blue + " setrgbcolor");
- currRed = red;
- currGreen = green;
- currBlue = blue;
- }
- }
-
- /**
- Default start renderer method. This would
- normally be overridden. ([EMAIL PROTECTED]).
- */
- public void startRenderer(OutputStream outputStream)
- throws IOException {
- log.debug("rendering areas to PostScript");
-
- this.pagecount = 0;
- this.out = new PSStream(outputStream);
- write("%!PS-Adobe-3.0");
- if (this.producer == null) {
- this.producer = org.apache.fop.apps.Version.getVersion();
- }
- write("%%Creator: "+this.producer);
- write("%%Pages: (atend)");
- write("%%DocumentProcessColors: Black");
- write("%%DocumentSuppliedResources: procset FOPFonts");
- write("%%EndComments");
- write("%%BeginDefaults");
- write("%%EndDefaults");
- write("%%BeginProlog");
- write("%%EndProlog");
- write("%%BeginSetup");
- writeProcs();
- 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");
- }
-
- /**
- Default stop renderer method. This would
- normally be overridden. ([EMAIL PROTECTED]).
- */
- public void stopRenderer(OutputStream outputStream)
- throws IOException {
- write("%%Trailer");
- write("%%Pages: "+this.pagecount);
- write("%%EOF");
- this.out.flush();
- log.debug("written out PostScript");
- }
-
- public void render(Page page, OutputStream outputStream) {
- this.renderPage(page);
- }
-}
+/*
+ * $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;
+
+// FOP
+import org.apache.fop.svg.SVGArea;
+import org.apache.fop.render.AbstractRenderer;
+import org.apache.fop.render.Renderer;
+import org.apache.fop.image.ImageArea;
+import org.apache.fop.image.FopImage;
+import org.apache.fop.image.FopImageException;
+import org.apache.fop.image.JpegImage;
+import org.apache.fop.layout.*;
+import org.apache.fop.layout.inline.*;
+import org.apache.fop.datatypes.*;
+import org.apache.fop.fo.properties.*;
+import org.apache.fop.render.pdf.Font;
+import org.apache.fop.image.*;
+import org.apache.fop.apps.FOPException;
+
+import org.apache.batik.bridge.*;
+import org.apache.batik.swing.svg.*;
+import org.apache.batik.swing.gvt.*;
+import org.apache.batik.gvt.*;
+import org.apache.batik.gvt.renderer.*;
+import org.apache.batik.gvt.filter.*;
+import org.apache.batik.gvt.event.*;
+
+// SVG
+import org.w3c.dom.svg.SVGSVGElement;
+import org.w3c.dom.svg.SVGDocument;
+import org.w3c.dom.*;
+import org.w3c.dom.svg.*;
+
+// Java
+import java.io.*;
+import java.util.*;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Dimension2D;
+import java.awt.Point;
+import java.awt.RenderingHints;
+import java.awt.Dimension;
+
+/*
+PostScript renderer
+
+Remarks:
+- If anyone modifies this renderer please make sure to also follow the DSC to
+ make it simpler to programmatically modify the generated Postscript files
+ (ex. extract pages etc.).
+- The filters in use are hardcoded at the moment.
+- Modified by Mark Lillywhite [EMAIL PROTECTED], to use the new
+ Renderer interface. This PostScript renderer appears to be the
+ most efficient at producing output.
+
+TODO-List:
+- Character size/spacing
+- SVG Transcoder for Batik
+- configuration
+- move to PrintRenderer
+- maybe improve filters (I'm not very proud of them)
+- add a RunLengthEncode filter (useful for Level 2 Postscript)
+- Improve DocumentProcessColors stuff (probably needs to be configurable, then maybe
+ add a color to grayscale conversion for bitmaps to make output smaller (See
+ PCLRenderer)
+- enhanced font support and font embedding
+- support different character encodings
+- try to implement image transparency
+- Add PPD support
+- fix border painting (see table.fo)
+
+*/
+
+/**
+ * Renderer that renders to PostScript.
+ * <br>
+ * This class currently generates PostScript Level 2 code. The only exception
+ * is the FlateEncode filter which is a Level 3 feature. The PostScript code
+ * generated follows the Document Structuring Conventions (DSC) version 3.0.
+ *
+ * @author Jeremias M�rki
+ */
+public class PSRenderer extends AbstractRenderer {
+
+ /**
+ * the application producing the PostScript
+ */
+ protected String producer;
+
+ int imagecount = 0; // DEBUG
+ int pagecount = 0;
+
+ private boolean enableComments = true;
+
+ /**
+ * the stream used to output the PostScript
+ */
+ protected PSStream out;
+ private boolean ioTrouble = false;
+
+ private String currentFontName;
+ private int currentFontSize;
+ private int pageHeight;
+ private int pageWidth;
+ private float currRed;
+ private float currGreen;
+ private float currBlue;
+
+ private FontInfo fontInfo;
+
+ private int psLevel = 3;
+
+ protected IDReferences idReferences;
+
+ protected java.util.HashMap options;
+
+
+ /**
+ * set the document's producer
+ *
+ * @param producer string indicating application producing the PostScript
+ */
+ public void setProducer(String producer) {
+ this.producer = producer;
+ }
+
+
+ /**
+ * set up renderer options
+ */
+ public void setOptions(java.util.HashMap options) {
+ this.options = options;
+ }
+
+
+ /**
+ * Sets the PostScript Level to generate.
+ *
+ * @param level You can specify either 2 or 3 for the PostScript Level
+ */
+ public void setPSLevel(int level) {
+ switch (level) {
+ case 2:
+ case 3:
+ this.psLevel = level;
+ break;
+ default:
+ throw new IllegalArgumentException("Only PostScript Levels 2 and 3
are supported");
+ }
+ }
+
+
+ public int getPSLevel() {
+ return this.psLevel;
+ }
+
+
+ /**
+ * write out a command
+ */
+ protected void write(String cmd) {
+ try {
+ out.write(cmd);
+ } catch (IOException e) {
+ if (!ioTrouble)
+ e.printStackTrace();
+ ioTrouble = true;
+ }
+ }
+
+ /**
+ * write out a comment
+ */
+ protected void comment(String comment) {
+ if (this.enableComments)
+ write(comment);
+ }
+
+ protected void writeProcs() {
+ write("%%BeginResource: procset FOPprocs");
+ write("%%Title: Utility procedures");
+ write("/FOPprocs 20 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("/A/ashow ld");
+ write("/cp/closepath ld");
+ write("/re {4 2 roll M"); //define rectangle
+ write("1 index 0 rlineto");
+ write("0 exch rlineto");
+ write("neg 0 rlineto");
+ write("cp } bd");
+
+ write("/ux 0.0 def");
+ write("/uy 0.0 def");
+
+ // <font> <size> 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");
+ write("end def");
+ write("%%EndResource");
+ }
+
+ protected void writeFontDict(FontInfo fontInfo) {
+ write("%%BeginResource: procset FOPFonts");
+ write("%%Title: Font setup (shortcuts) for this file");
+ write("/FOPFonts 100 dict dup begin");
+ // write("/gfF1{/Helvetica findfont} bd");
+ // write("/gfF3{/Helvetica-Bold findfont} bd");
+ HashMap fonts = fontInfo.getFonts();
+ Iterator enum = fonts.keySet().iterator();
+ while (enum.hasNext()) {
+ String key = (String)enum.next();
+ Font fm = (Font)fonts.get(key);
+ write("/" + key + " /" + fm.fontName() + " def");
+ }
+ write("end def");
+ write("%%EndResource");
+
+ //Rewrite font encodings
+ enum = fonts.keySet().iterator();
+ while (enum.hasNext()) {
+ String key = (String)enum.next();
+ Font fm = (Font)fonts.get(key);
+ write("/" + fm.fontName() + " 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.fontName() + " exch definefont pop");
+ }
+ }
+
+ protected void movetoCurrPosition() {
+ write(this.currentXPosition + " " + this.currentYPosition + " M");
+ }
+
+ /**
+ * set up the font info
+ *
+ * @param fontInfo the font info object to set up
+ */
+ public void setupFontInfo(FontInfo fontInfo)
+ throws FOPException {
+ /* use PDF's font setup to get PDF metrics */
+ org.apache.fop.render.pdf.FontSetup.setup(fontInfo);
+ this.fontInfo = fontInfo;
+ }
+
+ protected void addFilledRect(int x, int y, int w, int h,
+ ColorType col) {
+ // XXX: cater for braindead, legacy -ve heights
+ if (h < 0) {
+ h = -h;
+ }
+
+ write("newpath");
+ write(x + " " + y + " " + w + " " + -h + " re");
+ /*
+ 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");
+ }
+
+ /**
+ * render a display space to PostScript
+ *
+ * @param space the space to render
+ */
+ public void renderDisplaySpace(DisplaySpace space) {
+ // write("% --- DisplaySpace size="+space.getSize());
+ this.currentYPosition -= space.getSize();
+ movetoCurrPosition();
+ }
+
+ /**
+ * render a foreign object area
+ */
+ public void renderForeignObjectArea(ForeignObjectArea area) {
+ // if necessary need to scale and align the content
+ this.currentXPosition = this.currentXPosition + area.getXOffset();
+ int plOffset = 0;
+ Area parent = area.getParent();
+ if (parent instanceof LineArea) {
+ plOffset = ((LineArea)parent).getPlacementOffset();
+ }
+ this.currentYPosition += plOffset;
+ area.getObject().render(this);
+ this.currentXPosition += area.getEffectiveWidth();
+ this.currentYPosition -= plOffset;
+ movetoCurrPosition();
+ }
+
+ /**
+ * render an SVG area to PostScript
+ *
+ * @param area the area to render
+ */
+ public void renderSVGArea(SVGArea area) {
+ int x = this.currentXPosition;
+ int y = this.currentYPosition;
+ renderSVGDocument(area.getSVGDocument(), x, y, area.getFontState());
+ }
+
+
+ /**
+ * render SVG document to PostScript
+ *
+ * @param doc the document to render
+ * @param x the x offset
+ * @param y the y offset
+ * @param fs the fontstate to use
+ */
+ protected void renderSVGDocument(Document doc, int x, int y,
+ FontState fs) {
+ org.apache.fop.svg.SVGUserAgent userAgent
+ = new org.apache.fop.svg.SVGUserAgent(new AffineTransform());
+ userAgent.setLogger(log);
+
+ GVTBuilder builder = new GVTBuilder();
+ BridgeContext ctx = new BridgeContext(userAgent);
+
+ GraphicsNode root;
+ try {
+ root = builder.build(ctx, doc);
+ } catch (Exception e) {
+ log.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;
+
+ //log.debug("drawing SVG image: "+x+"/"+y+" "+w+"/"+h);
+
+ ctx = null;
+ builder = null;
+
+ float sx = 1, sy = -1;
+ int xOffset = x, yOffset = y;
+
+ comment("% --- SVG Area");
+ write("gsave");
+ if (w != 0 && h != 0) {
+ write("newpath");
+ write(x + " " + y + " M");
+ write((x + w) + " " + y + " rlineto");
+ write((x + w) + " " + (y - h) + " rlineto");
+ write(x + " " + (y - h) + " rlineto");
+ write("closepath");
+ write("clippath");
+ }
+ // 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.
+ write(xOffset + " " + yOffset + " translate");
+ write(sx + " " + sy + " scale");
+
+ PSGraphics2D graphics = new PSGraphics2D(false, fs,
+ this, currentFontName,
+ currentFontSize,
+ currentXPosition,
+ currentYPosition);
+ graphics.setGraphicContext(new
org.apache.batik.ext.awt.g2d.GraphicContext());
+ try {
+ root.paint(graphics);
+ } catch (Exception e) {
+ log.error("svg graphic could not be rendered: "
+ + e.getMessage(), e);
+ }
+
+ write("grestore");
+
+ comment("% --- SVG Area end");
+ }
+
+ /**
+ * Renders an image, scaling it to the given width and height.
+ * If the scaled width and height is the same intrinsic size
+ * of the image, the image is not scaled.
+ *
+ * @param x the x position of left edge in millipoints
+ * @param y the y position of top edge in millipoints
+ * @param w the width in millipoints
+ * @param h the height in millipoints
+ * @param image the image to be rendered
+ * @param fs the font state to use when rendering text
+ * in non-bitmapped images.
+ */
+ protected void drawImageScaled(int x, int y, int w, int h,
+ FopImage image,
+ FontState fs) {
+ //log.debug("drawing scaled image: "+x+"/"+y+" "+w+"/"+h);
+ if (image instanceof SVGImage) {
+ try {
+ renderSVGDocument(((SVGImage)image).getSVGDocument(), x, y, fs);
+ } catch (FopImageException e) {
+ log.error("Error rendering SVG image", e);
+ }
+ } else if (image instanceof EPSImage) {
+ renderEPS(image, x, y, w, h);
+ } else {
+ renderBitmap(image, x, y, w, h);
+ }
+ }
+
+ /**
+ * Renders an image, clipping it as specified.
+ *
+ * @param x the x position of left edge in millipoints.
+ * @param y the y position of top edge in millipoints.
+ * @param clipX the left edge of the clip in millipoints
+ * @param clipY the top edge of the clip in millipoints
+ * @param clipW the clip width in millipoints
+ * @param clipH the clip height in millipoints
+ * @param image the image to be rendered
+ * @param fs the font state to use when rendering text
+ * in non-bitmapped images.
+ */
+ protected void drawImageClipped(int x, int y,
+ int clipX, int clipY,
+ int clipW, int clipH,
+ FopImage image,
+ FontState fs) {
+ //log.debug("drawing clipped image: "+x+"/"+y+" "+clipX+"/"+clipY+"
"+clipW+"/"+clipH);
+ write("gsave");
+ write(clipX + " " + clipY + " " + clipW + " " + clipH + " re");
+ write("clippath");
+
+ try {
+ int w = image.getWidth() * 1000;
+ int h = image.getHeight() * 1000;
+
+ drawImageScaled(x, y, w, h, image, fs);
+ } catch (FopImageException e) {
+ log.error("Error getting image extents", e);
+ }
+ write("grestore");
+ }
+
+ public void renderEPS(FopImage img, int x, int y, int w, int h) {
+ try {
+ EPSImage eimg = (EPSImage)img;
+ int[] bbox = eimg.getBBox();
+ int bboxw = bbox[2] - bbox[0];
+ int bboxh = bbox[3] - bbox[1];
+
+
+ write("%%BeginDocument: " + eimg.getDocName());
+ write("BeginEPSF");
+
+ write(x + " " + (y - h) + " translate");
+ write("0.0 rotate");
+ write((long)(w/bboxw) + " " + (long)(h/bboxh) + " scale");
+ write(-bbox[0] + " " + (-bbox[1]) + " translate");
+ write(bbox[0] + " " + bbox[1] + " " + bboxw + " " + bboxh + "
rectclip");
+ write("newpath");
+ out.writeByteArr(img.getBitmaps());
+ write("%%EndDocument");
+ write("EndEPSF");
+ write("");
+ } catch (Exception e) {
+ e.printStackTrace();
+ log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+ + e.getMessage() + ")", e);
+ }
+ }
+
+ public void renderBitmap(FopImage img, int x, int y, int w, int h) {
+ try {
+ boolean iscolor = img.getColorSpace().getColorSpace()
+ != ColorSpace.DEVICE_GRAY;
+ byte[] imgmap = img.getBitmaps();
+
+ write("gsave");
+ if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK)
+ write("/DeviceCMYK setcolorspace");
+ else
+ write("/DeviceRGB setcolorspace");
+
+ write(x + " " + (y - h) + " translate");
+ write(w + " " + h + " scale");
+ write("<<");
+ write(" /ImageType 1");
+ write(" /Width " + img.getWidth());
+ write(" /Height " + img.getHeight());
+ write(" /BitsPerComponent 8");
+ if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_CMYK) {
+ if (img.invertImage())
+ write(" /Decode [1 0 1 0 1 0 1 0]");
+ else
+ write(" /Decode [0 1 0 1 0 1 0 1]");
+ } else if (iscolor) {
+ write(" /Decode [0 1 0 1 0 1]");
+ } else {
+ write(" /Decode [0 1]");
+ }
+ // Setup scanning for left-to-right and top-to-bottom
+ write(" /ImageMatrix [" + img.getWidth() + " 0 0 -"
+ + img.getHeight() + " 0 " + img.getHeight() + "]");
+
+ if (img instanceof JpegImage) {
+ write(" /DataSource currentfile /ASCII85Decode filter /DCTDecode
filter");
+ } else {
+ if (this.psLevel >= 3) {
+ write(" /DataSource currentfile /ASCII85Decode filter
/FlateDecode filter");
+ } else {
+ write(" /DataSource currentfile /ASCII85Decode filter
/RunLengthDecode filter");
+ }
+ }
+ // write(" /DataSource currentfile /ASCIIHexDecode filter /FlateDecode
filter");
+ // write(" /DataSource currentfile /ASCIIHexDecode filter
/RunLengthDecode filter");
+ // write(" /DataSource currentfile /ASCIIHexDecode filter");
+ // write(" /DataSource currentfile /ASCII85Decode filter");
+ // write(" /DataSource currentfile /RunLengthDecode filter");
+ write(">>");
+ write("image");
+
+ /*
+ * for (int y=0; y<img.getHeight(); y++) {
+ * int indx = y * img.getWidth();
+ * if (iscolor) indx*= 3;
+ * for (int x=0; x<img.getWidth(); x++) {
+ * if (iscolor) {
+ * writeASCIIHex(imgmap[indx++] & 0xFF);
+ * writeASCIIHex(imgmap[indx++] & 0xFF);
+ * writeASCIIHex(imgmap[indx++] & 0xFF);
+ * } else {
+ * writeASCIIHex(imgmap[indx++] & 0xFF);
+ * }
+ * }
+ * }
+ */
+ try {
+ // imgmap[0] = 1;
+ OutputStream out = this.out;
+ out = new ASCII85OutputStream(out);
+ if (!(img instanceof JpegImage)) {
+ if (this.psLevel >= 3) {
+ out = new FlateEncodeOutputStream(out);
+ } else {
+ out = new RunLengthEncodeOutputStream(out);
+ }
+ }
+ out.write(imgmap);
+ ((Finalizable)out).finalizeStream();
+ } catch (IOException e) {
+ if (!ioTrouble)
+ e.printStackTrace();
+ ioTrouble = true;
+ }
+
+ write("");
+ write("grestore");
+ } catch (FopImageException e) {
+ log.error("PSRenderer.renderImageArea(): Error rendering bitmap ("
+ + e.getMessage() + ")", e);
+ }
+ }
+
+ /**
+ * Render an image area.
+ *
+ * @param area the image area to render
+ */
+ public void renderImageArea(ImageArea area) {
+ // adapted from contribution by BoBoGi
+ int x = this.currentXPosition + area.getXOffset();
+ int ploffset = 0;
+ if (area.getParent() instanceof LineArea) {
+ ploffset = ((LineArea)area.getParent()).getPlacementOffset();
+ }
+ int y = this.currentYPosition + ploffset;
+ int w = area.getContentWidth();
+ int h = area.getHeight();
+
+ //this.currentYPosition -= h;
+ this.currentXPosition += w;
+
+ FopImage img = area.getImage();
+
+ if (img == null) {
+ log.error("Error while loading image: area.getImage() is null");
+ } else {
+ drawImageScaled(x, y, w, h, img, area.getFontState());
+ }
+ movetoCurrPosition();
+ }
+
+
+ /**
+ * render an image area to PostScript
+ *
+ * @param area the area to render
+ */
+ /*
+ public void renderImageArea(ImageArea area) {
+ int x = this.currentXPosition + area.getXOffset();
+ int ploffset = 0;
+ if (area.getParent() instanceof LineArea) {
+ ploffset = ((LineArea)area.getParent()).getPlacementOffset();
+ }
+ int y = this.currentYPosition + ploffset;
+ int w = area.getContentWidth();
+ int h = area.getHeight();
+ this.currentYPosition -= area.getHeight();
+
+ imagecount++;
+ // if (imagecount!=4) return;
+
+ comment("% --- ImageArea");
+ if (area.getImage() instanceof SVGImage) {
+ renderSVGDocument(((SVGImage)area.getImage()).getSVGDocument(), x, y,
area.getFontState());
+ } else if (area.getImage() instanceof EPSImage) {
+ renderEPS(area.getImage(), x, y, w, h);
+ } else {
+ renderBitmap(area.getImage(), x, y, w, h);
+ }
+ comment("% --- ImageArea end");
+ }*/
+
+ /**
+ * render an inline area to PostScript
+ *
+ * @param area the area to render
+ */
+ public void renderWordArea(WordArea area) {
+ movetoCurrPosition();
+ FontState fs = area.getFontState();
+ String fontWeight = fs.getFontWeight();
+ StringBuffer sb = new StringBuffer();
+ String s;
+ if (area.getPageNumberID()
+ != null) { // this text is a page number, so resolve it
+ s = idReferences.getPageNumber(area.getPageNumberID());
+ if (s == null) {
+ s = "";
+ }
+ } else {
+ s = area.getText();
+ }
+ int l = s.length();
+
+ for (int i = 0; i < l; i++) {
+ char ch = s.charAt(i);
+ char mch = fs.mapChar(ch);
+ if (mch > 127) {
+ sb = sb.append("\\" + Integer.toOctalString(mch));
+ } else {
+ String escape = "\\()[]{}";
+ if (escape.indexOf(mch) >= 0) {
+ sb.append("\\");
+ }
+ sb = sb.append(mch);
+ }
+ }
+
+ 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).
+ append(") A")).toString();
+ } else {
+ psString = (new StringBuffer("(").append(sb).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();
+ }
+
+ public void useFont(String name, int size) {
+ if ((currentFontName != name) || (currentFontSize != size)) {
+ write(name + " " + size + " F");
+ currentFontName = name;
+ currentFontSize = size;
+ }
+ }
+
+ /**
+ * render an inline space to PostScript
+ *
+ * @param space the space to render
+ */
+ public void renderInlineSpace(InlineSpace space) {
+ // write("% --- InlineSpace size="+space.getSize());
+ if (space.getUnderlined() || space.getLineThrough()
+ || space.getOverlined()) {
+ //start textdeko
+ movetoCurrPosition();
+ write("ULS");
+
+ write(space.getSize() + " 0 RM");
+
+ //end textdeko
+ if (space.getUnderlined())
+ write("ULE");
+ if (space.getLineThrough())
+ write("SOE");
+ if (space.getOverlined())
+ write("OLE");
+ }
+ this.currentXPosition += space.getSize();
+ }
+
+ /**
+ * render a line area to PostScript
+ *
+ * @param area the area to render
+ */
+ public void renderLineArea(LineArea area) {
+ int rx = this.currentAreaContainerXPosition + area.getStartIndent();
+ int ry = this.currentYPosition;
+ int w = area.getContentWidth();
+ int h = area.getHeight();
+
+ this.currentYPosition -= area.getPlacementOffset();
+ this.currentXPosition = rx;
+
+ int bl = this.currentYPosition;
+ // method is identical to super method except next line
+ movetoCurrPosition();
+
+ String fontWeight = area.getFontState().getFontWeight();
+ //comment("% --- LineArea begin font-weight="+fontWeight);
+ ArrayList children = area.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ Box b = (Box)children.get(i);
+ this.currentYPosition = ry - area.getPlacementOffset();
+ b.render(this);
+ }
+ //comment("% --- LineArea end");
+
+ this.currentYPosition = ry - h;
+ this.currentXPosition = rx;
+ }
+
+ /**
+ * render a page to PostScript
+ *
+ * @param page the page to render
+ */
+ public void renderPage(Page page) {
+ this.pagecount++;
+ this.idReferences = page.getIDReferences();
+
+ write("%%Page: " + page.getNumber() + " " + page.getNumber());
+ write("%%PageBoundingBox: 0 0 " +
+ Math.round(page.getWidth() / 1000f) + " " +
+ Math.round(page.getHeight() / 1000f));
+ write("%%BeginPageSetup");
+ write("FOPprocs begin");
+ write("FOPFonts begin");
+ write("0.001 0.001 scale");
+ write("%%EndPageSetup");
+ renderRegions(page);
+ write("showpage");
+ write("%%PageTrailer");
+ write("%%EndPage"); //This is non-standard, but used by Adobe.
+ }
+
+ /**
+ * render a leader area to PostScript
+ *
+ * @param area the area to render
+ */
+ public void renderLeaderArea(LeaderArea area) {
+ int rx = this.currentXPosition;
+ int ry = this.currentYPosition;
+ int w = area.getContentWidth();
+ int th = area.getRuleThickness();
+ int th2 = th / 2;
+ int th3 = th / 3;
+ int th4 = th / 4;
+
+ switch (area.getLeaderPattern()) {
+ case LeaderPattern.SPACE:
+ // NOP
+
+ break;
+ case LeaderPattern.RULE:
+ if (area.getRuleStyle() == RuleStyle.NONE)
+ break;
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("gsave");
+ write("0 setlinecap");
+ switch (area.getRuleStyle()) {
+ case RuleStyle.DOTTED:
+ write("newpath");
+ write("[1000 3000] 0 setdash");
+ write(th + " setlinewidth");
+ write(rx + " " + ry + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ break;
+ case RuleStyle.DASHED:
+ write("newpath");
+ write("[3000 3000] 0 setdash");
+ write(th + " setlinewidth");
+ write(rx + " " + ry + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ break;
+ case RuleStyle.SOLID:
+ write("newpath");
+ write(th + " setlinewidth");
+ write(rx + " " + ry + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ break;
+ case RuleStyle.DOUBLE:
+ write("newpath");
+ write(th3 + " setlinewidth");
+ write(rx + " " + (ry - th3) + " M");
+ write(w + " 0 rlineto");
+ write(rx + " " + (ry + th3) + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ break;
+ case RuleStyle.GROOVE:
+ write(th2 + " setlinewidth");
+ write("newpath");
+ write(rx + " " + (ry - th4) + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ write("newpath");
+ write(rx + " " + (ry + th4) + " M");
+ write(w + " 0 rlineto");
+ useColor(1, 1, 1); // white
+ write("stroke");
+ break;
+ case RuleStyle.RIDGE:
+ write(th2 + " setlinewidth");
+ write("newpath");
+ write(rx + " " + (ry - th4) + " M");
+ write(w + " 0 rlineto");
+ useColor(1, 1, 1); // white
+ write("stroke");
+ write("newpath");
+ write(rx + " " + (ry + th4) + " M");
+ write(w + " 0 rlineto");
+ useColor(area.getRed(), area.getGreen(), area.getBlue());
+ write("stroke");
+ break;
+ }
+ write("grestore");
+ break;
+ case LeaderPattern.DOTS:
+ comment("% --- Leader dots NYI");
+ log.error("Leader dots: Not yet implemented");
+ break;
+ case LeaderPattern.USECONTENT:
+ comment("% --- Leader use-content NYI");
+ log.error("Leader use-content: Not yet implemented");
+ break;
+ }
+ this.currentXPosition += area.getContentWidth();
+ write(area.getContentWidth() + " 0 RM");
+ }
+
+ protected void doFrame(Area area) {
+ int w, h;
+ int rx = this.currentAreaContainerXPosition;
+ w = area.getContentWidth();
+ BorderAndPadding bap = area.getBorderAndPadding();
+
+ if (area instanceof BlockArea)
+ rx += ((BlockArea)area).getStartIndent();
+
+ h = area.getContentHeight();
+ int ry = this.currentYPosition;
+
+ rx = rx - area.getPaddingLeft();
+ ry = ry + area.getPaddingTop();
+ w = w + area.getPaddingLeft() + area.getPaddingRight();
+ h = h + area.getPaddingTop() + area.getPaddingBottom();
+
+ rx = rx - area.getBorderLeftWidth();
+ ry = ry + area.getBorderTopWidth();
+ w = w + area.getBorderLeftWidth() + area.getBorderRightWidth();
+ h = h + area.getBorderTopWidth() + area.getBorderBottomWidth();
+
+ doBackground(area, rx, ry, w, h);
+
+ if (area.getBorderTopWidth() != 0) {
+ write("newpath");
+ write(rx + " " + ry + " M");
+ write(w + " 0 rlineto");
+ write(area.getBorderTopWidth() + " setlinewidth");
+ write("0 setlinecap");
+ useColor(bap.getBorderColor(BorderAndPadding.TOP));
+ write("stroke");
+ }
+ if (area.getBorderLeftWidth() != 0) {
+ write("newpath");
+ write(rx + " " + ry + " M");
+ write("0 " + (-h) + " rlineto");
+ write(area.getBorderLeftWidth() + " setlinewidth");
+ write("0 setlinecap");
+ useColor(bap.getBorderColor(BorderAndPadding.LEFT));
+ write("stroke");
+ }
+ if (area.getBorderRightWidth() != 0) {
+ write("newpath");
+ write((rx + w) + " " + ry + " M");
+ write("0 " + (-h) + " rlineto");
+ write(area.getBorderRightWidth() + " setlinewidth");
+ write("0 setlinecap");
+ useColor(bap.getBorderColor(BorderAndPadding.RIGHT));
+ write("stroke");
+ }
+ if (area.getBorderBottomWidth() != 0) {
+ write("newpath");
+ write(rx + " " + (ry - h) + " M");
+ write(w + " 0 rlineto");
+ write(area.getBorderBottomWidth() + " setlinewidth");
+ write("0 setlinecap");
+ useColor(bap.getBorderColor(BorderAndPadding.BOTTOM));
+ write("stroke");
+ }
+ }
+
+ private void useColor(ColorType col) {
+ useColor(col.red(), col.green(), col.blue());
+ }
+
+ private void useColor(float red, float green, float blue) {
+ if ((red != currRed) || (green != currGreen) || (blue != currBlue)) {
+ write(red + " " + green + " " + blue + " setrgbcolor");
+ currRed = red;
+ currGreen = green;
+ currBlue = blue;
+ }
+ }
+
+ /**
+ Default start renderer method. This would
+ normally be overridden. ([EMAIL PROTECTED]).
+ */
+ public void startRenderer(OutputStream outputStream)
+ throws IOException {
+ log.debug("rendering areas to PostScript");
+
+ this.pagecount = 0;
+ this.out = new PSStream(outputStream);
+ write("%!PS-Adobe-3.0");
+ if (this.producer == null) {
+ this.producer = org.apache.fop.apps.Version.getVersion();
+ }
+ write("%%Creator: "+this.producer);
+ write("%%Pages: (atend)");
+ write("%%DocumentProcessColors: Black");
+ write("%%DocumentSuppliedResources: procset FOPFonts");
+ write("%%EndComments");
+ write("%%BeginDefaults");
+ write("%%EndDefaults");
+ write("%%BeginProlog");
+ write("%%EndProlog");
+ write("%%BeginSetup");
+ writeProcs();
+ 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");
+ }
+
+ /**
+ Default stop renderer method. This would
+ normally be overridden. ([EMAIL PROTECTED]).
+ */
+ public void stopRenderer(OutputStream outputStream)
+ throws IOException {
+ write("%%Trailer");
+ write("%%Pages: "+this.pagecount);
+ write("%%EOF");
+ this.out.flush();
+ log.debug("written out PostScript");
+ }
+
+ public void render(Page page, OutputStream outputStream) {
+ this.renderPage(page);
+ }
+}
No revision
No revision
1.1.2.1 +0 -0
xml-fop/src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java
Index: RunLengthEncodeOutputStream.java
===================================================================
RCS file:
/home/cvs/xml-fop/src/org/apache/fop/render/ps/RunLengthEncodeOutputStream.java,v
retrieving revision 1.1
retrieving revision 1.1.2.1
diff -u -r1.1 -r1.1.2.1
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]