]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Improved accuracy of font size selection. The font size is not rounded down to the...
authorJeremias Maerki <jeremias@apache.org>
Wed, 31 May 2006 21:17:18 +0000 (21:17 +0000)
committerJeremias Maerki <jeremias@apache.org>
Wed, 31 May 2006 21:17:18 +0000 (21:17 +0000)
PCL Renderer:
Found a use case for that Java2D ascent value (which I call MaxAscent). It is used for painting text as bitmaps and to make sure the image the text is painted on is big enough if the font ascends beyond the em box. For non-Java2D fonts, MaxAscent is the same as ascent.
Added a check that lets text painting fall back to bitmaps if there are characters that are not in the ISO-8859-1 encoding. This also enables Symbol and ZapfDingbats fonts.
A "text-rendering" setting allows to disable PCL text painting in case the mix of PCL and bitmap text painting should result in unwelcome output. Note: the bitmap rendering is relatively slow (many small bitmaps). In the end we might end up rendering using a BitmapRenderer and only wrapping the whole thing in PCL (much like the Windows PCL drivers do). This would be faster than creating many small bitmaps.

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

src/documentation/content/xdocs/trunk/configuration.xml
src/documentation/content/xdocs/trunk/output.xml
src/java/org/apache/fop/fonts/FontMetrics.java
src/java/org/apache/fop/fonts/LazyFont.java
src/java/org/apache/fop/fonts/Typeface.java
src/java/org/apache/fop/render/java2d/FontMetricsMapper.java
src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java
src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java

index a5ad453129667f280205b355d2055db5d96bd481..07691e13a56fa304f32a891e83d359e75f258884 100644 (file)
         offered by Java.
       </p>
       <p>
-        Additionally, there's one setting that controls how borders are painted.
+        Additionally, there are certain settings that control who the renderer handles various elements.
       </p>
 <source><![CDATA[<renderer mime="application/vnd.hp-PCL">
   <rendering>quality</rendering>
+  <text-rendering>bitmap</text-rendering>
 </renderer>]]></source>
       <p>
         The default value for the "rendering" setting is "speed" which causes borders 
         value to "quality" as indicated above. This will cause the borders to be painted
         as bitmaps.
       </p>
+      <p>
+        The default value for the "text-rendering" setting is "auto" which paints the
+        base fonts using PCL fonts. Non-base fonts are painted as bitmaps through Java2D.
+        If the mix of painting methods results in unwelcome output, you can set this
+        to "bitmap" which causes all text to be rendered as bitmaps.
+      </p>
     </section>
   </section>
   </body>
index 9c701fd76da77248bcd0730fac1380e22f282ce5..6cc625eca2ff00f0df4fbb4b505866bd311d83ed 100644 (file)
@@ -369,10 +369,11 @@ out = proc.getOutputStream();]]></source>
     <section id="pcl-configuration">
       <title>Configuration</title>
       <p>
-        The PCL renderer configuration currently allows one setting:
+        The PCL renderer configuration currently allows the following settings:
       </p>
 <source><![CDATA[<renderer mime="application/vnd.hp-PCL">
   <rendering>quality</rendering>
+  <text-rendering>bitmap</text-rendering>
 </renderer>]]></source>
       <p>
         The default value for the "rendering" setting is "speed" which causes borders 
@@ -381,6 +382,12 @@ out = proc.getOutputStream();]]></source>
         value to "quality" as indicated above. This will cause the borders to be painted
         as bitmaps.
       </p>
+      <p>
+        The default value for the "text-rendering" setting is "auto" which paints the
+        base fonts using PCL fonts. Non-base fonts are painted as bitmaps through Java2D.
+        If the mix of painting methods results in unwelcome output, you can set this
+        to "bitmap" which causes all text to be rendered as bitmaps.
+      </p>
       <p>
         You can control the output resolution for the PCL using the "target resolution" 
         setting on the FOUserAgent. The actual value will be rounded up to the next
index d7ec7975a10fc50286f75bff6007ab201b48a9f7..3ca228125d22b48bfdbea4bece11a93d8039c09a 100644 (file)
@@ -40,9 +40,17 @@ public interface FontMetrics {
     FontType getFontType();
     
 
+    /**
+     * Returns the maximum ascent of the font described by this
+     * FontMetrics object. Note: This is not the same as getAscender().
+     * @param size font size
+     * @return ascent in milliponts
+     */
+    int getMaxAscent(int size);
+    
     /**
      * Returns the ascent of the font described by this
-     * FontMetrics object.
+     * FontMetrics object. It returns the nominal ascent within the em box.
      * @param size font size
      * @return ascent in milliponts
      */
index c08216ab092bfd7c879d63664d74add439c82039..19bb4ffde69358310962cc296aca23fe9a3536da 100644 (file)
@@ -176,6 +176,14 @@ public class LazyFont extends Typeface implements FontDescriptor {
         return realFont.getFontName();
     }
 
+    /**
+     * @see org.apache.fop.fonts.FontMetrics#getMaxAscent(int)
+     */
+    public int getMaxAscent(int size) {
+        load(true);
+        return realFont.getMaxAscent(size);
+    }
+
     /**
      * @see org.apache.fop.fonts.FontMetrics#getAscender(int)
      */
index f39a80d40785c6f91939e61103694ea8f483ce70..34ed962153cd1cac8bd136847638ce04e8a1f11c 100644 (file)
@@ -54,5 +54,10 @@ public abstract class Typeface implements FontMetrics {
         return false;
     }
 
+    /** @see org.apache.fop.fonts.FontMetrics#getMaxAscent(int) */
+    public int getMaxAscent(int size) {
+        return getAscender(size);
+    }
+    
 }
 
index e49ee8967faa440ef1924fb459380d936b72c28d..6890300e960dc51ff0d8814ae6e452f40527b268 100644 (file)
@@ -85,6 +85,13 @@ public class FontMetricsMapper extends Typeface implements FontMetrics {
         return FontType.OTHER;
     }
     
+    /**
+     * @see org.apache.fop.fonts.FontMetrics#getMaxAscent(int)
+     */
+    public int getMaxAscent(int size) {
+        return metric.getMaxAscent(family, style, size);
+    }
+
     /**
      * @see org.apache.fop.fonts.FontMetrics#getAscender(int)
      */
index e459781f9005d5724cf9fd3ab253d021ce0c9cec..0ddc44bbf6948122feacec611ebb9a8b42571492 100644 (file)
@@ -23,7 +23,10 @@ import java.awt.Font;
 import java.awt.Graphics2D;
 import java.awt.geom.Rectangle2D;
 import java.awt.FontMetrics;
+import java.awt.font.LineMetrics;
+import java.awt.font.TextAttribute;
 import java.awt.font.TextLayout;
+import java.util.Map;
 
 /**
  * This is a FontMetrics to be used  for AWT  rendering.
@@ -97,6 +100,9 @@ public class Java2DFontMetrics {
      */
     private FontMetrics fmt = null;
 
+    /** A LineMetrics to access high-resolution metrics information. */
+    private LineMetrics lineMetrics;
+    
     /**
      * Temp graphics object needed to get the font metrics
      */
@@ -111,6 +117,19 @@ public class Java2DFontMetrics {
         this.graphics = graphics;
     }
 
+    /**
+     * Determines the font's maximum ascent of the Font described by the current
+     * FontMetrics object
+     * @param family font family (java name) to use
+     * @param style font style (java def.) to use
+     * @param size font size
+     * @return ascent in milliponts
+     */
+    public int getMaxAscent(String family, int style, int size) {
+        setFont(family, style, size);
+        return Math.round(lineMetrics.getAscent() * FONT_FACTOR);
+    }
+    
     /**
      * Determines the font ascent of the Font described by this
      * FontMetrics object
@@ -233,6 +252,19 @@ public class Java2DFontMetrics {
         return width;
     }
 
+    private Font getBaseFont(String family, int style, float size) {
+        Map atts = new java.util.HashMap();
+        atts.put(TextAttribute.FAMILY, family);
+        if ((style & Font.BOLD) != 0) {
+            atts.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
+        }
+        if ((style & Font.ITALIC) != 0) {
+            atts.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);
+        }
+        atts.put(TextAttribute.SIZE, new Float(size)); //size in pt
+        return new Font(atts);
+    }
+    
     /**
      * Checks whether the font  for which values are
      * requested is the one used immediately before or
@@ -244,21 +276,19 @@ public class Java2DFontMetrics {
      */
     private boolean setFont(String family, int style, int size) {
         boolean changed = false;
-        //TODO this seems bad. It rounds font sizes down to the next integer value (=pt)
-        int s = (int)(size / 1000f);
-        //int s = size;
+        float s = size / 1000f;
 
         if (f1 == null) {
-            f1 = new Font(family, style, s);
+            f1 = getBaseFont(family, style, s);
             fmt = graphics.getFontMetrics(f1);
             changed = true;
         } else {
             if ((this.style != style) || !this.family.equals(family)
                     || this.size != s) {
                 if (family.equals(this.family)) {
-                    f1 = f1.deriveFont(style, (float)s);
+                    f1 = f1.deriveFont(style, s);
                 } else {
-                    f1 = new Font(family, style, s);
+                    f1 = getBaseFont(family, style, s);
                 }
                 fmt = graphics.getFontMetrics(f1);
                 changed = true;
@@ -282,7 +312,7 @@ public class Java2DFontMetrics {
             descender = (int)Math.round((rect.getY() + rect.getHeight()) * -1000);
             
             //Alternative way to get metrics but the ascender is again wrong for our purposes
-            //lineMetrics = f1.getLineMetrics("", graphics.getFontRenderContext());
+            lineMetrics = f1.getLineMetrics("", graphics.getFontRenderContext());
         }
         // save the family and style for later comparison
         this.family = family;
index 71780448c595facdd9a2736d76e1c72ebe39a3c0..2e2366daa3cab51aef079db0fa215e3e59fb442b 100644 (file)
@@ -127,6 +127,12 @@ public class PCLRenderer extends PrintRenderer {
      */
     private boolean qualityBeforeSpeed = false;
     
+    /**
+     * Controls whether all text should be painted as text. This is a fallback setting in case
+     * the mixture of native and bitmapped text does not provide the necessary quality.
+     */
+    private boolean allTextAsBitmaps = false;
+    
     /**
      * Create the PCL renderer
      */
@@ -148,6 +154,16 @@ public class PCLRenderer extends PrintRenderer {
                     "Valid values for 'rendering' are 'quality' and 'speed'. Value found: " 
                         + rendering);
         }
+        String textRendering = cfg.getChild("text-rendering").getValue(null);
+        if ("bitmap".equalsIgnoreCase(textRendering)) {
+            this.allTextAsBitmaps = true;
+        } else if ("auto".equalsIgnoreCase(textRendering)) {
+            this.allTextAsBitmaps = false;
+        } else if (textRendering != null) {
+            throw new ConfigurationException(
+                    "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: " 
+                        + textRendering);
+        }
     }
 
     /**
@@ -202,10 +218,17 @@ public class PCLRenderer extends PrintRenderer {
      * Sets the current font (NOTE: Hard-coded font mappings ATM!)
      * @param name the font name (internal F* names for now)
      * @param size the font size
+     * @param text the text to be rendered (used to determine if there are non-printable chars)
      * @return true if the font can be mapped to PCL
      * @throws IOException if an I/O problem occurs
      */
-    public boolean setFont(String name, float size) throws IOException {
+    public boolean setFont(String name, float size, String text) throws IOException {
+        byte[] encoded = text.getBytes("ISO-8859-1");
+        for (int i = 0, c = encoded.length; i < c; i++) {
+            if (encoded[i] == 0x3F && text.charAt(i) != '?') {
+                return false;
+            }
+        }
         int fontcode = 0;
         if (name.length() > 1 && name.charAt(0) == 'F') {
             try {
@@ -214,6 +237,7 @@ public class PCLRenderer extends PrintRenderer {
                 log.error(e);
             }
         }
+        //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
         String formattedSize = gen.formatDouble2(size / 1000);
         switch (fontcode) {
         case 1:     // F1 = Helvetica
@@ -288,17 +312,19 @@ public class PCLRenderer extends PrintRenderer {
             break;
         case 13:    // F13 = Symbol
 
-            gen.writeCommand("(19M");
-            gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
+            return false;
+            //gen.writeCommand("(19M");
+            //gen.writeCommand("(s1p" + formattedSize + "v0s0b16686T");
             // ECMA Latin 1 Symbol Set in Times Roman???
             // gen.writeCommand("(9U");
             // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
-            break;
+            //break;
         case 14:    // F14 = Zapf Dingbats
 
-            gen.writeCommand("(14L");
-            gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
-            break;
+            return false;
+            //gen.writeCommand("(14L");
+            //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
+            //break;
         default:
             //gen.writeCommand("(0N");
             //gen.writeCommand("(s" + formattedSize + "V");
@@ -554,7 +580,9 @@ public class PCLRenderer extends PrintRenderer {
 
         try {
             final Color col = (Color)text.getTrait(Trait.COLOR);
-            boolean pclFont = setFont(fontname, fontsize);
+            boolean pclFont = allTextAsBitmaps 
+                    ? false
+                    : setFont(fontname, fontsize, text.getText()); 
             if (pclFont) {
                 //this.currentFill = col;
                 if (col != null) {
@@ -577,11 +605,15 @@ public class PCLRenderer extends PrintRenderer {
                 
                 //for cursive fonts, so the text isn't clipped
                 int extraWidth = font.getFontSize() / 3;
+                final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
+                        font.getFontName());
+                int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
+                final int additionalBPD = maxAscent - baseline;
                 
                 Graphics2DAdapter g2a = getGraphics2DAdapter();
                 final Rectangle paintRect = new Rectangle(
-                        rx, currentBPPosition + text.getOffset(),
-                        text.getIPD() + extraWidth, text.getBPD());
+                        rx, currentBPPosition + text.getOffset() - additionalBPD,
+                        text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
                 RendererContext rc = createRendererContext(paintRect.x, paintRect.y, 
                         paintRect.width, paintRect.height, null);
                 Map atts = new java.util.HashMap();
@@ -592,10 +624,8 @@ public class PCLRenderer extends PrintRenderer {
                 Graphics2DImagePainter painter = new Graphics2DImagePainter() {
 
                     public void paint(Graphics2D g2d, Rectangle2D area) {
-                        FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
-                                font.getFontName());
                         g2d.setFont(mapper.getFont(font.getFontSize()));
-                        g2d.translate(0, baseline);
+                        g2d.translate(0, baseline + additionalBPD);
                         g2d.scale(1000, 1000);
                         g2d.setColor(col);
                         Java2DRenderer.renderText(text, g2d, font);