Browse Source

Re-Implemented "quality" rendering mode (painting borders and rules using bitmaps).

Added a new rendering mode "bitmap" (in addition to "speed" and "bitmap") that uses Java2DPainter for the whole page and paints a single bitmap (much like most PCL drivers operate). Quality: "speed" < "quality" < "bitmap", Performance: "speed" > "quality" > "bitmap" (at high page complexity "bitmap" might actually be better), File Size: "speed" < "quality" < "bitmap"
Increased bitmap encoding performance by up to 100% (by optimizing the Java code and by supporting the "zeroed row" PCL command)

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_AreaTreeNewDesign@709119 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-1_0
Jeremias Maerki 15 years ago
parent
commit
a4847a2df3

+ 66
- 2
src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java View File

@@ -21,6 +21,7 @@ package org.apache.fop.render.intermediate;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.io.FileNotFoundException;
@@ -47,6 +48,8 @@ import org.apache.fop.events.ResourceEventProducer;
import org.apache.fop.render.ImageHandler;
import org.apache.fop.render.ImageHandlerRegistry;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;

/**
* Abstract base class for IFPainter implementations.
@@ -195,8 +198,8 @@ public abstract class AbstractIFPainter implements IFPainter {
+ effImage.getInfo() + " (" + effImage.getClass().getName() + ")");
}

if (log.isDebugEnabled()) {
log.debug("Using ImageHandler: " + handler.getClass().getName());
if (log.isTraceEnabled()) {
log.trace("Using ImageHandler: " + handler.getClass().getName());
}

//TODO foreign attributes
@@ -261,6 +264,67 @@ public abstract class AbstractIFPainter implements IFPainter {
}
}

/** {@inheritDoc} */
public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
BorderProps start, BorderProps end) throws IFException {
if (before != null) {
Rectangle b = new Rectangle(
rect.x, rect.y,
rect.width, before.width);
fillRect(b, before.color);
}
if (end != null) {
Rectangle b = new Rectangle(
rect.x + rect.width - end.width, rect.y,
end.width, rect.height);
fillRect(b, end.color);
}
if (after != null) {
Rectangle b = new Rectangle(
rect.x, rect.y + rect.height - after.width,
rect.width, after.width);
fillRect(b, after.color);
}
if (start != null) {
Rectangle b = new Rectangle(
rect.x, rect.y,
start.width, rect.height);
fillRect(b, start.color);
}
}

/** {@inheritDoc} */
public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
throws IFException {
Rectangle rect = getLineBoundingBox(start, end, width);
fillRect(rect, color);
}

/**
* Calculates the bounding box for a line. Currently, only horizontal and vertical lines
* are needed and supported.
* @param start the starting point of the line (coordinates in mpt)
* @param end the ending point of the line (coordinates in mpt)
* @param width the line width (in mpt)
* @return the bounding box (coordinates in mpt)
*/
protected Rectangle getLineBoundingBox(Point start, Point end, int width) {
if (start.y == end.y) {
int topy = start.y - width / 2;
return new Rectangle(
start.x, topy,
end.x - start.x, width);
} else if (start.x == end.y) {
int leftx = start.x - width / 2;
return new Rectangle(
leftx, start.x,
width, end.y - start.y);
} else {
throw new IllegalArgumentException(
"Only horizontal or vertical lines are supported at the moment.");
}
}

/** {@inheritDoc} */
public void setFont(String family, String style, Integer weight, String variant, Integer size,
Color color) throws IFException {

+ 15
- 3
src/java/org/apache/fop/render/pcl/DefaultMonochromeBitmapConverter.java View File

@@ -32,9 +32,13 @@ import java.awt.image.RenderedImage;
public class DefaultMonochromeBitmapConverter implements
MonochromeBitmapConverter {

private boolean quality = false;

/** {@inheritDoc} */
public void setHint(String name, String value) {
//ignore, not supported
if ("quality".equalsIgnoreCase(name)) {
quality = "true".equalsIgnoreCase(value);
}
}

/** {@inheritDoc} */
@@ -42,8 +46,16 @@ public class DefaultMonochromeBitmapConverter implements
BufferedImage buf = new BufferedImage(img.getWidth(), img.getHeight(),
BufferedImage.TYPE_BYTE_BINARY);
RenderingHints hints = new RenderingHints(null);
//This hint doesn't seem to make a difference :-(
hints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
//These hints don't seem to make a difference :-( Not seeing any dithering on Sun Java.
hints.put(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
if (quality) {
hints.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
hints.put(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
}

ColorConvertOp op = new ColorConvertOp(
ColorSpace.getInstance(ColorSpace.CS_GRAY), hints);
op.filter(img, buf);

+ 77
- 2
src/java/org/apache/fop/render/pcl/PCLDocumentHandler.java View File

@@ -19,18 +19,27 @@

package org.apache.fop.render.pcl;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.xmlgraphics.util.UnitConv;

import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.FopFactoryConfigurator;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler;
import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFPainter;
import org.apache.fop.render.java2d.Java2DPainter;

/**
* {@code IFDocumentHandler} implementation that produces PCL 5.
@@ -54,6 +63,10 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler
/** contains the pageHeight of the last printed page */
private long pageHeight = 0;

/** the current page image (only set when all-bitmap painting is activated) */
private BufferedImage currentImage;


/**
* Default constructor.
*/
@@ -190,12 +203,74 @@ public class PCLDocumentHandler extends AbstractBinaryWritingIFDocumentHandler

/** {@inheritDoc} */
public IFPainter startPageContent() throws IFException {
return new PCLPainter(this, this.currentPageDefinition);
if (pclUtil.getRenderingMode() == PCLRenderingMode.BITMAP) {
return createAllBitmapPainter();
} else {
return new PCLPainter(this, this.currentPageDefinition);
}
}

private IFPainter createAllBitmapPainter() {
double scale = gen.getMaximumBitmapResolution()
/ FopFactoryConfigurator.DEFAULT_TARGET_RESOLUTION;
Rectangle printArea = this.currentPageDefinition.getLogicalPageRect();
int bitmapWidth = (int)Math.ceil(
UnitConv.mpt2px(printArea.width, gen.getMaximumBitmapResolution()));
int bitmapHeight = (int)Math.ceil(
UnitConv.mpt2px(printArea.height, gen.getMaximumBitmapResolution()));
this.currentImage = createBufferedImage(bitmapWidth, bitmapHeight);
Graphics2D graphics2D = this.currentImage.createGraphics();

if (!PCLGenerator.isJAIAvailable()) {
RenderingHints hints = new RenderingHints(null);
//These hints don't seem to make a difference :-( Not seeing any dithering on Sun Java.
hints.put(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_ENABLE);
graphics2D.addRenderingHints(hints);
}

//Ensure white page background
graphics2D.setBackground(Color.WHITE);
graphics2D.clearRect(0, 0, bitmapWidth, bitmapHeight);

graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
RenderingHints.VALUE_FRACTIONALMETRICS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
graphics2D.scale(scale / 1000f, scale / 1000f);
graphics2D.translate(-printArea.x, -printArea.y);

return new Java2DPainter(graphics2D, getUserAgent(), getFontInfo());
}

private BufferedImage createBufferedImage(int bitmapWidth, int bitmapHeight) {
int bitmapType;
if (PCLGenerator.isJAIAvailable()) {
//TYPE_BYTE_GRAY was used to work around the lack of dithering when using
//TYPE_BYTE_BINARY. Adding RenderingHints didn't help.
bitmapType = BufferedImage.TYPE_BYTE_GRAY;
//bitmapType = BufferedImage.TYPE_INT_RGB; //Use to enable Batik gradients
} else {
bitmapType = BufferedImage.TYPE_BYTE_BINARY;
}
return new BufferedImage(
bitmapWidth, bitmapHeight, bitmapType);
}

/** {@inheritDoc} */
public void endPageContent() throws IFException {
//nop
if (this.currentImage != null) {
try {
//ImageWriterUtil.saveAsPNG(this.currentImage, new java.io.File("D:/page.png"));
Rectangle printArea = this.currentPageDefinition.getLogicalPageRect();
gen.setCursorPos(0, 0);
gen.paintBitmap(this.currentImage, printArea.getSize(), true);
} catch (IOException ioe) {
throw new IFException("I/O error while encoding page image", ioe);
} finally {
this.currentImage = null;
}
}
}

/** {@inheritDoc} */

+ 164
- 52
src/java/org/apache/fop/render/pcl/PCLGenerator.java View File

@@ -30,8 +30,10 @@ import java.awt.image.ByteLookupTable;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.IndexColorModel;
import java.awt.image.LookupOp;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
@@ -604,6 +606,26 @@ public class PCLGenerator {
return (img.getColorModel().getNumColorComponents() == 1);
}

private static int jaiAvailable = -1; //no synchronization necessary, not critical

/**
* Indicates whether JAI is available. JAI has shown to be reliable when dithering a
* grayscale or color image to monochrome bitmaps (1-bit).
* @return true if JAI is available
*/
public static boolean isJAIAvailable() {
if (jaiAvailable < 0) {
try {
String clName = "org.apache.fop.render.pcl.JAIMonochromeBitmapConverter";
Class.forName(clName);
jaiAvailable = 1;
} catch (ClassNotFoundException cnfe) {
jaiAvailable = 0;
}
}
return (jaiAvailable > 0);
}

private MonochromeBitmapConverter createMonochromeBitmapConverter() {
MonochromeBitmapConverter converter = null;
try {
@@ -839,6 +861,16 @@ public class PCLGenerator {
g2d.clearRect(0, 0, effDim.width, effDim.height);
}

private int toGray(int rgb) {
// see http://www.jguru.com/faq/view.jsp?EID=221919
double greyVal = 0.072169d * (rgb & 0xff);
rgb >>= 8;
greyVal += 0.715160d * (rgb & 0xff);
rgb >>= 8;
greyVal += 0.212671d * (rgb & 0xff);
return (int)greyVal;
}

/**
* Paint a bitmap at the current cursor position. The bitmap must be a monochrome
* (1-bit) bitmap image.
@@ -850,79 +882,159 @@ public class PCLGenerator {
if (!isValidPCLResolution(resolution)) {
throw new IllegalArgumentException("Invalid PCL resolution: " + resolution);
}
setRasterGraphicsResolution(resolution);
writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
Raster raster = img.getData();
boolean monochrome = isMonochromeImage(img);
if (!monochrome) {
throw new IllegalArgumentException("img must be a monochrome image");
}

int x = 0;
int y = 0;
int imgw = img.getWidth();
int imgh = img.getHeight();
int bytewidth = (imgw / 8);
if ((imgw % 8) != 0) {
bytewidth++;
}
byte ib;
byte[] rle = new byte[bytewidth * 2]; //compressed (RLE)
byte[] uncompressed = new byte[bytewidth]; //uncompressed
int lastcount = -1;
byte lastbyte = 0;
int rlewidth = 0;
setRasterGraphicsResolution(resolution);
writeCommand("*r0f" + img.getHeight() + "t" + img.getWidth() + "s1A");
Raster raster = img.getData();

Encoder encoder = new Encoder(img);
// Transfer graphics data
for (y = 0; y < imgh; y++) {
ib = 0;
for (x = 0; x < imgw; x++) {
int sample = raster.getSample(x, y, 0);
//Set image bit for black
if ((sample == 0)) {
ib |= (1 << (7 - (x % 8)));
}

//RLE encoding
if ((x % 8) == 7 || ((x + 1) == imgw)) {
if (rlewidth < bytewidth) {
if (lastcount >= 0) {
if (ib == lastbyte) {
lastcount++;
} else {
rle[rlewidth++] = (byte)(lastcount & 0xFF);
rle[rlewidth++] = lastbyte;
lastbyte = ib;
lastcount = 0;
}
int imgw = img.getWidth();
IndexColorModel cm = (IndexColorModel)img.getColorModel();
if (cm.getTransferType() == DataBuffer.TYPE_BYTE) {
DataBufferByte dataBuffer = (DataBufferByte)raster.getDataBuffer();
MultiPixelPackedSampleModel packedSampleModel = new MultiPixelPackedSampleModel(
DataBuffer.TYPE_BYTE, img.getWidth(), img.getHeight(), 1);
if (img.getSampleModel().equals(packedSampleModel)
&& dataBuffer.getNumBanks() == 1) {
//Optimized packed encoding
byte[] buf = dataBuffer.getData();
int scanlineStride = packedSampleModel.getScanlineStride();
int idx = 0;
int c0 = toGray(cm.getRGB(0));
int c1 = toGray(cm.getRGB(1));
boolean zeroIsWhite = c0 > c1;
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
for (int x = 0, maxx = scanlineStride; x < maxx; x++) {
if (zeroIsWhite) {
encoder.add8Bits(buf[idx]);
} else {
lastbyte = ib;
lastcount = 0;
}
if (lastcount == 255 || ((x + 1) == imgw)) {
rle[rlewidth++] = (byte)(lastcount & 0xFF);
rle[rlewidth++] = lastbyte;
lastbyte = 0;
lastcount = -1;
encoder.add8Bits((byte)~buf[idx]);
}
idx++;
}
uncompressed[x / 8] = ib;
ib = 0;
encoder.endLine();
}
} else {
//Optimized non-packed encoding
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
byte[] line = (byte[])raster.getDataElements(0, y, imgw, 1, null);
for (int x = 0, maxx = imgw; x < maxx; x++) {
encoder.addBit(line[x] == 0);
}
encoder.endLine();
}
}
} else {
//Safe but slow fallback
for (int y = 0, maxy = img.getHeight(); y < maxy; y++) {
for (int x = 0, maxx = imgw; x < maxx; x++) {
int sample = raster.getSample(x, y, 0);
encoder.addBit(sample == 0);
}
encoder.endLine();
}
}

// End raster graphics
writeCommand("*rB");
}

private class Encoder {

private int imgw;
private int bytewidth;
private byte[] rle; //compressed (RLE)
private byte[] uncompressed; //uncompressed
private int lastcount = -1;
private byte lastbyte = 0;
private int rlewidth = 0;
private byte ib = 0; //current image bits
private int x = 0;
private boolean zeroRow = true;

public Encoder(RenderedImage img) {
imgw = img.getWidth();
bytewidth = (imgw / 8);
if ((imgw % 8) != 0) {
bytewidth++;
}
rle = new byte[bytewidth * 2];
uncompressed = new byte[bytewidth];
}

public void addBit(boolean bit) {
//Set image bit for black
if (bit) {
ib |= 1;
}

//RLE encoding
if ((x % 8) == 7 || ((x + 1) == imgw)) {
finishedByte();
} else {
ib <<= 1;
}
x++;
}

public void add8Bits(byte b) {
ib = b;
finishedByte();
x += 8;
}

private void finishedByte() {
if (rlewidth < bytewidth) {
if (lastcount >= 0) {
if (ib == lastbyte) {
lastcount++;
} else {
rle[rlewidth++] = (byte)(lastcount & 0xFF);
rle[rlewidth++] = lastbyte;
lastbyte = ib;
lastcount = 0;
}
} else {
lastbyte = ib;
lastcount = 0;
}
if (lastcount == 255 || ((x + 1) == imgw)) {
rle[rlewidth++] = (byte)(lastcount & 0xFF);
rle[rlewidth++] = lastbyte;
lastbyte = 0;
lastcount = -1;
}
}
uncompressed[x / 8] = ib;
if (ib != 0) {
zeroRow = false;
}
ib = 0;
}

public void endLine() throws IOException {
if (zeroRow) {
writeCommand("*b1Y");
} else if (rlewidth < bytewidth) {
writeCommand("*b1m" + rlewidth + "W");
this.out.write(rle, 0, rlewidth);
out.write(rle, 0, rlewidth);
} else {
writeCommand("*b0m" + bytewidth + "W");
this.out.write(uncompressed);
out.write(uncompressed);
}
lastcount = -1;
rlewidth = 0;
ib = 0;
x = 0;
zeroRow = true;
}

// End raster graphics
writeCommand("*rB");

}

}

+ 16
- 0
src/java/org/apache/fop/render/pcl/PCLPageDefinition.java View File

@@ -114,6 +114,22 @@ public class PCLPageDefinition {
return null;
}

/**
* Returns a page definition based on a page format.
* @param name the name of the page format (ex. "A4" or "Letter")
* @return the page definition or null if no match was found
*/
public static PCLPageDefinition getPageDefinition(String name) {
Iterator iter = pageDefinitions.iterator();
while (iter.hasNext()) {
PCLPageDefinition def = (PCLPageDefinition)iter.next();
if (def.getName().equalsIgnoreCase(name)) {
return def;
}
}
return null;
}

/** @return the default page definition (letter) */
public static PCLPageDefinition getDefaultPageDefinition() {
return defaultPageDefinition;

+ 92
- 42
src/java/org/apache/fop/render/pcl/PCLPainter.java View File

@@ -66,7 +66,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
/** logging instance */
private static Log log = LogFactory.getLog(PCLPainter.class);

private final boolean DEBUG = false;
private static final boolean DEBUG = false;

private PCLDocumentHandler parent;

@@ -173,10 +173,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
/** {@inheritDoc} */
public void clipRect(Rectangle rect) throws IFException {
//PCL cannot clip (only HP GL/2 can)
/*
generator.endTextObject();
generator.clipRect(rect);
*/
//If you need clipping support, switch to RenderingMode.BITMAP.
}

/** {@inheritDoc} */
@@ -203,23 +200,97 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
}

/** {@inheritDoc} */
public void drawBorderRect(Rectangle rect, BorderProps before, BorderProps after,
BorderProps start, BorderProps end) throws IFException {
public void drawBorderRect(final Rectangle rect,
final BorderProps before, final BorderProps after,
final BorderProps start, final BorderProps end) throws IFException {
if (getPCLUtil().getRenderingMode() == PCLRenderingMode.SPEED) {
super.drawBorderRect(rect, before, after, start, end);
return;
}
if (before != null || after != null || start != null || end != null) {
/*
generator.endTextObject();
this.borderPainter.drawBorders(rect, before, after, start, end);
*/
final Rectangle boundingBox = rect;
final Dimension dim = boundingBox.getSize();

Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public void paint(Graphics2D g2d, Rectangle2D area) {
g2d.translate(-rect.x, -rect.y);

Java2DPainter painter = new Java2DPainter(g2d,
getUserAgent(), parent.getFontInfo(), state);
try {
painter.drawBorderRect(rect, before, after, start, end);
} catch (IFException e) {
//This should never happen with the Java2DPainter
throw new RuntimeException("Unexpected error while painting borders", e);
}
}

public Dimension getImageSize() {
return dim.getSize();
}

};
paintMarksAsBitmap(painter, boundingBox);
}
}

/** {@inheritDoc} */
public void drawLine(Point start, Point end, int width, Color color, RuleStyle style)
public void drawLine(final Point start, final Point end,
final int width, final Color color, final RuleStyle style)
throws IFException {
/*
generator.endTextObject();
this.borderPainter.drawLine(start, end, width, color, style);
*/
if (getPCLUtil().getRenderingMode() == PCLRenderingMode.SPEED) {
super.drawLine(start, end, width, color, style);
return;
}
final Rectangle boundingBox = getLineBoundingBox(start, end, width);
final Dimension dim = boundingBox.getSize();

Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public void paint(Graphics2D g2d, Rectangle2D area) {
g2d.translate(-boundingBox.x, -boundingBox.y);

Java2DPainter painter = new Java2DPainter(g2d,
getUserAgent(), parent.getFontInfo(), state);
try {
painter.drawLine(start, end, width, color, style);
} catch (IFException e) {
//This should never happen with the Java2DPainter
throw new RuntimeException("Unexpected error while painting a line", e);
}
}

public Dimension getImageSize() {
return dim.getSize();
}

};
paintMarksAsBitmap(painter, boundingBox);
}

private void paintMarksAsBitmap(Graphics2DImagePainter painter, Rectangle boundingBox)
throws IFException {
ImageInfo info = new ImageInfo(null, null);
ImageSize size = new ImageSize();
size.setSizeInMillipoints(boundingBox.width, boundingBox.height);
info.setSize(size);
ImageGraphics2D img = new ImageGraphics2D(info, painter);

Map hints = new java.util.HashMap();
hints.put(ImageProcessingHints.BITMAP_TYPE_INTENT,
ImageProcessingHints.BITMAP_TYPE_INTENT_GRAY);
PCLRenderingContext context = (PCLRenderingContext)createRenderingContext();
context.setSourceTransparencyEnabled(true);
try {
drawImage(img, boundingBox, context, true, hints);
} catch (IOException ioe) {
throw new IFException(
"I/O error while painting marks using a bitmap", ioe);
} catch (ImageException ie) {
throw new IFException(
"Error while painting marks using a bitmap", ie);
}
}

/** {@inheritDoc} */
@@ -246,8 +317,6 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
}
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
} catch (ImageException ime) {
throw new IFException("Image processing error in drawText()", ime);
}
}

@@ -304,7 +373,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {

private static final double SAFETY_MARGIN_FACTOR = 0.05;

private Rectangle getTextBoundingRect(int x, int y, int[] dx, int[] dy, String text,
private Rectangle getTextBoundingBox(int x, int y, int[] dx, int[] dy, String text,
Font font, FontMetricsMapper metrics) {
int maxAscent = metrics.getMaxAscent(font.getFontSize()) / 1000;
int descent = metrics.getDescender(font.getFontSize()) / 1000; //is negative
@@ -339,11 +408,9 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
}

private void drawTextAsBitmap(final int x, final int y, final int[] dx, final int[] dy,
final String text, FontTriplet triplet) throws IOException, ImageException {
final String text, FontTriplet triplet) throws IFException {
//Use Java2D to paint different fonts via bitmap
final Font font = parent.getFontInfo().getFontInstance(triplet, state.getFontSize());
//final Font font = getFontFromArea(text);
//final int baseline = text.getBaselineOffset();

//for cursive fonts, so the text isn't clipped
final FontMetricsMapper mapper = (FontMetricsMapper)parent.getFontInfo().getMetricsFor(
@@ -354,14 +421,9 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
int safetyMargin = (int)(SAFETY_MARGIN_FACTOR * font.getFontSize());
final int baselineOffset = maxAscent + safetyMargin;

final Rectangle boundingRect = getTextBoundingRect(x, y, dx, dy, text, font, mapper);
final Rectangle boundingBox = getTextBoundingBox(x, y, dx, dy, text, font, mapper);
final Dimension dim = boundingBox.getSize();

Map atts = new java.util.HashMap();
atts.put(CONV_MODE, "bitmap");
atts.put(SRC_TRANSPARENCY, "true");
//rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);

final Dimension dim = boundingRect.getSize();
Graphics2DImagePainter painter = new Graphics2DImagePainter() {

public void paint(Graphics2D g2d, Rectangle2D area) {
@@ -394,19 +456,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants {
}

};
ImageInfo info = new ImageInfo(null, null);
ImageSize size = new ImageSize();
size.setSizeInMillipoints(boundingRect.width, boundingRect.height);
info.setSize(size);
ImageGraphics2D img = new ImageGraphics2D(info, painter);

Rectangle rect = boundingRect;
Map hints = new java.util.HashMap();
hints.put(ImageProcessingHints.BITMAP_TYPE_INTENT,
ImageProcessingHints.BITMAP_TYPE_INTENT_GRAY);
PCLRenderingContext context = (PCLRenderingContext)createRenderingContext();
context.setSourceTransparencyEnabled(true);
drawImage(img, rect, context, true, hints);
paintMarksAsBitmap(painter, boundingBox);
}

/** Saves the current graphics state on the stack. */

+ 5
- 4
src/java/org/apache/fop/render/pcl/PCLRenderer.java View File

@@ -164,7 +164,8 @@ public class PCLRenderer extends PrintRenderer implements PCLConstants {
* @param qualityBeforeSpeed true if quality is more important than speed
*/
public void setQualityBeforeSpeed(boolean qualityBeforeSpeed) {
pclUtil.setQualityBeforeSpeed(qualityBeforeSpeed);
pclUtil.setRenderingMode(qualityBeforeSpeed
? PCLRenderingMode.QUALITY : PCLRenderingMode.SPEED);
}

/**
@@ -1187,10 +1188,10 @@ public class PCLRenderer extends PrintRenderer implements PCLConstants {
if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
return; //no borders to paint
}
if (pclUtil.isQualityBeforeSpeed()) {
drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
} else {
if (PCLRenderingMode.SPEED == pclUtil.getRenderingMode()) {
drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
} else {
drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
}
}


+ 4
- 6
src/java/org/apache/fop/render/pcl/PCLRendererConfigurator.java View File

@@ -75,13 +75,11 @@ public class PCLRendererConfigurator extends PrintRendererConfigurator

private void configure(Configuration cfg, PCLRenderingUtil pclUtil) throws FOPException {
String rendering = cfg.getChild("rendering").getValue(null);
if ("quality".equalsIgnoreCase(rendering)) {
pclUtil.setQualityBeforeSpeed(true);
} else if ("speed".equalsIgnoreCase(rendering)) {
pclUtil.setQualityBeforeSpeed(false);
} else if (rendering != null) {
try {
pclUtil.setRenderingMode(PCLRenderingMode.valueOf(rendering));
} catch (IllegalArgumentException e) {
throw new FOPException(
"Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
"Valid values for 'rendering' are 'quality', 'speed' and 'bitmap'. Value found: "
+ rendering);
}


+ 82
- 0
src/java/org/apache/fop/render/pcl/PCLRenderingMode.java View File

@@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.pcl;

import java.io.ObjectStreamException;
import java.io.Serializable;

/**
* Enumeration class for PCL rendering modes.
*/
public final class PCLRenderingMode implements Serializable {

private static final long serialVersionUID = 6359884255324755026L;

/** "Quality" rendering (mixed native and bitmap for improved quality) */
public static final PCLRenderingMode QUALITY = new PCLRenderingMode("quality");
/** "Speed" rendering (maximum speed with native rendering, reduced visual quality) */
public static final PCLRenderingMode SPEED = new PCLRenderingMode("speed");
/**
* "Bitmap" rendering (pages are painted entirely as bitmaps, maximum quality,
* reduced performance)
*/
public static final PCLRenderingMode BITMAP = new PCLRenderingMode("bitmap");

private String name;

/**
* Constructor to add a new named item.
* @param name Name of the item.
*/
private PCLRenderingMode(String name) {
this.name = name;
}

/** @return the name of the enum */
public String getName() {
return this.name;
}

/**
* Returns the enumeration/singleton object based on its name.
* @param name the name of the enumeration value
* @return the enumeration object
*/
public static PCLRenderingMode valueOf(String name) {
if (QUALITY.getName().equalsIgnoreCase(name)) {
return QUALITY;
} else if (SPEED.getName().equalsIgnoreCase(name)) {
return SPEED;
} else if (BITMAP.getName().equalsIgnoreCase(name)) {
return BITMAP;
} else {
throw new IllegalArgumentException("Illegal value for enumeration: " + name);
}
}

private Object readResolve() throws ObjectStreamException {
return valueOf(getName());
}

/** {@inheritDoc} */
public String toString() {
return "PCLRenderingMode:" + name;
}
}

+ 9
- 9
src/java/org/apache/fop/render/pcl/PCLRenderingUtil.java View File

@@ -42,10 +42,10 @@ public class PCLRenderingUtil {
private FOUserAgent userAgent;

/**
* Controls whether appearance is more important than speed. False can cause some FO feature
* Controls whether appearance is more important than speed. "SPEED" can cause some FO feature
* to be ignored (like the advanced borders).
*/
private boolean qualityBeforeSpeed = false;
private PCLRenderingMode renderingMode = PCLRenderingMode.SPEED;

/**
* Controls whether all text should be painted as text. This is a fallback setting in case
@@ -84,18 +84,18 @@ public class PCLRenderingUtil {
/**
* Configures the renderer to trade speed for quality if desired. One example here is the way
* that borders are rendered.
* @param qualityBeforeSpeed true if quality is more important than speed
* @param mode one of the {@code PCLRenderingMode}.* constants
*/
public void setQualityBeforeSpeed(boolean qualityBeforeSpeed) {
this.qualityBeforeSpeed = qualityBeforeSpeed;
public void setRenderingMode(PCLRenderingMode mode) {
this.renderingMode = mode;
}

/**
* Indicates whether quality is more important than speed.
* @return true if quality is favored over speed
* Returns the selected rendering mode.
* @return the rendering mode
*/
public boolean isQualityBeforeSpeed() {
return this.qualityBeforeSpeed;
public PCLRenderingMode getRenderingMode() {
return this.renderingMode;
}

/**

Loading…
Cancel
Save