jeremias 2004/04/03 05:35:09 Modified: src/java/org/apache/fop/render/ps PSGraphics2D.java PSGenerator.java PSRenderer.java PSDocumentGraphics2D.java EPSDocumentGraphics2D.java PSTextPainter.java Added: src/java/org/apache/fop/render/ps PSImageUtils.java Log: Some improvements on the quality fallback for text (use stroking when in doubt).
PSGenerator returns the PS level to use. Start bringing back bitmap support. Revision Changes Path 1.8 +57 -66 xml-fop/src/java/org/apache/fop/render/ps/PSGraphics2D.java Index: PSGraphics2D.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/PSGraphics2D.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- PSGraphics2D.java 27 Feb 2004 17:53:11 -0000 1.7 +++ PSGraphics2D.java 3 Apr 2004 13:35:09 -0000 1.8 @@ -38,6 +38,7 @@ import java.awt.Stroke; import java.awt.TexturePaint; import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; @@ -54,9 +55,12 @@ //Batik import org.apache.batik.ext.awt.g2d.AbstractGraphics2D; import org.apache.batik.ext.awt.g2d.GraphicContext; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; //FOP import org.apache.fop.fonts.Font; +import org.apache.fop.image.FopImage; import org.apache.fop.apps.Document; /** @@ -73,6 +77,9 @@ */ public class PSGraphics2D extends AbstractGraphics2D { + /** the logger for this class */ + protected Log log = LogFactory.getLog(PSTextPainter.class); + /** the PostScript generator being created */ protected PSGenerator gen; @@ -196,7 +203,7 @@ public boolean drawImage(Image img, int x, int y, ImageObserver observer) { preparePainting(); - System.out.println("drawImage: x, y " + img.getClass().getName()); + log.debug("drawImage: " + x + ", " + y + " " + img.getClass().getName()); final int width = img.getWidth(observer); final int height = img.getHeight(observer); @@ -249,24 +256,21 @@ // error break; } -/* + try { - FopImage fopimg = new TempImage(width, height, result, mask); + FopImage fopimg = new TempImage(width, height, result, null); AffineTransform at = getTransform(); - double[] matrix = new double[6]; - at.getMatrix(matrix); gen.saveGraphicsState(); Shape imclip = getClip(); writeClip(imclip); - // psRenderer.write("" + matrix[0] + " " + matrix[1] + - // " " + matrix[2] + " " + matrix[3] + " " + - // matrix[4] + " " + matrix[5] + " cm\n"); - //psRenderer.renderBitmap(fopimg, x, y, width, height); + gen.concatMatrix(at); + PSImageUtils.renderFopImage(fopimg, + 1000 * x, 1000 * y, 1000 * width, 1000 * height, gen); gen.restoreGraphicsState(); } catch (IOException ioe) { handleIOException(ioe); } -*/ + return true; } @@ -280,40 +284,44 @@ BufferedImage.TYPE_INT_ARGB); } -/* + class TempImage implements FopImage { - int height; - int width; - int bitsPerPixel; - ColorSpace colorSpace; - int bitmapSiye; - byte[] bitmaps; - byte[] mask; - PDFColor transparent = new PDFColor(255, 255, 255); + private int height; + private int width; + private int bitsPerPixel; + private ColorSpace colorSpace; + private int bitmapSiye; + private byte[] bitmaps; + private byte[] mask; + private Color transparentColor; - TempImage(int width, int height, byte[] result, + TempImage(int width, int height, byte[] bitmaps, byte[] mask) { this.height = height; this.width = width; this.bitsPerPixel = 8; - this.colorSpace = ColorSpace.new PDFColorSpace(PDFColorSpace.DEVICE_RGB); - this.bitmaps = result; + this.colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB); + this.bitmaps = bitmaps; this.mask = mask; } - public boolean load(int type, FOUserAgent ua) { - return true; - } - public String getMimeType() { - return ""; + return "application/octet-stream"; } - public String getURL() { - return "" + this.bitmaps; + /** + * @see org.apache.fop.image.FopImage#load(int, org.apache.commons.logging.Log) + */ + public boolean load(int type, Log logger) { + switch (type) { + case FopImage.DIMENSIONS: break; + case FopImage.BITMAP: break; + case FopImage.ORIGINAL_DATA: break; + default: throw new RuntimeException("Unknown load type: " + type); + } + return true; } - // image size public int getWidth() { return this.width; } @@ -322,23 +330,25 @@ return this.height; } - // DeviceGray, DeviceRGB, or DeviceCMYK public ColorSpace getColorSpace() { return this.colorSpace; } - // bits per pixel + public ICC_Profile getICCProfile() { + return null; + } + public int getBitsPerPixel() { return this.bitsPerPixel; } // For transparent images public boolean isTransparent() { - return this.transparent != null; + return getTransparentColor() != null; } - public PDFColor getTransparentColor() { - return this.transparent; + public Color getTransparentColor() { + return this.transparentColor; } public boolean hasSoftMask() { @@ -349,9 +359,6 @@ return this.mask; } - // get the image bytes, and bytes properties - - // get uncompressed image bytes public byte[] getBitmaps() { return this.bitmaps; } @@ -372,22 +379,8 @@ return 0; } - // return null if no corresponding PDFFilter - public PDFFilter getPDFFilter() { - return null; - } - - // release memory - public void close() { - //nop - } - - public ICC_Profile getICCProfile() { - return null; - } - } -*/ + /** * Draws as much of the specified image as has already been scaled @@ -426,7 +419,7 @@ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { preparePainting(); - System.out.println("drawImage"); + log.warn("NYI: drawImage"); return true; } @@ -458,7 +451,6 @@ * @see java.awt.Graphics#create */ public void dispose() { - // System.out.println("dispose"); this.gen = null; this.font = null; this.currentColour = null; @@ -529,7 +521,6 @@ public void draw(Shape s) { preparePainting(); try { - // System.out.println("draw(Shape)"); gen.saveGraphicsState(); Shape imclip = getClip(); writeClip(imclip); @@ -578,9 +569,9 @@ protected void applyPaint(Paint paint, boolean fill) { preparePainting(); if (paint instanceof GradientPaint) { - //NYI + log.warn("NYI: Gradient paint"); } else if (paint instanceof TexturePaint) { - //NYI + log.warn("NYI: texture paint"); } } @@ -618,6 +609,7 @@ case BasicStroke.CAP_SQUARE: gen.writeln("2 setlinecap"); break; + default: log.warn("Unsupported line cap: " + ec); } int lj = bs.getLineJoin(); @@ -631,6 +623,7 @@ case BasicStroke.JOIN_BEVEL: gen.writeln("2 setlinejoin"); break; + default: log.warn("Unsupported line join: " + lj); } float lw = bs.getLineWidth(); gen.writeln(gen.formatDouble(1000 * lw) + " setlinewidth"); @@ -665,7 +658,7 @@ */ public void drawRenderedImage(RenderedImage img, AffineTransform xform) { preparePainting(); - System.out.println("drawRenderedImage"); + log.warn("NYI: drawRenderedImage"); } /** @@ -701,7 +694,7 @@ public void drawRenderableImage(RenderableImage img, AffineTransform xform) { preparePainting(); - System.out.println("drawRenderableImage"); + log.warn("NYI: drawRenderableImage"); } /** @@ -807,7 +800,7 @@ */ public void drawStringAsText(String s, float x, float y) { preparePainting(); - //System.out.println("drawString('" + s + "', " + x + ", " + y + ")"); + log.trace("drawString('" + s + "', " + x + ", " + y + ")"); try { if (this.overrideFont == null) { java.awt.Font awtFont = getFont(); @@ -926,7 +919,7 @@ public void drawString(AttributedCharacterIterator iterator, float x, float y) { preparePainting(); - System.err.println("drawString(AttributedCharacterIterator) NYI"); + log.warn("NYI: drawString(AttributedCharacterIterator)"); /* try { gen.writeln("BT"); @@ -974,7 +967,6 @@ */ public void fill(Shape s) { preparePainting(); - // System.err.println("fill"); try { gen.saveGraphicsState(); Shape imclip = getClip(); @@ -1030,7 +1022,6 @@ * @return the device configuration */ public GraphicsConfiguration getDeviceConfiguration() { - // System.out.println("getDeviceConviguration"); return GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice().getDefaultConfiguration(); } @@ -1083,7 +1074,7 @@ * @param c1 the XOR alternation color */ public void setXORMode(Color c1) { - System.out.println("setXORMode"); + log.warn("NYI: setXORMode"); } @@ -1108,7 +1099,7 @@ */ public void copyArea(int x, int y, int width, int height, int dx, int dy) { - System.out.println("copyArea"); + log.warn("NYI: copyArea"); } /* --- for debugging 1.5 +9 -0 xml-fop/src/java/org/apache/fop/render/ps/PSGenerator.java Index: PSGenerator.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/PSGenerator.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- PSGenerator.java 27 Feb 2004 17:53:11 -0000 1.4 +++ PSGenerator.java 3 Apr 2004 13:35:09 -0000 1.5 @@ -69,6 +69,15 @@ } /** + * Returns the selected PostScript level. + * (Hardcoded to level 3 for the moment.) + * @return the PostScript level + */ + public int getPSLevel() { + return 3; + } + + /** * Writes a newline character to the OutputStream. * * @throws IOException In case of an I/O problem 1.25 +1 -0 xml-fop/src/java/org/apache/fop/render/ps/PSRenderer.java Index: PSRenderer.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/PSRenderer.java,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- PSRenderer.java 27 Feb 2004 17:53:11 -0000 1.24 +++ PSRenderer.java 3 Apr 2004 13:35:09 -0000 1.25 @@ -324,6 +324,7 @@ writeln(DSCConstants.PS_ADOBE_30); gen.writeDSCComment(DSCConstants.CREATOR, new String[] {"FOP " + this.producer}); gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); + gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(gen.getPSLevel())); gen.writeDSCComment(DSCConstants.PAGES, new Object[] {PSGenerator.ATEND}); gen.writeDSCComment(DSCConstants.END_COMMENTS); 1.11 +3 -1 xml-fop/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java Index: PSDocumentGraphics2D.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- PSDocumentGraphics2D.java 27 Feb 2004 17:53:11 -0000 1.10 +++ PSDocumentGraphics2D.java 3 Apr 2004 13:35:09 -0000 1.11 @@ -25,6 +25,7 @@ //FOP import org.apache.fop.apps.Document; +import org.apache.fop.apps.Version; import org.apache.fop.fonts.FontSetup; /** @@ -91,7 +92,8 @@ //PostScript Header gen.writeln(DSCConstants.PS_ADOBE_30); gen.writeDSCComment(DSCConstants.CREATOR, - new String[] {"FOP PostScript Transcoder for SVG"}); + new String[] {"Apache FOP " + Version.getVersion() + + ": PostScript Transcoder for SVG"}); gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); gen.writeDSCComment(DSCConstants.PAGES, PSGenerator.ATEND); 1.3 +7 -4 xml-fop/src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java Index: EPSDocumentGraphics2D.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- EPSDocumentGraphics2D.java 27 Feb 2004 17:53:11 -0000 1.2 +++ EPSDocumentGraphics2D.java 3 Apr 2004 13:35:09 -0000 1.3 @@ -20,6 +20,8 @@ import java.io.IOException; +import org.apache.fop.apps.Version; + /** * This class is a wrapper for the <tt>AbstractPSDocumentGraphics2D</tt> that * is used to create EPS (Encapsulated PostScript) files instead of PS file. @@ -53,13 +55,14 @@ //PostScript Header gen.writeln(DSCConstants.PS_ADOBE_30 + " " + DSCConstants.EPSF_30); gen.writeDSCComment(DSCConstants.CREATOR, - new String[] {"FOP EPS Transcoder for SVG"}); + new String[] {"Apache FOP " + Version.getVersion() + + ": EPS Transcoder for SVG"}); gen.writeDSCComment(DSCConstants.CREATION_DATE, new Object[] {new java.util.Date()}); gen.writeDSCComment(DSCConstants.PAGES, new Integer(0)); gen.writeDSCComment(DSCConstants.BBOX, new Object[] {ZERO, ZERO, pagewidth, pageheight}); - gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(2)); + gen.writeDSCComment(DSCConstants.LANGUAGE_LEVEL, new Integer(gen.getPSLevel())); gen.writeDSCComment(DSCConstants.END_COMMENTS); //Prolog 1.12 +39 -0 xml-fop/src/java/org/apache/fop/render/ps/PSTextPainter.java Index: PSTextPainter.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/ps/PSTextPainter.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- PSTextPainter.java 27 Feb 2004 17:53:11 -0000 1.11 +++ PSTextPainter.java 3 Apr 2004 13:35:09 -0000 1.12 @@ -42,6 +42,8 @@ import org.apache.batik.gvt.text.TextPaintInfo; import org.apache.batik.gvt.font.GVTFontFamily; import org.apache.batik.gvt.renderer.StrokingTextPainter; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.fop.fonts.FontMetrics; import org.apache.fop.fonts.Font; @@ -64,6 +66,9 @@ */ public class PSTextPainter implements TextPainter { + /** the logger for this class */ + protected Log log = LogFactory.getLog(PSTextPainter.class); + private Document document; /** @@ -117,6 +122,13 @@ private boolean hasUnsupportedAttributes(AttributedCharacterIterator aci) { boolean hasunsupported = false; + String text = getText(aci); + Font font = makeFont(aci); + if (hasUnsupportedGlyphs(text, font)) { + log.trace("-> Unsupported glyphs found"); + hasunsupported = true; + } + TextPaintInfo tpi = (TextPaintInfo) aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.PAINT_INFO); if ((tpi != null) @@ -124,6 +136,7 @@ || (tpi.strikethroughStroke != null) || (tpi.underlineStroke != null) || (tpi.overlineStroke != null))) { + log.trace("-> under/overlines etc. found"); hasunsupported = true; } @@ -132,6 +145,7 @@ if (foreground instanceof Color) { Color col = (Color)foreground; if (col.getAlpha() != 255) { + log.trace("-> transparency found"); hasunsupported = true; } } @@ -139,18 +153,21 @@ Object letSpace = aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.LETTER_SPACING); if (letSpace != null) { + log.trace("-> letter spacing found"); hasunsupported = true; } Object wordSpace = aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.WORD_SPACING); if (wordSpace != null) { + log.trace("-> word spacing found"); hasunsupported = true; } Object lengthAdjust = aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.LENGTH_ADJUST); if (lengthAdjust != null) { + log.trace("-> length adjustments found"); hasunsupported = true; } @@ -159,6 +176,7 @@ if (writeMod != null && !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals( writeMod)) { + log.trace("-> Unsupported writing modes found"); hasunsupported = true; } @@ -166,15 +184,20 @@ GVTAttributedCharacterIterator.TextAttribute.VERTICAL_ORIENTATION); if (GVTAttributedCharacterIterator.TextAttribute.ORIENTATION_ANGLE.equals( vertOr)) { + log.trace("-> vertical orientation found"); hasunsupported = true; } Object rcDel = aci.getAttribute( GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER); if (!(rcDel instanceof SVGOMTextElement)) { + log.trace("-> spans found"); hasunsupported = true; //Filter spans } + if (hasunsupported) { + log.trace("Unsupported attributes found in ACI, using StrokingTextPainter"); + } return hasunsupported; } @@ -343,6 +366,9 @@ private Font makeFont(AttributedCharacterIterator aci) { Float fontSize = (Float)aci.getAttribute(TextAttribute.SIZE); + if (fontSize == null) { + fontSize = new Float(10.0f); + } String style = getStyle(aci); int weight = getWeight(aci); @@ -408,6 +434,19 @@ wordWidth += charWidth; } return wordWidth / 1000f; + } + + private boolean hasUnsupportedGlyphs(String str, Font font) { + for (int i = 0; i < str.length(); i++) { + float charWidth; + char c = str.charAt(i); + if (!((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))) { + if (!font.hasChar(c)) { + return true; + } + } + } + return false; } /** 1.1 xml-fop/src/java/org/apache/fop/render/ps/PSImageUtils.java Index: PSImageUtils.java =================================================================== /* * Copyright 2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: PSImageUtils.java,v 1.1 2004/04/03 13:35:09 jeremias Exp $ */ package org.apache.fop.render.ps; import java.awt.color.ColorSpace; import java.io.IOException; import java.io.OutputStream; import org.apache.fop.image.FopImage; import org.apache.fop.image.JpegImage; import org.apache.fop.util.ASCII85OutputStream; import org.apache.fop.util.Finalizable; import org.apache.fop.util.FlateEncodeOutputStream; import org.apache.fop.util.RunLengthEncodeOutputStream; /** * Utility code for rendering images in PostScript. */ public class PSImageUtils { /** * Renders an image to PostScript. * @param img image to render * @param x x position * @param y y position * @param w width * @param h height * @param gen PS generator * @throws IOException In case of an I/O problem while rendering the image */ public static void renderFopImage(FopImage img, int x, int y, int w, int h, PSGenerator gen) throws IOException { boolean iscolor = img.getColorSpace().getType() != ColorSpace.CS_GRAY; byte[] imgmap = img.getBitmaps(); gen.saveGraphicsState(); if (img.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { gen.writeln("/DeviceCMYK setcolorspace"); } else if (img.getColorSpace().getType() == ColorSpace.CS_GRAY) { gen.writeln("/DeviceGray setcolorspace"); } else { gen.writeln("/DeviceRGB setcolorspace"); } gen.writeln(x + " " + y + " translate"); gen.writeln(w + " " + h + " scale"); gen.writeln("{{"); // Template: (RawData is used for the EOF signal only) // gen.write("/RawData currentfile <first filter> filter def"); // gen.write("/Data RawData <second filter> <third filter> [...] def"); if (img instanceof JpegImage) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData << >> /DCTDecode filter def"); } else { if (gen.getPSLevel() >= 3) { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /FlateDecode filter def"); } else { gen.writeln("/RawData currentfile /ASCII85Decode filter def"); gen.writeln("/Data RawData /RunLengthDecode filter def"); } } gen.writeln("<<"); gen.writeln(" /ImageType 1"); gen.writeln(" /Width " + img.getWidth()); gen.writeln(" /Height " + img.getHeight()); gen.writeln(" /BitsPerComponent 8"); if (img.getColorSpace().getType() == ColorSpace.TYPE_CMYK) { if (false /*TODO img.invertImage()*/) { gen.writeln(" /Decode [1 0 1 0 1 0 1 0]"); } else { gen.writeln(" /Decode [0 1 0 1 0 1 0 1]"); } } else if (iscolor) { gen.writeln(" /Decode [0 1 0 1 0 1]"); } else { gen.writeln(" /Decode [0 1]"); } // Setup scanning for left-to-right and top-to-bottom gen.writeln(" /ImageMatrix [" + img.getWidth() + " 0 0 " + img.getHeight() + " 0 0]"); gen.writeln(" /DataSource Data"); gen.writeln(">>"); gen.writeln("image"); /* the following two lines could be enabled if something still goes wrong * gen.write("Data closefile"); * gen.write("RawData flushfile"); */ gen.writeln("} stopped {handleerror} if"); gen.writeln(" RawData flushfile"); gen.writeln("} 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); * } * } * } */ OutputStream out = gen.getOutputStream(); out = new ASCII85OutputStream(out); if (img instanceof JpegImage) { //nop } else { if (gen.getPSLevel() >= 3) { out = new FlateEncodeOutputStream(out); } else { out = new RunLengthEncodeOutputStream(out); } } out.write(imgmap); if (out instanceof Finalizable) { ((Finalizable)out).finalizeStream(); } else { out.flush(); } gen.writeln(""); gen.restoreGraphicsState(); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]