jeremias 2002/06/11 22:41:02 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 ASCII85OutputStream.java ASCIIHexOutputStream.java Finalizable.java FlateEncodeOutputStream.java Removed: src/org/apache/fop/render/ps Tag: fop-0_20_2-maintain ASCII85EncodeFilter.java ASCIIHexEncodeFilter.java Filter.java FilterThread.java FlateEncodeFilter.java Log: Fixed vertical image position bug Submitted by: Huikang Xu <[EMAIL PROTECTED]> Fixed horizontal image position bug (See images.fo) Added %%Pages and %%PageBoundingBox DSC comments (removes error messages from GhostView) Split FOPFonts proc into FOPprocs and FOPFonts Refactored encoding filters for PS renderer (now: descendants of FilteredOutputStream) Fixed letter spacing Revision Changes Path No revision No revision 1.15.2.5 +208 -97 xml-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.4 retrieving revision 1.15.2.5 diff -u -r1.15.2.4 -r1.15.2.5 --- PSRenderer.java 11 Jun 2002 00:01:15 -0000 1.15.2.4 +++ PSRenderer.java 12 Jun 2002 05:41:02 -0000 1.15.2.5 @@ -1,6 +1,6 @@ /* * $Id$ - * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * 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. */ @@ -51,29 +51,42 @@ 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 filters in use - * are hardcoded at the moment. - * <br> - * This class follows the Document Structuring Conventions (DSC) version 3.0 - * (If I did everything right). 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.). - * <br> - * TODO: 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), font embedding, support different character encodings, try to - * implement image transparency, positioning of images is wrong etc. <P> - * - * Modified by Mark Lillywhite [EMAIL PROTECTED], to use the new - * Renderer interface. This PostScript renderer appears to be the - * most efficient at producing output. + * 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 */ @@ -85,6 +98,7 @@ protected String producer; int imagecount = 0; // DEBUG + int pagecount = 0; private boolean enableComments = true; @@ -147,21 +161,25 @@ write(comment); } - protected void writeFontDict(FontInfo fontInfo) { - write("%%BeginResource: procset FOPFonts"); - write("%%Title: Font setup (shortcuts) for this file"); - write("/FOPFonts 100 dict dup begin"); + 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"); - // write("/cf /Helvetica def"); - // write("/cs 12000 def"); // <font> <size> F write("/F {"); @@ -211,9 +229,14 @@ 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"); Hashtable fonts = fontInfo.getFonts(); @@ -225,6 +248,8 @@ } write("end def"); write("%%EndResource"); + + //Rewrite font encodings enum = fonts.keys(); while (enum.hasMoreElements()) { String key = (String)enum.nextElement(); @@ -257,18 +282,21 @@ 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; - } + // 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"); } @@ -289,7 +317,17 @@ */ 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(); } /** @@ -300,8 +338,20 @@ public void renderSVGArea(SVGArea area) { int x = this.currentXPosition; int y = this.currentYPosition; - Document doc = area.getSVGDocument(); + 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); @@ -320,6 +370,9 @@ // 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; @@ -343,7 +396,7 @@ write(xOffset + " " + yOffset + " translate"); write(sx + " " + sy + " scale"); - PSGraphics2D graphics = new PSGraphics2D(false, area.getFontState(), + PSGraphics2D graphics = new PSGraphics2D(false, fs, this, currentFontName, currentFontSize, currentXPosition, @@ -359,14 +412,13 @@ write("grestore"); comment("% --- SVG Area end"); - movetoCurrPosition(); } /** * 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 @@ -376,30 +428,54 @@ * in non-bitmapped images. */ protected void drawImageScaled(int x, int y, int w, int h, - FopImage image, - FontState fs) { - // XXX: implement this + 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. - * + * 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 fill the image to be rendered + * @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) { - // XXX: implement this + 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) { @@ -493,15 +569,13 @@ */ try { // imgmap[0] = 1; - InputStream bain = new ByteArrayInputStream(imgmap); - InputStream in; - in = bain; - if (!(img instanceof JpegImage)) - in = FlateEncodeFilter.filter(in); - // in = RunLengthEncodeFilter.filter(in); - // in = ASCIIHexEncodeFilter.filter(in); - in = ASCII85EncodeFilter.filter(in); - copyStream(in, this.out); + 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(); @@ -517,13 +591,48 @@ } /** + * 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.currentAreaContainerXPosition + area.getXOffset(); - int y = this.currentYPosition; + 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(); @@ -531,33 +640,16 @@ imagecount++; // if (imagecount!=4) return; - comment("% --- ImageArea"); - if (area.getImage() instanceof SVGImage) {} - else if (area.getImage() instanceof EPSImage) { + 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"); - } - - private long copyStream(InputStream in, OutputStream out, - int bufferSize) throws IOException { - long bytes_total = 0; - byte[] buf = new byte[bufferSize]; - int bytes_read; - while ((bytes_read = in.read(buf)) != -1) { - bytes_total += bytes_read; - out.write(buf, 0, bytes_read); - } - return bytes_total; - } - - - private long copyStream(InputStream in, - OutputStream out) throws IOException { - return copyStream(in, out, 4096); - } + }*/ /** * render an inline area to PostScript @@ -565,6 +657,7 @@ * @param area the area to render */ public void renderWordArea(WordArea area) { + movetoCurrPosition(); FontState fs = area.getFontState(); String fontWeight = fs.getFontWeight(); StringBuffer sb = new StringBuffer(); @@ -596,7 +689,8 @@ String psString = null; if (area.getFontState().getLetterSpacing() > 0) { - float f = area.getFontState().getLetterSpacing() * 1000 / this.currentFontSize; + //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 { @@ -637,17 +731,23 @@ */ public void renderInlineSpace(InlineSpace space) { // write("% --- InlineSpace size="+space.getSize()); - this.currentXPosition += space.getSize(); if (space.getUnderlined() || space.getLineThrough() - || space.getOverlined()) + || space.getOverlined()) { + //start textdeko + movetoCurrPosition(); write("ULS"); - write(space.getSize() + " 0 RM"); - if (space.getUnderlined()) - write("ULE"); - if (space.getLineThrough()) - write("SOE"); - if (space.getOverlined()) - write("OLE"); + + 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(); } /** @@ -669,14 +769,14 @@ movetoCurrPosition(); String fontWeight = area.getFontState().getFontWeight(); - // comment("% --- LineArea begin font-weight="+fontWeight); + //comment("% --- LineArea begin font-weight="+fontWeight); Enumeration e = area.getChildren().elements(); while (e.hasMoreElements()) { Box b = (Box)e.nextElement(); this.currentYPosition = ry - area.getPlacementOffset(); b.render(this); } - // comment("% --- LineArea end"); + //comment("% --- LineArea end"); this.currentYPosition = ry - h; this.currentXPosition = rx; @@ -688,12 +788,17 @@ * @param page the page to render */ public void renderPage(Page page) { + this.pagecount++; this.idReferences = page.getIDReferences(); BodyAreaContainer body; AreaContainer before, after; 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"); @@ -709,7 +814,7 @@ } write("showpage"); write("%%PageTrailer"); - write("%%EndPage"); + write("%%EndPage"); //This is non-standard, but used by Adobe. } /** @@ -838,7 +943,7 @@ w = w + area.getBorderLeftWidth() + area.getBorderRightWidth(); h = h + area.getBorderTopWidth() + area.getBorderBottomWidth(); - doBackground(area, rx, ry, w, h); + doBackground(area, rx, ry, w, h); if (area.getBorderTopWidth() != 0) { write("newpath"); @@ -899,9 +1004,14 @@ 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"); @@ -910,6 +1020,7 @@ write("%%BeginProlog"); write("%%EndProlog"); write("%%BeginSetup"); + writeProcs(); writeFontDict(fontInfo); /* Write proc for including EPS */ @@ -941,7 +1052,6 @@ write("%%EndResource"); write("%%EndSetup"); - write("FOPFonts begin"); } /** @@ -951,6 +1061,7 @@ public void stopRenderer(OutputStream outputStream) throws IOException { write("%%Trailer"); + write("%%Pages: "+this.pagecount); write("%%EOF"); this.out.flush(); log.debug("written out PostScript"); No revision No revision 1.1.2.1 +201 -0 xml-fop/src/org/apache/fop/render/ps/Attic/ASCII85OutputStream.java 1.1.2.1 +81 -0 xml-fop/src/org/apache/fop/render/ps/Attic/ASCIIHexOutputStream.java 1.1.2.1 +30 -0 xml-fop/src/org/apache/fop/render/ps/Attic/Finalizable.java 1.1.2.1 +39 -0 xml-fop/src/org/apache/fop/render/ps/Attic/FlateEncodeOutputStream.java
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]