From d8a9dfe792e9ee4816928b2b066cebbd16286bfb Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Wed, 26 Jul 2006 12:06:49 +0000 Subject: [PATCH] Attempt to make grayscale patterns look nicer when using PCL commands. The standard PCL shades are very coarse and I replaced them with a simple 4x4 bayer dither pattern defined as a user-defined pattern in PCL. Current side-effect: Darker gray values will result in almost black output on some printers (at least on mine). git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@425716 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/render/pcl/PCLGenerator.java | 92 +++++++++++++++++-- .../apache/fop/render/pcl/PCLRenderer.java | 2 +- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/java/org/apache/fop/render/pcl/PCLGenerator.java b/src/java/org/apache/fop/render/pcl/PCLGenerator.java index 8612a51e6..31d8fd57d 100644 --- a/src/java/org/apache/fop/render/pcl/PCLGenerator.java +++ b/src/java/org/apache/fop/render/pcl/PCLGenerator.java @@ -34,12 +34,14 @@ import java.awt.image.LookupOp; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; +import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Locale; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.fop.util.UnitConv; import org.apache.xmlgraphics.image.GraphicsUtil; @@ -64,6 +66,12 @@ public class PCLGenerator { private boolean currentPatternTransparency = true; private int maxBitmapResolution = PCL_RESOLUTIONS[PCL_RESOLUTIONS.length - 1]; + + /** + * true: Standard PCL shades are used (poor quality). false: user-defined pattern are used + * to create custom dither patterns for better grayscale quality. + */ + private boolean usePCLShades = false; /** * Main constructor. @@ -337,17 +345,71 @@ public class PCLGenerator { } else { //y += h; } - setPatternTransparencyMode(false); - writeCommand("*c" + formatDouble4(w / 100) + "h" - + formatDouble4(h / 100) + "V"); - int lineshade = convertToPCLShade(col); - writeCommand("*c" + lineshade + "G"); - writeCommand("*c2P"); + if (false) { + writeCommand("*c" + formatDouble4(w / 100) + "h" + + formatDouble4(h / 100) + "V"); + int lineshade = convertToPCLShade(col); + writeCommand("*c" + lineshade + "G"); + writeCommand("*c2P"); //Shaded fill + } else { + defineGrayscalePattern(col, 32); + + writeCommand("*c" + formatDouble4(w / 100) + "h" + + formatDouble4(h / 100) + "V"); + writeCommand("*c32G"); + writeCommand("*c4P"); //User-defined pattern + } // Reset pattern transparency mode. setPatternTransparencyMode(true); } + /** + * Generates a user-defined pattern for a dithering pattern matching the grayscale value + * of the color given. + * @param col the color to create the pattern for + * @param patternID the pattern ID to use + * @throws IOException In case of an I/O error + */ + public void defineGrayscalePattern(Color col, int patternID) throws IOException { + ByteArrayOutputStream baout = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(baout); + data.writeByte(0); //Format + data.writeByte(0); //Continuation + data.writeByte(1); //Pixel Encoding + data.writeByte(0); //Reserved + data.writeShort(8); //Width in Pixels + data.writeShort(8); //Height in Pixels + //data.writeShort(600); //X Resolution (didn't manage to get that to work) + //data.writeShort(600); //Y Resolution + final int[] dither4x4 = {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; + int gray255 = convertToGray(col.getRed(), col.getGreen(), col.getBlue()); + int gray17 = gray255 * 17 / 255; + + //Since a 4x4 pattern did not work, the 4x4 pattern is applied 4 times to an 8x8 pattern. + //Maybe this could be changed to use an 8x8 bayer dither pattern instead of the 4x4 one. + byte[] pattern = new byte[dither4x4.length / 8 * 4]; + + for (int i = 0, c = dither4x4.length; i < c; i++) { + boolean dot = !(dither4x4[i] < gray17 - 1); + if (dot) { + int byteIdx = i / 4; + pattern[byteIdx] |= 1 << (i % 4); + pattern[byteIdx] |= 1 << ((i % 4) + 4); + pattern[byteIdx + 4] |= 1 << (i % 4); + pattern[byteIdx + 4] |= 1 << ((i % 4) + 4); + } + } + data.write(pattern); + if ((baout.size() % 2) > 0) { + baout.write(0); + } + writeCommand("*c" + patternID + "G"); + writeCommand("*c" + baout.size() + "W"); + baout.writeTo(this.out); + writeCommand("*c4Q"); //temporary pattern + } + /** * Sets the source transparency mode. * @param transparent true if transparent, false for opaque @@ -405,6 +467,24 @@ public class PCLGenerator { return (int)(100 - (gray * 100f)); } + /** + * Selects the current grayscale color (the given color is converted to grayscales). + * @param col the color + * @throws IOException In case of an I/O error + */ + public void selectGrayscale(Color col) throws IOException { + if (col.equals(Color.black)) { + selectCurrentPattern(0, 0); //black + } else { + if (usePCLShades ) { + selectCurrentPattern(convertToPCLShade(col), 2); + } else { + defineGrayscalePattern(col, 32); + selectCurrentPattern(32, 4); + } + } + } + /** * Select the current pattern * @param patternID the pattern ID (*c#G command) diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderer.java b/src/java/org/apache/fop/render/pcl/PCLRenderer.java index 05952d933..36031f7ec 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderer.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderer.java @@ -588,7 +588,7 @@ public class PCLRenderer extends PrintRenderer { if (col != null) { //useColor(ct); gen.setTransparencyMode(true, false); - gen.selectCurrentPattern(gen.convertToPCLShade(col), 2); + gen.selectGrayscale(col); } saveGraphicsState(); -- 2.39.5