From e189115a925441c612694e3820bdc24bede5aa0d Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 31 May 2006 21:17:18 +0000 Subject: [PATCH] Improved accuracy of font size selection. The font size is not rounded down to the next integer point value anymore. (Java2D renderers profit from that one, too) 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 --- .../content/xdocs/trunk/configuration.xml | 9 ++- .../content/xdocs/trunk/output.xml | 9 ++- .../org/apache/fop/fonts/FontMetrics.java | 10 +++- src/java/org/apache/fop/fonts/LazyFont.java | 8 +++ src/java/org/apache/fop/fonts/Typeface.java | 5 ++ .../fop/render/java2d/FontMetricsMapper.java | 7 +++ .../fop/render/java2d/Java2DFontMetrics.java | 44 ++++++++++++--- .../apache/fop/render/pcl/PCLRenderer.java | 56 ++++++++++++++----- 8 files changed, 125 insertions(+), 23 deletions(-) diff --git a/src/documentation/content/xdocs/trunk/configuration.xml b/src/documentation/content/xdocs/trunk/configuration.xml index a5ad45312..07691e13a 100644 --- a/src/documentation/content/xdocs/trunk/configuration.xml +++ b/src/documentation/content/xdocs/trunk/configuration.xml @@ -253,10 +253,11 @@ offered by Java.

- Additionally, there's one setting that controls how borders are painted. + Additionally, there are certain settings that control who the renderer handles various elements.

quality + bitmap ]]>

The default value for the "rendering" setting is "speed" which causes borders @@ -265,6 +266,12 @@ value to "quality" as indicated above. This will cause the borders to be painted as bitmaps.

+

+ 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. +

diff --git a/src/documentation/content/xdocs/trunk/output.xml b/src/documentation/content/xdocs/trunk/output.xml index 9c701fd76..6cc625eca 100644 --- a/src/documentation/content/xdocs/trunk/output.xml +++ b/src/documentation/content/xdocs/trunk/output.xml @@ -369,10 +369,11 @@ out = proc.getOutputStream();]]>
Configuration

- The PCL renderer configuration currently allows one setting: + The PCL renderer configuration currently allows the following settings:

quality + bitmap ]]>

The default value for the "rendering" setting is "speed" which causes borders @@ -381,6 +382,12 @@ out = proc.getOutputStream();]]> value to "quality" as indicated above. This will cause the borders to be painted as bitmaps.

+

+ 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. +

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 diff --git a/src/java/org/apache/fop/fonts/FontMetrics.java b/src/java/org/apache/fop/fonts/FontMetrics.java index d7ec7975a..3ca228125 100644 --- a/src/java/org/apache/fop/fonts/FontMetrics.java +++ b/src/java/org/apache/fop/fonts/FontMetrics.java @@ -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 */ diff --git a/src/java/org/apache/fop/fonts/LazyFont.java b/src/java/org/apache/fop/fonts/LazyFont.java index c08216ab0..19bb4ffde 100644 --- a/src/java/org/apache/fop/fonts/LazyFont.java +++ b/src/java/org/apache/fop/fonts/LazyFont.java @@ -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) */ diff --git a/src/java/org/apache/fop/fonts/Typeface.java b/src/java/org/apache/fop/fonts/Typeface.java index f39a80d40..34ed96215 100644 --- a/src/java/org/apache/fop/fonts/Typeface.java +++ b/src/java/org/apache/fop/fonts/Typeface.java @@ -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); + } + } diff --git a/src/java/org/apache/fop/render/java2d/FontMetricsMapper.java b/src/java/org/apache/fop/render/java2d/FontMetricsMapper.java index e49ee8967..6890300e9 100644 --- a/src/java/org/apache/fop/render/java2d/FontMetricsMapper.java +++ b/src/java/org/apache/fop/render/java2d/FontMetricsMapper.java @@ -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) */ diff --git a/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java b/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java index e459781f9..0ddc44bbf 100644 --- a/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java +++ b/src/java/org/apache/fop/render/java2d/Java2DFontMetrics.java @@ -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; diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java b/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java index 71780448c..2e2366daa 100644 --- a/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java +++ b/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java @@ -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); -- 2.39.5