1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222 |
- /*
- * $Id$
- * ============================================================================
- * The Apache Software License, Version 1.1
- * ============================================================================
- *
- * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modifica-
- * tion, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. The end-user documentation included with the redistribution, if any, must
- * include the following acknowledgment: "This product includes software
- * developed by the Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself, if
- * and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "FOP" and "Apache Software Foundation" must not be used to
- * endorse or promote products derived from this software without prior
- * written permission. For written permission, please contact
- * apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache", nor may
- * "Apache" appear in their name, without prior written permission of the
- * Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
- * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * ============================================================================
- *
- * This software consists of voluntary contributions made by many individuals
- * on behalf of the Apache Software Foundation and was originally created by
- * James Tauber <jtauber@jtauber.com>. For more information on the Apache
- * Software Foundation, please see <http://www.apache.org/>.
- */
- package org.apache.fop.render.ps;
-
- // FOP
- import org.apache.fop.svg.SVGArea;
- import org.apache.fop.render.AbstractRenderer;
- 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.FontInfo;
- import org.apache.fop.layout.DisplaySpace;
- import org.apache.fop.layout.FontState;
- import org.apache.fop.layout.LineArea;
- import org.apache.fop.layout.Page;
- import org.apache.fop.layout.Area;
- import org.apache.fop.layout.Box;
- import org.apache.fop.layout.BorderAndPadding;
- import org.apache.fop.layout.BlockArea;
- import org.apache.fop.layout.inline.ForeignObjectArea;
- import org.apache.fop.layout.inline.WordArea;
- import org.apache.fop.layout.inline.InlineSpace;
- import org.apache.fop.layout.inline.LeaderArea;
- import org.apache.fop.datatypes.ColorType;
- import org.apache.fop.datatypes.ColorSpace;
- import org.apache.fop.fo.properties.LeaderPattern;
- import org.apache.fop.fo.properties.RuleStyle;
- import org.apache.fop.fonts.Glyphs;
- import org.apache.fop.render.pdf.Font;
- import org.apache.fop.image.SVGImage;
- import org.apache.fop.image.EPSImage;
- import org.apache.fop.apps.FOPException;
-
- import org.apache.batik.bridge.GVTBuilder;
- import org.apache.batik.bridge.BridgeContext;
- import org.apache.batik.bridge.ViewBox;
- import org.apache.batik.gvt.GraphicsNode;
-
- // SVG
- import org.w3c.dom.Document;
- import org.w3c.dom.svg.SVGDocument;
- import org.w3c.dom.svg.SVGSVGElement;
-
- // Java
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.awt.geom.AffineTransform;
-
- /*
- 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 mark-fop@inomial.com, 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
- - fix character encodings (Helvetica uses WinAnsiEncoding internally but is
- encoded as ISOLatin1 in PS)
- - 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;
- private boolean autoRotateLandscape = false;
-
- /**
- * 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 java.util.Map 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.Map 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;
- }
-
- public void setAutoRotateLandscape(boolean value) {
- this.autoRotateLandscape = value;
- }
-
- public boolean isAutoRotateLandscape() {
- return this.autoRotateLandscape;
- }
-
- /**
- * 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");
- Map fonts = fontInfo.getFonts();
- Iterator iter = fonts.keySet().iterator();
- while (iter.hasNext()) {
- String key = (String)iter.next();
- Font fm = (Font)fonts.get(key);
- write("/" + key + " /" + fm.fontName() + " def");
- }
- write("end def");
- write("%%EndResource");
- defineWinAnsiEncoding();
-
- //Rewrite font encodings
- iter = fonts.keySet().iterator();
- while (iter.hasNext()) {
- String key = (String)iter.next();
- Font fm = (Font)fonts.get(key);
- if (null == fm.encoding()) {
- //ignore (ZapfDingbats and Symbol run through here
- //TODO: ZapfDingbats and Symbol should get getEncoding() fixed!
- } else if ("WinAnsiEncoding".equals(fm.encoding())) {
- write("/" + fm.fontName() + " findfont");
- write("dup length dict begin");
- write(" {1 index /FID ne {def} {pop pop} ifelse} forall");
- write(" /Encoding " + fm.encoding() + " def");
- write(" currentdict");
- write("end");
- write("/" + fm.fontName() + " exch definefont pop");
- } else {
- log.warn("Only WinAnsiEncoding is supported. Font '"
- + fm.fontName() + "' asks for: " + fm.encoding());
- }
- }
- }
-
- private void defineWinAnsiEncoding() {
- write("/WinAnsiEncoding [");
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < Glyphs.winAnsiEncoding.length; i++) {
- if (i > 0) {
- if ((i % 5) == 0) {
- write(sb.toString());
- sb.setLength(0);
- } else {
- sb.append(" ");
- }
- }
- final char ch = Glyphs.winAnsiEncoding[i];
- final String glyphname = Glyphs.charToGlyphName(ch);
- if ("".equals(glyphname)) {
- sb.append("/" + Glyphs.notdef);
- } else {
- sb.append("/");
- sb.append(glyphname);
- }
- }
- write(sb.toString());
- write("] def");
- }
-
-
-
- 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();
- }
-
- /**
- * 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;
- }
-
- /**
- * 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);
- SVGSVGElement svg = ((SVGDocument) doc).getRootElement();
- AffineTransform at = ViewBox.getPreserveAspectRatioTransform(svg,
- w/1000f , h/1000f );
-
- 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((at.getTranslateX() * 1000) + " "
- + (-at.getTranslateY() * 1000) + " translate");
- write(sx * at.getScaleX() + " " + sy * at.getScaleY() + " 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 if (img.getColorSpace().getColorSpace() == ColorSpace.DEVICE_GRAY)
- write("/DeviceGray setcolorspace");
- else
- write("/DeviceRGB setcolorspace");
-
- write(x + " " + (y - h) + " translate");
- write(w + " " + h + " scale");
-
- write("{{");
- // Template: (RawData is used for the EOF signal only)
- // write("/RawData currentfile <first filter> filter def");
- // write("/Data RawData <second filter> <third filter> [...] def");
- if (img instanceof JpegImage) {
- write("/RawData currentfile /ASCII85Decode filter def");
- write("/Data RawData << >> /DCTDecode filter def");
- } else {
- if (this.psLevel >= 3) {
- write("/RawData currentfile /ASCII85Decode filter def");
- write("/Data RawData /FlateDecode filter def");
- } else {
- write("/RawData currentfile /ASCII85Decode filter def");
- write("/Data RawData /RunLengthDecode filter def");
- }
- }
- 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() + "]");
-
- write(" /DataSource Data");
- write(">>");
- write("image");
- /* the following two lines could be enabled if something still goes wrong
- * write("Data closefile");
- * write("RawData flushfile");
- */
- write("} stopped {handleerror} if");
- write(" RawData flushfile");
- write("} exec");
-
- /*
- * 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) {
- //nop
- } else {
- if (this.psLevel >= 3) {
- out = new FlateEncodeOutputStream(out);
- } else {
- out = new RunLengthEncodeOutputStream(out);
- }
- }
- out.write(imgmap);
- if (out instanceof Finalizable) {
- ((Finalizable)out).finalizeStream();
- } else {
- out.flush();
- }
- } 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());
- }
- }
-
-
- /**
- * 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 = 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 {
- final 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.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();
- }
-
- 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);
- List 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() + " " + this.pagecount);
-
- final long pagewidth = page.getWidth();
- final long pageheight = page.getHeight();
- final double pspagewidth = pagewidth / 1000f;
- final double pspageheight = pageheight / 1000f;
- boolean rotate = false;
- if (isAutoRotateLandscape() && (pageheight < pagewidth)) {
- rotate = true;
- write("%%PageBoundingBox: 0 0 " +
- Math.round(pspageheight) + " " +
- Math.round(pspagewidth));
- write("%%PageOrientation: Landscape");
- } else {
- write("%%PageBoundingBox: 0 0 " +
- Math.round(pspagewidth) + " " +
- Math.round(pspageheight));
- if (isAutoRotateLandscape()) {
- write("%%PageOrientation: Portrait");
- }
- }
-
- write("%%BeginPageSetup");
- if (rotate) {
- write(Math.round(pspageheight) + " 0 translate");
- write("90 rotate");
- }
- 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. (mark-fop@inomial.com).
- */
- 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("FOPprocs begin");
- write("FOPFonts begin");
-
- write("%%EndSetup");
- }
-
- /**
- Default stop renderer method. This would
- normally be overridden. (mark-fop@inomial.com).
- */
- 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);
- }
- }
|