From: Jeremias Maerki Date: Wed, 17 May 2006 15:06:42 +0000 (+0000) Subject: Several bug fixes in PCLRenderer (border painting mostly). X-Git-Tag: fop-0_93~230 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=436c9f26ea62ed151f38a5eaf4e5e69fa67afda1;p=xmlgraphics-fop.git Several bug fixes in PCLRenderer (border painting mostly). Option in AbstractGraphics2DAdapter to work with or without alpha. Text Setup changed to the Java2D model. Custom font painting is now done through Java2D as bitmaps for all fonts which are not supported by the pre-defined set. This was done as a shortcut for full-fledged TrueType support which seems to be a little complicated in PCL. BTW, Microsoft PCL printer drivers do the same, i.e. paint text as bitmaps. Image printing refined, but my attempt at handling bitmasked images (transparency) didn't work out. While the previewers did the expected thing, the printer hardware flat-out ignored it, so it's disabled now. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@407277 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java index af5343f33..e7b126121 100644 --- a/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java +++ b/src/java/org/apache/fop/render/AbstractGraphics2DAdapter.java @@ -20,12 +20,18 @@ package org.apache.fop.render; import java.awt.Color; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.color.ColorSpace; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.apache.fop.render.Graphics2DAdapter; import org.apache.fop.render.Graphics2DImagePainter; import org.apache.fop.render.RendererContext.RendererContextWrapper; @@ -45,14 +51,22 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { * @return the generated BufferedImage */ protected BufferedImage paintToBufferedImage(Graphics2DImagePainter painter, - RendererContextWrapper context, int resolution, boolean gray) { + RendererContextWrapper context, int resolution, boolean gray, boolean withAlpha) { int bmw = UnitConv.mpt2px(context.getWidth(), resolution); int bmh = UnitConv.mpt2px(context.getHeight(), resolution); BufferedImage bi; if (gray) { - bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_BYTE_GRAY); + if (withAlpha) { + bi = createGrayBufferedImageWithAlpha(bmw, bmh); + } else { + bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_BYTE_GRAY); + } } else { - bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_ARGB); + if (withAlpha) { + bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_ARGB); + } else { + bi = new BufferedImage(bmw, bmh, BufferedImage.TYPE_INT_RGB); + } } Graphics2D g2d = bi.createGraphics(); try { @@ -62,7 +76,9 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { g2d.setBackground(Color.white); g2d.setColor(Color.black); - g2d.clearRect(0, 0, bmw, bmh); + if (!withAlpha) { + g2d.clearRect(0, 0, bmw, bmh); + } double sx = (double)bmw / context.getWidth(); double sy = (double)bmh / context.getHeight(); g2d.scale(sx, sy); @@ -77,6 +93,28 @@ public abstract class AbstractGraphics2DAdapter implements Graphics2DAdapter { return bi; } + private static BufferedImage createGrayBufferedImageWithAlpha(int width, int height) { + BufferedImage bi; + boolean alphaPremultiplied = true; + int bands = 2; + int[] bits = new int[bands]; + for (int i = 0; i < bands; i++) { + bits[i] = 8; + } + ColorModel cm = new ComponentColorModel( + ColorSpace.getInstance(ColorSpace.CS_GRAY), + bits, + true, alphaPremultiplied, + Transparency.TRANSLUCENT, + DataBuffer.TYPE_BYTE); + WritableRaster wr = Raster.createInterleavedRaster( + DataBuffer.TYPE_BYTE, + width, height, bands, + new Point(0, 0)); + bi = new BufferedImage(cm, wr, alphaPremultiplied, null); + return bi; + } + /** * Sets rendering hints on the Graphics2D created for painting to a BufferedImage. Subclasses * can modify the settings to customize the behaviour. diff --git a/src/sandbox/org/apache/fop/render/afp/AFPGraphics2DAdapter.java b/src/sandbox/org/apache/fop/render/afp/AFPGraphics2DAdapter.java index 7aa68fe33..3fc558d76 100644 --- a/src/sandbox/org/apache/fop/render/afp/AFPGraphics2DAdapter.java +++ b/src/sandbox/org/apache/fop/render/afp/AFPGraphics2DAdapter.java @@ -46,7 +46,7 @@ public class AFPGraphics2DAdapter extends AbstractGraphics2DAdapter { //Paint to a BufferedImage int resolution = (int)Math.round(context.getUserAgent().getTargetResolution()); - BufferedImage bi = paintToBufferedImage(painter, wrappedContext, resolution, false); + BufferedImage bi = paintToBufferedImage(painter, wrappedContext, resolution, false, false); afp.drawBufferedImage(bi, resolution, x, y, width, height); } diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java b/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java index 58447f787..f8e1b09c4 100644 --- a/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java +++ b/src/sandbox/org/apache/fop/render/pcl/PCLGenerator.java @@ -24,17 +24,24 @@ import java.awt.Graphics2D; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ByteLookupTable; import java.awt.image.ColorConvertOp; import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; import java.awt.image.IndexColorModel; +import java.awt.image.LookupOp; import java.awt.image.Raster; import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; import java.io.IOException; import java.io.OutputStream; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; +import org.apache.xmlgraphics.image.GraphicsUtil; + /** * This class provides methods for generating PCL print files. */ @@ -52,6 +59,11 @@ public class PCLGenerator { private OutputStream out; + private boolean currentSourceTransparency = true; + private boolean currentPatternTransparency = true; + + private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1]; + /** * Main constructor. * @param out the OutputStream to write the PCL stream to @@ -60,11 +72,36 @@ public class PCLGenerator { this.out = out; } + /** + * Main constructor. + * @param out the OutputStream to write the PCL stream to + * @param maxResolution the maximum resolution to encode bitmap images at + */ + public PCLGenerator(OutputStream out, int maxResolution) { + this(out); + boolean found = false; + for (int i = 0; i < PCL_RESOLUTIONS.length; i++) { + if (PCL_RESOLUTIONS[i] == maxResolution) { + found = true; + break; + } + } + if (!found) { + throw new IllegalArgumentException("Illegal value for maximum resolution!"); + } + this.maxBitmapResolution = maxResolution; + } + /** @return the OutputStream that this generator writes to */ public OutputStream getOutputStream() { return this.out; } + /** @return the maximum resolution to encode bitmap images at */ + public int getMaximumBitmapResolution() { + return this.maxBitmapResolution; + } + /** * Writes a PCL escape command to the output stream. * @param cmd the command (without the ESCAPE character) @@ -217,6 +254,22 @@ public class PCLGenerator { } } + /** + * Pushes the current cursor position on a stack (stack size: max 20 entries) + * @throws IOException In case of an I/O error + */ + public void pushCursorPos() throws IOException { + writeCommand("&f0S"); + } + + /** + * Pops the current cursor position from the stack. + * @throws IOException In case of an I/O error + */ + public void popCursorPos() throws IOException { + writeCommand("&f1S"); + } + /** * Changes the current print direction while maintaining the current cursor position. * @param rotate the rotation angle (counterclockwise), one of 0, 90, 180 and 270. @@ -282,17 +335,40 @@ public class PCLGenerator { setPatternTransparencyMode(true); } + /** + * Sets the source transparency mode. + * @param transparent true if transparent, false for opaque + * @throws IOException In case of an I/O error + */ + public void setSourceTransparencyMode(boolean transparent) throws IOException { + setTransparencyMode(transparent, currentPatternTransparency); + } + /** * Sets the pattern transparency mode. * @param transparent true if transparent, false for opaque * @throws IOException In case of an I/O error */ public void setPatternTransparencyMode(boolean transparent) throws IOException { - if (transparent) { - writeCommand("*v0O"); - } else { - writeCommand("*v1O"); + setTransparencyMode(currentSourceTransparency, transparent); + } + + /** + * Sets the transparency modes. + * @param source source transparency: true if transparent, false for opaque + * @param pattern pattern transparency: true if transparent, false for opaque + * @throws IOException In case of an I/O error + */ + public void setTransparencyMode(boolean source, boolean pattern) throws IOException { + if (source != currentSourceTransparency && pattern != currentPatternTransparency) { + writeCommand("*v" + (source ? '0' : '1') + "n" + (pattern ? '0' : '1') + "O"); + } else if (source != currentSourceTransparency) { + writeCommand("*v" + (source ? '0' : '1') + "N"); + } else if (pattern != currentPatternTransparency) { + writeCommand("*v" + (pattern ? '0' : '1') + "O"); } + this.currentSourceTransparency = source; + this.currentPatternTransparency = pattern; } /** @@ -323,7 +399,9 @@ public class PCLGenerator { * @throws IOException In case of an I/O error */ public void selectCurrentPattern(int patternID, int pattern) throws IOException { - writeCommand("*c" + patternID + "G"); + if (pattern > 1) { + writeCommand("*c" + patternID + "G"); + } writeCommand("*v" + pattern + "T"); } @@ -389,6 +467,7 @@ public class PCLGenerator { * @return the resulting PCL resolution (one of 75, 100, 150, 200, 300, 600) */ private int calculatePCLResolution(int resolution, boolean increased) { + int choice = -1; for (int i = PCL_RESOLUTIONS.length - 2; i >= 0; i--) { if (resolution > PCL_RESOLUTIONS[i]) { int idx = i + 1; @@ -397,10 +476,18 @@ public class PCLGenerator { } else if (idx < PCL_RESOLUTIONS.length - 1) { idx += increased ? 1 : 0; } - return PCL_RESOLUTIONS[idx]; + choice = idx; + break; + //return PCL_RESOLUTIONS[idx]; } } - return PCL_RESOLUTIONS[increased ? 2 : 0]; + if (choice < 0) { + choice = (increased ? 2 : 0); + } + while (choice > 0 && PCL_RESOLUTIONS[choice] > getMaximumBitmapResolution()) { + choice--; + } + return PCL_RESOLUTIONS[choice]; } private boolean isValidPCLResolution(int resolution) { @@ -419,6 +506,60 @@ public class PCLGenerator { } } + //Threshold table to convert an alpha channel (8-bit) into a clip mask (1-bit) + private static final byte[] THRESHOLD_TABLE = new byte[256]; + static { // Initialize the arrays + for (int i = 0; i < 256; i++) { + THRESHOLD_TABLE[i] = (byte) ((i < 240) ? 255 : 0); + } + } + + private RenderedImage getMask(RenderedImage img, Dimension targetDim) { + ColorModel cm = img.getColorModel(); + if (cm.hasAlpha()) { + BufferedImage alpha = new BufferedImage(img.getWidth(), img.getHeight(), + BufferedImage.TYPE_BYTE_GRAY); + Raster raster = img.getData(); + GraphicsUtil.copyBand(raster, cm.getNumColorComponents(), alpha.getRaster(), 0); + + BufferedImageOp op1 = new LookupOp(new ByteLookupTable(0, THRESHOLD_TABLE), null); + BufferedImage alphat = op1.filter(alpha, null); + + BufferedImage mask; + if (true) { + mask = new BufferedImage(targetDim.width, targetDim.height, + BufferedImage.TYPE_BYTE_BINARY); + } else { + byte[] arr = {(byte)0, (byte)0xff}; + ColorModel colorModel = new IndexColorModel(1, 2, arr, arr, arr); + WritableRaster wraster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, + targetDim.width, targetDim.height, 1, 1, null); + mask = new BufferedImage(colorModel, wraster, false, null); + } + + Graphics2D g2d = mask.createGraphics(); + try { + AffineTransform at = new AffineTransform(); + double sx = targetDim.getWidth() / img.getWidth(); + double sy = targetDim.getHeight() / img.getHeight(); + at.scale(sx, sy); + g2d.drawRenderedImage(alphat, at); + } finally { + g2d.dispose(); + } + /* + try { + BatchDiffer.saveAsPNG(alpha, new java.io.File("D:/out-alpha.png")); + BatchDiffer.saveAsPNG(mask, new java.io.File("D:/out-mask.png")); + } catch (IOException e) { + e.printStackTrace(); + }*/ + return mask; + } else { + return null; + } + } + /** * Paint a bitmap at the current cursor position. The bitmap is converted to a monochrome * (1-bit) bitmap image. @@ -433,9 +574,21 @@ public class PCLGenerator { Dimension orgDim = new Dimension(img.getWidth(), img.getHeight()); Dimension effDim = getAdjustedDimension(orgDim, resolution, effResolution); boolean scaled = !orgDim.equals(effDim); + + //Transparency mask disabled. Doesn't work reliably + final boolean transparencyDisabled = true; + RenderedImage mask = (transparencyDisabled ? null : getMask(img, effDim)); + if (mask != null) { + pushCursorPos(); + selectCurrentPattern(0, 1); //Solid white + setTransparencyMode(true, true); + paintMonochromeBitmap(mask, effResolution); + popCursorPos(); + } + BufferedImage src = null; if (img instanceof BufferedImage && !scaled) { - if (!isGrayscaleImage(img)) { + if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) { src = new BufferedImage(effDim.width, effDim.height, BufferedImage.TYPE_BYTE_GRAY); ColorConvertOp op = new ColorConvertOp( @@ -462,15 +615,16 @@ public class PCLGenerator { MonochromeBitmapConverter converter = createMonochromeBitmapConverter(); converter.setHint("quality", "false"); - long start = System.currentTimeMillis(); BufferedImage buf = (BufferedImage)converter.convertToMonochrome(src); - long duration = System.currentTimeMillis() - start; - System.out.println(duration + " ms"); RenderedImage red = buf; + selectCurrentPattern(0, 0); //Solid black + setTransparencyMode(mask != null, true); paintMonochromeBitmap(red, effResolution); } else { int effResolution = calculatePCLResolution(resolution); + setSourceTransparencyMode(false); + selectCurrentPattern(0, 0); //Solid black paintMonochromeBitmap(img, effResolution); } } diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java index 674b63941..0e27a8d29 100644 --- a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java +++ b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2D.java @@ -47,6 +47,7 @@ import org.apache.xmlgraphics.java2d.GraphicContext; /** * Graphics2D implementation implementing PCL and HP GL/2. + * Note: This class cannot be used stand-alone to create full PCL documents. */ public class PCLGraphics2D extends AbstractGraphics2D { diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java index df9fb8589..bded84098 100644 --- a/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java +++ b/src/sandbox/org/apache/fop/render/pcl/PCLGraphics2DAdapter.java @@ -64,7 +64,7 @@ public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter { boolean paintAsBitmap = pclContext.paintAsBitmap(); if (!paintAsBitmap) { ByteArrayOutputStream baout = new ByteArrayOutputStream(); - PCLGenerator tempGen = new PCLGenerator(baout); + PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution()); try { GraphicContext ctx = (GraphicContext)pcl.getGraphicContext().clone(); @@ -109,7 +109,7 @@ public class PCLGraphics2DAdapter extends AbstractGraphics2DAdapter { if (!painted) { //Fallback solution: Paint to a BufferedImage int resolution = (int)Math.round(context.getUserAgent().getTargetResolution()); - BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true); + BufferedImage bi = paintToBufferedImage(painter, pclContext, resolution, true, false); pcl.setCursorPos(x, y); gen.paintBitmap(bi, resolution); diff --git a/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java b/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java index 057f9e140..5bd30e2f8 100644 --- a/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java +++ b/src/sandbox/org/apache/fop/render/pcl/PCLRenderer.java @@ -23,6 +23,7 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Rectangle; +import java.awt.RenderingHints; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; @@ -70,6 +71,7 @@ import org.apache.fop.area.inline.TextArea; import org.apache.fop.area.inline.WordArea; import org.apache.fop.fo.extensions.ExtensionElementMapping; import org.apache.fop.fonts.Font; +import org.apache.fop.fonts.FontInfo; import org.apache.fop.image.EPSImage; import org.apache.fop.image.FopImage; import org.apache.fop.image.ImageFactory; @@ -79,6 +81,8 @@ import org.apache.fop.render.Graphics2DImagePainter; import org.apache.fop.render.PrintRenderer; import org.apache.fop.render.RendererContext; import org.apache.fop.render.RendererContextConstants; +import org.apache.fop.render.java2d.FontMetricsMapper; +import org.apache.fop.render.java2d.FontSetup; import org.apache.fop.render.java2d.Java2DRenderer; import org.apache.fop.traits.BorderProps; import org.apache.fop.util.QName; @@ -139,6 +143,23 @@ public class PCLRenderer extends PrintRenderer { } } + /** + * @see org.apache.fop.render.Renderer#setupFontInfo(org.apache.fop.fonts.FontInfo) + */ + public void setupFontInfo(FontInfo inFontInfo) { + //Don't call super.setupFontInfo() here! + //The PCLRenderer uses the Java2D FontSetup which needs a special font setup + //create a temp Image to test font metrics on + fontInfo = inFontInfo; + BufferedImage fontImage = new BufferedImage(100, 100, + BufferedImage.TYPE_INT_RGB); + Graphics2D g = fontImage.createGraphics(); + //The next line is important to get accurate font metrics! + g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + FontSetup.setup(fontInfo, g); + } + /** * Central exception handler for I/O exceptions. * @param ioe IOException to handle @@ -160,13 +181,24 @@ public class PCLRenderer extends PrintRenderer { return this.graphicContext; } + /** @return the target resolution */ + protected int getResolution() { + int resolution = (int)Math.round(userAgent.getTargetResolution()); + if (resolution <= 300) { + return 300; + } else { + return 600; + } + } + /** * 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 + * @return true if the font can be mapped to PCL * @throws IOException if an I/O problem occurs */ - public void setFont(String name, float size) throws IOException { + public boolean setFont(String name, float size) throws IOException { int fontcode = 0; if (name.length() > 1 && name.charAt(0) == 'F') { try { @@ -261,20 +293,25 @@ public class PCLRenderer extends PrintRenderer { gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T"); break; default: - gen.writeCommand("(0N"); - gen.writeCommand("(s" + formattedSize + "V"); - break; + //gen.writeCommand("(0N"); + //gen.writeCommand("(s" + formattedSize + "V"); + return false; } + return true; } /** @see org.apache.fop.render.Renderer#startRenderer(java.io.OutputStream) */ public void startRenderer(OutputStream outputStream) throws IOException { log.debug("Rendering areas to PCL..."); this.out = outputStream; - this.gen = new PCLGenerator(out); + this.gen = new PCLGenerator(out, getResolution()); gen.universalEndOfLanguage(); - gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n"); + gen.writeText("@PJL COMMENT Produced by " + userAgent.getProducer() + "\n"); + if (userAgent.getTitle() != null) { + gen.writeText("@PJL JOB NAME = \"" + userAgent.getTitle() + "\"\n"); + } + gen.writeText("@PJL SET RESOLUTION = " + getResolution() + "\n"); gen.writeText("@PJL ENTER LANGUAGE = PCL\n"); gen.resetPrinter(); } @@ -325,8 +362,8 @@ public class PCLRenderer extends PrintRenderer { gen.clearHorizontalMargins(); gen.setTopMargin(0); gen.setVMI(0); - gen.setUnitOfMeasure(600); - gen.setRasterGraphicsResolution(600); + gen.setUnitOfMeasure(getResolution()); + gen.setRasterGraphicsResolution(getResolution()); } /** Saves the current graphics state on the stack. */ @@ -486,35 +523,76 @@ public class PCLRenderer extends PrintRenderer { /** * @see org.apache.fop.render.AbstractRenderer#renderText(TextArea) */ - protected void renderText(TextArea area) { - //renderInlineAreaBackAndBorders(area); - String fontname = getInternalFontNameForArea(area); - int fontsize = area.getTraitAsInteger(Trait.FONT_SIZE); + protected void renderText(final TextArea text) { + renderInlineAreaBackAndBorders(text); + + String fontname = getInternalFontNameForArea(text); + int fontsize = text.getTraitAsInteger(Trait.FONT_SIZE); //Determine position - //int saveIP = currentIPPosition; - //int saveBP = currentBPPosition; - int rx = currentIPPosition + area.getBorderAndPaddingWidthStart(); - int bl = currentBPPosition + area.getOffset() + area.getBaselineOffset(); + int saveIP = currentIPPosition; + int rx = currentIPPosition + text.getBorderAndPaddingWidthStart(); + int bl = currentBPPosition + text.getOffset() + text.getBaselineOffset(); try { - setFont(fontname, fontsize); - Color col = (Color)area.getTrait(Trait.COLOR); - //this.currentFill = col; - if (col != null) { - //useColor(ct); - gen.setPatternTransparencyMode(false); - gen.selectCurrentPattern(gen.convertToPCLShade(col), 2); + final Color col = (Color)text.getTrait(Trait.COLOR); + boolean pclFont = setFont(fontname, fontsize); + if (pclFont) { + //this.currentFill = col; + if (col != null) { + //useColor(ct); + gen.setTransparencyMode(true, false); + gen.selectCurrentPattern(gen.convertToPCLShade(col), 2); + } + + saveGraphicsState(); + graphicContext.translate(rx, bl); + setCursorPos(0, 0); + gen.setTransparencyMode(true, true); + + super.renderText(text); //Updates IPD and renders words and spaces + restoreGraphicsState(); + } else { + //Use Java2D to paint different fonts via bitmap + final Font font = getFontFromArea(text); + final int baseline = text.getBaselineOffset(); + + //for cursive fonts, so the text isn't clipped + int extraWidth = font.getFontSize() / 3; + + Graphics2DAdapter g2a = getGraphics2DAdapter(); + final Rectangle paintRect = new Rectangle( + rx, currentBPPosition + text.getOffset(), + text.getIPD() + extraWidth, text.getBPD()); + RendererContext rc = createRendererContext(paintRect.x, paintRect.y, + paintRect.width, paintRect.height, null); + Map atts = new java.util.HashMap(); + atts.put(new QName(ExtensionElementMapping.URI, null, "conversion-mode"), "bitmap"); + rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts); + + 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.scale(1000, 1000); + g2d.setColor(col); + Java2DRenderer.renderText(text, g2d, font); + } + + public Dimension getImageSize() { + return paintRect.getSize(); + } + + }; + g2a.paintImage(painter, rc, + paintRect.x, paintRect.y, paintRect.width, paintRect.height); + currentIPPosition = saveIP + text.getAllocIPD(); } - - saveGraphicsState(); - graphicContext.translate(rx, bl); - setCursorPos(0, 0); - - super.renderText(area); //Updates IPD //renderTextDecoration(tf, fontsize, area, bl, rx); - restoreGraphicsState(); } catch (IOException ioe) { handleIOTrouble(ioe); } @@ -583,7 +661,7 @@ public class PCLRenderer extends PrintRenderer { protected void fillRect(float x, float y, float width, float height) { try { setCursorPos(x * 1000, y * 1000); - gen.fillRect((int)width * 1000, (int)height * 1000, + gen.fillRect((int)(width * 1000), (int)(height * 1000), this.currentFillColor); } catch (IOException ioe) { handleIOTrouble(ioe); @@ -625,7 +703,7 @@ public class PCLRenderer extends PrintRenderer { Font font = getFontFromArea(textArea); int tws = (space.isAdjustable() - ? ((TextArea) space.getParentArea()).getTextWordSpaceAdjust() + ? textArea.getTextWordSpaceAdjust() + 2 * textArea.getTextLetterSpaceAdjust() : 0); @@ -999,29 +1077,25 @@ public class PCLRenderer extends PrintRenderer { float width = borderRect.width; float height = borderRect.height; if (bpsBefore != null) { - int borderWidth = (int) Math.round((bpsBefore.width / 1000f)); + float borderWidth = bpsBefore.width / 1000f; updateFillColor(bpsBefore.color); - fillRect((int) startx, (int) starty, (int) width, - borderWidth); + fillRect(startx, starty, width, borderWidth); } if (bpsAfter != null) { - int borderWidth = (int) Math.round((bpsAfter.width / 1000f)); + float borderWidth = bpsAfter.width / 1000f; updateFillColor(bpsAfter.color); - fillRect((int) startx, - (int) (starty + height - borderWidth), (int) width, - borderWidth); + fillRect(startx, (starty + height - borderWidth), + width, borderWidth); } if (bpsStart != null) { - int borderWidth = (int) Math.round((bpsStart.width / 1000f)); + float borderWidth = bpsStart.width / 1000f; updateFillColor(bpsStart.color); - fillRect((int) startx, (int) starty, borderWidth, - (int) height); + fillRect(startx, starty, borderWidth, height); } if (bpsEnd != null) { - int borderWidth = (int) Math.round((bpsEnd.width / 1000f)); + float borderWidth = bpsEnd.width / 1000f; updateFillColor(bpsEnd.color); - fillRect((int) (startx + width - borderWidth), - (int) starty, borderWidth, (int) height); + fillRect((startx + width - borderWidth), starty, borderWidth, height); } }