]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Some improvements on the quality fallback for text (use stroking when in doubt).
authorJeremias Maerki <jeremias@apache.org>
Sat, 3 Apr 2004 13:35:09 +0000 (13:35 +0000)
committerJeremias Maerki <jeremias@apache.org>
Sat, 3 Apr 2004 13:35:09 +0000 (13:35 +0000)
PSGenerator returns the PS level to use.
Start bringing back bitmap support.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@197487 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/fop/render/ps/EPSDocumentGraphics2D.java
src/java/org/apache/fop/render/ps/PSDocumentGraphics2D.java
src/java/org/apache/fop/render/ps/PSGenerator.java
src/java/org/apache/fop/render/ps/PSGraphics2D.java
src/java/org/apache/fop/render/ps/PSImageUtils.java [new file with mode: 0644]
src/java/org/apache/fop/render/ps/PSRenderer.java
src/java/org/apache/fop/render/ps/PSTextPainter.java

index 5d46ad533303ed78deb837258d90986fe45d8a0f..340ac85dedce0782201b593d8a4510af0ef071c4 100644 (file)
@@ -20,6 +20,8 @@ package org.apache.fop.render.ps;
 
 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 @@ public class EPSDocumentGraphics2D extends AbstractPSDocumentGraphics2D {
         //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
index 93a66fe8e3d90d7ccae22779673b9e30949e8964..ce419f722b808a92d6313862cecf78f69993b3ff 100644 (file)
@@ -25,6 +25,7 @@ import java.io.IOException;
 
 //FOP
 import org.apache.fop.apps.Document;
+import org.apache.fop.apps.Version;
 import org.apache.fop.fonts.FontSetup;
 
 /**
@@ -91,7 +92,8 @@ public class PSDocumentGraphics2D extends AbstractPSDocumentGraphics2D {
         //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);
index 3f739eac957dbf7437f27a4e891b5da6278a89dd..4a64f626cda02f7cfbb02b2a11d6cbcce1c417bc 100644 (file)
@@ -68,6 +68,15 @@ public class PSGenerator {
         return this.out;
     }
 
+    /**
+     * 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.
      * 
index 97ab34417ca9025479e479ed1dcc2e373181db49..e527450d79073008486f5262775c6675517508c7 100644 (file)
@@ -38,6 +38,7 @@ import java.awt.Shape;
 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 @@ import java.io.IOException;
 //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 @@ import org.apache.fop.apps.Document;
  */
 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 class PSGraphics2D extends AbstractGraphics2D {
     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 @@ public class PSGraphics2D extends AbstractGraphics2D {
             // 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 @@ public class PSGraphics2D extends AbstractGraphics2D {
                                  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);
-
-        TempImage(int width, int height, byte[] result,
+        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[] 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 @@ public class PSGraphics2D extends AbstractGraphics2D {
             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 @@ public class PSGraphics2D extends AbstractGraphics2D {
             return this.mask;
         }
 
-        // get the image bytes, and bytes properties
-
-        // get uncompressed image bytes
         public byte[] getBitmaps() {
             return this.bitmaps;
         }
@@ -372,22 +379,8 @@ public class PSGraphics2D extends AbstractGraphics2D {
             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 class PSGraphics2D extends AbstractGraphics2D {
     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 @@ public class PSGraphics2D extends AbstractGraphics2D {
      * @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 class PSGraphics2D extends AbstractGraphics2D {
     public void draw(Shape s) {
         preparePainting();
         try {
-            // System.out.println("draw(Shape)");
             gen.saveGraphicsState();
             Shape imclip = getClip();
             writeClip(imclip);
@@ -578,9 +569,9 @@ public class PSGraphics2D extends AbstractGraphics2D {
     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 @@ public class PSGraphics2D extends AbstractGraphics2D {
                 case BasicStroke.CAP_SQUARE:
                     gen.writeln("2 setlinecap");
                     break;
+                default: log.warn("Unsupported line cap: " + ec);
                 }
 
                 int lj = bs.getLineJoin();
@@ -631,6 +623,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
                 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 class PSGraphics2D extends AbstractGraphics2D {
      */
     public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
         preparePainting();
-        System.out.println("drawRenderedImage");
+        log.warn("NYI: drawRenderedImage");
     }
 
     /**
@@ -701,7 +694,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
     public void drawRenderableImage(RenderableImage img,
                                     AffineTransform xform) {
         preparePainting();
-        System.out.println("drawRenderableImage");
+        log.warn("NYI: drawRenderableImage");
     }
 
     /**
@@ -807,7 +800,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
      */
     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 class PSGraphics2D extends AbstractGraphics2D {
     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 class PSGraphics2D extends AbstractGraphics2D {
      */
     public void fill(Shape s) {
         preparePainting();
-        // System.err.println("fill");
         try {
             gen.saveGraphicsState();
             Shape imclip = getClip();
@@ -1030,7 +1022,6 @@ public class PSGraphics2D extends AbstractGraphics2D {
      * @return the device configuration
      */
     public GraphicsConfiguration getDeviceConfiguration() {
-        // System.out.println("getDeviceConviguration");
         return GraphicsEnvironment.getLocalGraphicsEnvironment().
                 getDefaultScreenDevice().getDefaultConfiguration();
     }
@@ -1083,7 +1074,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
      * @param     c1 the XOR alternation color
      */
     public void setXORMode(Color c1) {
-        System.out.println("setXORMode");
+        log.warn("NYI: setXORMode");
     }
 
 
@@ -1108,7 +1099,7 @@ public class PSGraphics2D extends AbstractGraphics2D {
      */
     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
diff --git a/src/java/org/apache/fop/render/ps/PSImageUtils.java b/src/java/org/apache/fop/render/ps/PSImageUtils.java
new file mode 100644 (file)
index 0000000..7edc340
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * 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$ */
+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();
+    }
+
+
+}
index 614e9922aab44eec57236ab8718ccd4359059730..ef39dcc5f88a148f36fb3e53aaa79eec053e2188 100644 (file)
@@ -324,6 +324,7 @@ public class PSRenderer extends AbstractRenderer {
         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);
 
index 4112ac2951b95081b59c15c98a1f1b2210595827..2c58813cc2b6e1da05dee91ee933f1906c1070e9 100644 (file)
@@ -42,6 +42,8 @@ import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
 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 @@ import org.apache.fop.apps.Document;
  */
 public class PSTextPainter implements TextPainter {
     
+    /** the logger for this class */
+    protected Log log = LogFactory.getLog(PSTextPainter.class);
+    
     private Document document;
 
     /**
@@ -117,6 +122,13 @@ public class PSTextPainter implements TextPainter {
     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 @@ public class PSTextPainter implements TextPainter {
                     || (tpi.strikethroughStroke != null)
                     || (tpi.underlineStroke != null)
                     || (tpi.overlineStroke != null))) {
+                        log.trace("-> under/overlines etc. found");
             hasunsupported = true;
         }
 
@@ -132,6 +145,7 @@ public class PSTextPainter implements TextPainter {
         if (foreground instanceof Color) {
             Color col = (Color)foreground;
             if (col.getAlpha() != 255) {
+                log.trace("-> transparency found");
                 hasunsupported = true;
             }
         }
@@ -139,18 +153,21 @@ public class PSTextPainter implements TextPainter {
         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 @@ public class PSTextPainter implements TextPainter {
         if (writeMod != null 
             && !GVTAttributedCharacterIterator.TextAttribute.WRITING_MODE_LTR.equals(
                   writeMod)) {
+            log.trace("-> Unsupported writing modes found");
             hasunsupported = true;
         }
 
@@ -166,15 +184,20 @@ public class PSTextPainter implements TextPainter {
                 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 @@ public class PSTextPainter implements TextPainter {
 
     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);
 
@@ -410,6 +436,19 @@ public class PSTextPainter implements TextPainter {
         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;
+    }
+
     /**
      * Get the outline shape of the text characters.
      * This uses the StrokingTextPainter to get the outline