org.apache.fop.render.pdf.PDFImageHandlerSVG\r
org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage\r
org.apache.fop.render.java2d.Java2DImageHandlerGraphics2D\r
+org.apache.fop.render.pcl.PCLImageHandlerRenderedImage\r
package org.apache.fop.render.intermediate;
+import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageException;
import org.apache.xmlgraphics.image.loader.ImageInfo;
import org.apache.xmlgraphics.image.loader.ImageManager;
/** non-URI that can be used in feedback messages that an image is an instream-object */
protected static final String INSTREAM_OBJECT_URI = "(instream-object)";
+ /** Holds the intermediate format state */
+ protected IFState state;
+
/**
* Default constructor.
//Load and convert the image to a supported format
RenderingContext context = createRenderingContext();
- Map hints = ImageUtil.getDefaultHints(sessionContext);
+ Map hints = createDefaultImageProcessingHints(sessionContext);
org.apache.xmlgraphics.image.loader.Image img = manager.getImage(
info, imageHandlerRegistry.getSupportedFlavors(context),
hints, sessionContext);
+ try {
+ drawImage(img, rect, context);
+ } catch (IOException ioe) {
+ ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
+ getUserAgent().getEventBroadcaster());
+ eventProducer.imageWritingError(this, ioe);
+ }
+ }
+
+ /**
+ * Creates the default map of processing hints for the image loading framework.
+ * @param sessionContext the session context for access to resolution information
+ * @return the default processing hints
+ */
+ protected Map createDefaultImageProcessingHints(ImageSessionContext sessionContext) {
+ return ImageUtil.getDefaultHints(sessionContext);
+ }
+
+ /**
+ * Draws an image using a suitable image handler.
+ * @param image the image to be painted (it needs to of a supported image flavor)
+ * @param rect the rectangle in which to paint the image
+ * @param context a suitable rendering context
+ * @throws IOException in case of an I/O error while handling/writing the image
+ * @throws ImageException if an error occurs while converting the image to a suitable format
+ */
+ protected void drawImage(Image image, Rectangle rect,
+ RenderingContext context) throws IOException, ImageException {
+ drawImage(image, rect, context, false, null);
+ }
+
+ /**
+ * Draws an image using a suitable image handler.
+ * @param image the image to be painted (it needs to of a supported image flavor)
+ * @param rect the rectangle in which to paint the image
+ * @param context a suitable rendering context
+ * @param convert true to run the image through image conversion if that is necessary
+ * @param additionalHints additional image processing hints
+ * @throws IOException in case of an I/O error while handling/writing the image
+ * @throws ImageException if an error occurs while converting the image to a suitable format
+ */
+ protected void drawImage(Image image, Rectangle rect,
+ RenderingContext context, boolean convert, Map additionalHints)
+ throws IOException, ImageException {
+ ImageManager manager = getFopFactory().getImageManager();
+ ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry();
+
+ Image effImage;
+ if (convert) {
+ Map hints = createDefaultImageProcessingHints(getUserAgent().getImageSessionContext());
+ if (additionalHints != null) {
+ hints.putAll(additionalHints);
+ }
+ effImage = manager.convertImage(image,
+ imageHandlerRegistry.getSupportedFlavors(context), hints);
+ } else {
+ effImage = image;
+ }
+
//First check for a dynamically registered handler
- ImageHandler handler = imageHandlerRegistry.getHandler(context, img);
+ ImageHandler handler = imageHandlerRegistry.getHandler(context, effImage);
if (handler == null) {
throw new UnsupportedOperationException(
"No ImageHandler available for image: "
- + info + " (" + img.getClass().getName() + ")");
+ + effImage.getInfo() + " (" + effImage.getClass().getName() + ")");
}
if (log.isDebugEnabled()) {
log.debug("Using ImageHandler: " + handler.getClass().getName());
}
- try {
- //TODO foreign attributes
- handler.handleImage(context, img, rect);
- } catch (IOException ioe) {
- ResourceEventProducer eventProducer = ResourceEventProducer.Provider.get(
- getUserAgent().getEventBroadcaster());
- eventProducer.imageWritingError(this, ioe);
- return;
- }
+
+ //TODO foreign attributes
+ handler.handleImage(context, effImage, rect);
}
/**
}
}
+ /** {@inheritDoc} */
+ public void setFont(String family, String style, Integer weight, String variant, Integer size,
+ Color color) throws IFException {
+ if (family != null) {
+ state.setFontFamily(family);
+ }
+ if (style != null) {
+ state.setFontStyle(style);
+ }
+ if (weight != null) {
+ state.setFontWeight(weight.intValue());
+ }
+ if (variant != null) {
+ state.setFontVariant(variant);
+ }
+ if (size != null) {
+ state.setFontSize(size.intValue());
+ }
+ if (color != null) {
+ state.setTextColor(color);
+ }
+ }
}
import org.apache.xmlgraphics.image.loader.Image;
import org.apache.xmlgraphics.image.loader.ImageFlavor;
import org.apache.xmlgraphics.image.loader.ImageInfo;
-import org.apache.xmlgraphics.image.loader.impl.ImageRawStream;
import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
import org.apache.fop.render.ImageHandler;
/** {@inheritDoc} */
public Class getSupportedImageClass() {
- return ImageRawStream.class;
+ return ImageRendered.class;
}
/** {@inheritDoc} */
/** The font information */
protected FontInfo fontInfo;
- /** Holds the intermediate format state */
- protected IFState state;
-
private Java2DBorderPainter borderPainter;
/** The current state, holds a Graphics2D and its context */
* @param fontInfo the font information
*/
public Java2DPainter(Graphics2D g2d, FOUserAgent userAgent, FontInfo fontInfo) {
+ this(g2d, userAgent, fontInfo, null);
+ }
+
+ /**
+ * Special constructor for embedded use (when another painter uses Java2DPainter
+ * to convert part of a document into a bitmap, for example).
+ * @param g2d the target Graphics2D instance
+ * @param userAgent the user agent
+ * @param fontInfo the font information
+ */
+ public Java2DPainter(Graphics2D g2d, FOUserAgent userAgent, FontInfo fontInfo, IFState state) {
super();
this.userAgent = userAgent;
- this.state = IFState.create();
+ if (state != null) {
+ this.state = state.push();
+ } else {
+ this.state = IFState.create();
+ }
this.fontInfo = fontInfo;
this.g2dState = new Java2DGraphicsState(g2d, fontInfo, g2d.getTransform());
this.borderPainter = new Java2DBorderPainter(this);
g2d.drawGlyphVector(gv, x, y);
}
- /** {@inheritDoc} */
- public void setFont(String family, String style, Integer weight, String variant, Integer size,
- Color color) throws IFException {
- if (family != null) {
- state.setFontFamily(family);
- }
- if (style != null) {
- state.setFontStyle(style);
- }
- if (weight != null) {
- state.setFontWeight(weight.intValue());
- }
- if (variant != null) {
- state.setFontVariant(variant);
- }
- if (size != null) {
- state.setFontSize(size.intValue());
- }
- if (color != null) {
- state.setTextColor(color);
- }
- }
-
- //----------------------------------------------------------------------------------------------
-
/** Saves the current graphics state on the stack. */
protected void saveGraphicsState() {
g2dStateStack.push(g2dState);
import org.apache.fop.render.AbstractRenderingContext;
/**
- * Rendering context for PDF production.
+ * Rendering context for Java2D painting.
*/
public class Java2DRenderingContext extends AbstractRenderingContext {
--- /dev/null
+/*
+ * 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.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This class hold code for selecting a set of hard-coded fonts available in practically all
+ * PCL implementations. We hope this can be improved in the future.
+ */
+class HardcodedFonts {
+
+ /** logging instance */
+ private static Log log = LogFactory.getLog(HardcodedFonts.class);
+
+ /**
+ * 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 (in millipoints)
+ * @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 static boolean setFont(PCLGenerator gen, String name, int 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;
+ }
+ }
+ return selectFont(gen, name, size);
+ }
+
+ private static boolean selectFont(PCLGenerator gen, String name, int size) throws IOException {
+ int fontcode = 0;
+ if (name.length() > 1 && name.charAt(0) == 'F') {
+ try {
+ fontcode = Integer.parseInt(name.substring(1));
+ } catch (Exception e) {
+ log.error(e);
+ }
+ }
+ //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
+ String formattedSize = gen.formatDouble2(size / 1000.0);
+ switch (fontcode) {
+ case 1: // F1 = Helvetica
+ // gen.writeCommand("(8U");
+ // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
+ // Arial is more common among PCL5 printers than Helvetica - so use Arial
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
+ break;
+ case 2: // F2 = Helvetica Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
+ break;
+ case 3: // F3 = Helvetica Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
+ break;
+ case 4: // F4 = Helvetica Bold Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
+ break;
+ case 5: // F5 = Times Roman
+ // gen.writeCommand("(8U");
+ // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
+ // Times New is more common among PCL5 printers than Times - so use Times New
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
+ break;
+ case 6: // F6 = Times Italic
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
+ break;
+ case 7: // F7 = Times Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
+ break;
+ case 8: // F8 = Times Bold Italic
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
+ break;
+ case 9: // F9 = Courier
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h0s0b4099T");
+ break;
+ case 10: // F10 = Courier Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h1s0b4099T");
+ break;
+ case 11: // F11 = Courier Bold
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h0s3b4099T");
+ break;
+ case 12: // F12 = Courier Bold Oblique
+
+ gen.writeCommand("(0N");
+ gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
+ + "h1s3b4099T");
+ break;
+ case 13: // F13 = Symbol
+
+ 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;
+ case 14: // F14 = Zapf Dingbats
+
+ return false;
+ //gen.writeCommand("(14L");
+ //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
+ //break;
+ default:
+ //gen.writeCommand("(0N");
+ //gen.writeCommand("(s" + formattedSize + "V");
+ return false;
+ }
+ return true;
+ }
+
+}
/** {@inheritDoc} */
public IFDocumentHandlerConfigurator getConfigurator() {
- return null; //No configurator, yet.
+ return new PCLRendererConfigurator(getUserAgent());
}
PCLRenderingUtil getPCLUtil() {
/** {@inheritDoc} */
public IFDocumentHandlerConfigurator getConfigurator(FOUserAgent userAgent) {
- return null;
+ return new PCLRendererConfigurator(userAgent);
}
}
* @return true if it's a grayscale image
*/
public static boolean isGrayscaleImage(RenderedImage img) {
- return (img.getColorModel().getColorSpace().getNumComponents() == 1);
+ return (img.getColorModel().getNumColorComponents() == 1);
}
private MonochromeBitmapConverter createMonochromeBitmapConverter() {
Dimension orgDim = new Dimension(img.getWidth(), img.getHeight());
Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution);
boolean scaled = !orgDim.equals(effDim);
+ //ImageWriterUtil.saveAsPNG(img, new java.io.File("D:/text-0-org.png"));
boolean monochrome = isMonochromeImage(img);
if (!monochrome) {
if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) {
src = new BufferedImage(effDim.width, effDim.height,
BufferedImage.TYPE_BYTE_GRAY);
+ Graphics2D g2d = src.createGraphics();
+ try {
+ clearBackground(g2d, effDim);
+ } finally {
+ g2d.dispose();
+ }
ColorConvertOp op = new ColorConvertOp(
ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
op.filter((BufferedImage)img, src);
BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2d = src.createGraphics();
try {
+ clearBackground(g2d, effDim);
+
AffineTransform at = new AffineTransform();
double sx = effDim.getWidth() / orgDim.getWidth();
double sy = effDim.getHeight() / orgDim.getHeight();
}
}
+ private void clearBackground(Graphics2D g2d, Dimension effDim) {
+ //white background
+ g2d.setBackground(Color.WHITE);
+ g2d.clearRect(0, 0, effDim.width, effDim.height);
+ }
+
/**
* Paint a bitmap at the current cursor position. The bitmap must be a monochrome
* (1-bit) bitmap image.
--- /dev/null
+/*
+ * 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.awt.Dimension;
+import java.awt.Rectangle;
+import java.awt.geom.Point2D;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+
+import org.apache.xmlgraphics.image.loader.Image;
+import org.apache.xmlgraphics.image.loader.ImageFlavor;
+import org.apache.xmlgraphics.image.loader.impl.ImageRendered;
+
+import org.apache.fop.render.ImageHandler;
+import org.apache.fop.render.RenderingContext;
+
+/**
+ * Image handler implementation that paints {@code RenderedImage} instances in PCL.
+ */
+public class PCLImageHandlerRenderedImage implements ImageHandler {
+
+ /** {@inheritDoc} */
+ public int getPriority() {
+ return 300;
+ }
+
+ /** {@inheritDoc} */
+ public Class getSupportedImageClass() {
+ return ImageRendered.class;
+ }
+
+ /** {@inheritDoc} */
+ public ImageFlavor[] getSupportedImageFlavors() {
+ return new ImageFlavor[] {
+ ImageFlavor.BUFFERED_IMAGE,
+ ImageFlavor.RENDERED_IMAGE,
+ };
+ }
+
+ /** {@inheritDoc} */
+ public void handleImage(RenderingContext context, Image image, Rectangle pos)
+ throws IOException {
+ PCLRenderingContext pclContext = (PCLRenderingContext)context;
+ ImageRendered imageRend = (ImageRendered)image;
+ PCLGenerator gen = pclContext.getPCLGenerator();
+
+ RenderedImage ri = imageRend.getRenderedImage();
+ Point2D transPoint = pclContext.transformedPoint(pos.x, pos.y);
+ gen.setCursorPos(transPoint.getX(), transPoint.getY());
+ gen.paintBitmap(ri, new Dimension(pos.width, pos.height),
+ pclContext.isSourceTransparencyEnabled());
+ }
+
+ /** {@inheritDoc} */
+ public boolean isCompatible(RenderingContext targetContext, Image image) {
+ return (image == null || image instanceof ImageRendered)
+ && targetContext instanceof PCLRenderingContext;
+ }
+
+}
import java.awt.Color;
import java.awt.Dimension;
+import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Map;
import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageProcessingHints;
+import org.apache.xmlgraphics.image.loader.ImageSize;
+import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D;
import org.apache.xmlgraphics.java2d.GraphicContext;
+import org.apache.xmlgraphics.java2d.Graphics2DImagePainter;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.fonts.Font;
import org.apache.fop.fonts.FontTriplet;
-import org.apache.fop.pdf.PDFXObject;
import org.apache.fop.render.RenderingContext;
import org.apache.fop.render.intermediate.AbstractIFPainter;
import org.apache.fop.render.intermediate.IFException;
import org.apache.fop.render.intermediate.IFState;
+import org.apache.fop.render.java2d.FontMetricsMapper;
+import org.apache.fop.render.java2d.Java2DPainter;
import org.apache.fop.traits.BorderProps;
import org.apache.fop.traits.RuleStyle;
import org.apache.fop.util.CharUtilities;
-import org.apache.fop.util.UnitConv;
/**
* {@code IFPainter} implementation that produces PCL 5.
/** logging instance */
private static Log log = LogFactory.getLog(PCLPainter.class);
- private PCLDocumentHandler parent;
+ private final boolean DEBUG = false;
- /** Holds the intermediate format state */
- protected IFState state;
+ private PCLDocumentHandler parent;
/** The PCL generator */
private PCLGenerator gen;
/** {@inheritDoc} */
public void drawImage(String uri, Rectangle rect, Map foreignAttributes) throws IFException {
- /*
- PDFXObject xobject = pdfDoc.getXObject(uri);
- if (xobject != null) {
- placeImage(rect, xobject);
- return;
- }
-
- drawImageUsingURI(uri, rect);
-
- flushPDFDoc();
- */
+ drawImageUsingURI(uri, rect/*, foreignAttributes*/);
}
/** {@inheritDoc} */
protected RenderingContext createRenderingContext() {
- /*
PCLRenderingContext pdfContext = new PCLRenderingContext(
- getUserAgent(), generator, currentPage, getFontInfo());
- return pdfContext;
- */
- return null;
- }
+ getUserAgent(), this.gen, getPCLUtil()) {
- /**
- * Places a previously registered image at a certain place on the page.
- * @param x X coordinate
- * @param y Y coordinate
- * @param w width for image
- * @param h height for image
- * @param xobj the image XObject
- */
- private void placeImage(Rectangle rect, PDFXObject xobj) {
- /*
- generator.saveGraphicsState();
- generator.add(format(rect.width) + " 0 0 "
- + format(-rect.height) + " "
- + format(rect.x) + " "
- + format(rect.y + rect.height )
- + " cm " + xobj.getName() + " Do\n");
- generator.restoreGraphicsState();
- */
+ public Point2D transformedPoint(int x, int y) {
+ return PCLPainter.this.transformedPoint(x, y);
+ }
+
+ };
+ return pdfContext;
}
/** {@inheritDoc} */
public void drawImage(Document doc, Rectangle rect, Map foreignAttributes) throws IFException {
- /*
drawImageUsingDocument(doc, rect);
-
- flushPDFDoc();
- */
}
/** {@inheritDoc} */
String fontKey = parent.getFontInfo().getInternalFontKey(triplet);
boolean pclFont = getPCLUtil().isAllTextAsBitmaps()
? false
- : setFont(fontKey, state.getFontSize(), text);
- if (true || pclFont) {
+ : HardcodedFonts.setFont(gen, fontKey, state.getFontSize(), text);
+ if (pclFont) {
drawTextNative(x, y, dx, text, triplet);
} else {
drawTextAsBitmap(x, y, dx, dy, text, triplet);
+ if (DEBUG) {
+ state.setTextColor(Color.GRAY);
+ HardcodedFonts.setFont(gen, "F1", state.getFontSize(), text);
+ drawTextNative(x, y, dx, text, triplet);
+ }
}
} catch (IOException ioe) {
throw new IFException("I/O error in drawText()", ioe);
+ } catch (ImageException ime) {
+ throw new IFException("Image processing error in drawText()", ime);
}
}
}
- private void drawTextAsBitmap(int x, int y, int[] dx, int[] dy,
- String text, FontTriplet triplet) throws IOException {
- /*
+ private static final double SAFETY_MARGIN_FACTOR = 0.05;
+
+ private Rectangle getTextBoundingRect(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
+ int safetyMargin = (int)(SAFETY_MARGIN_FACTOR * font.getFontSize());
+ Rectangle boundingRect = new Rectangle(
+ x, y - maxAscent - safetyMargin,
+ 0, maxAscent - descent + 2 * safetyMargin);
+
+ int l = text.length();
+ int dxl = (dx != null ? dx.length : 0);
+
+ if (dx != null && dxl > 0 && dx[0] != 0) {
+ boundingRect.setLocation(boundingRect.x - (int)Math.ceil(dx[0] / 10f), boundingRect.y);
+ }
+ float width = 0.0f;
+ for (int i = 0; i < l; i++) {
+ char orgChar = text.charAt(i);
+ float glyphAdjust = 0;
+ int cw = font.getCharWidth(orgChar);
+
+ if (dx != null && i < dxl - 1) {
+ glyphAdjust += dx[i + 1];
+ }
+
+ width += cw - glyphAdjust;
+ }
+ int extraWidth = font.getFontSize() / 3;
+ boundingRect.setSize(
+ (int)Math.ceil(width) + extraWidth,
+ boundingRect.height);
+ return boundingRect;
+ }
+
+ private void drawTextAsBitmap(final int x, final int y, final int[] dx, final int[] dy,
+ final String text, FontTriplet triplet) throws IOException, ImageException {
//Use Java2D to paint different fonts via bitmap
- final Font font = getFontFromArea(text);
- final int baseline = text.getBaselineOffset();
+ 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
- int extraWidth = font.getFontSize() / 3;
- final FontMetricsMapper mapper = (FontMetricsMapper)fontInfo.getMetricsFor(
+ final FontMetricsMapper mapper = (FontMetricsMapper)parent.getFontInfo().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() - additionalBPD,
- text.getIPD() + extraWidth, text.getBPD() + additionalBPD);
- RendererContext rc = createRendererContext(paintRect.x, paintRect.y,
- paintRect.width, paintRect.height, null);
+ final int maxAscent = mapper.getMaxAscent(font.getFontSize()) / 1000;
+ final int ascent = mapper.getAscender(font.getFontSize()) / 1000;
+ final int descent = mapper.getDescender(font.getFontSize()) / 1000;
+ int safetyMargin = (int)(SAFETY_MARGIN_FACTOR * font.getFontSize());
+ final int baselineOffset = maxAscent + safetyMargin;
+
+ final Rectangle boundingRect = getTextBoundingRect(x, y, dx, dy, text, font, mapper);
+
Map atts = new java.util.HashMap();
atts.put(CONV_MODE, "bitmap");
atts.put(SRC_TRANSPARENCY, "true");
- rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+ //rc.setProperty(RendererContextConstants.FOREIGN_ATTRIBUTES, atts);
+ final Dimension dim = boundingRect.getSize();
Graphics2DImagePainter painter = new Graphics2DImagePainter() {
public void paint(Graphics2D g2d, Rectangle2D area) {
- g2d.setFont(mapper.getFont(font.getFontSize()));
- g2d.translate(0, baseline + additionalBPD);
- g2d.scale(1000, 1000);
- g2d.setColor(col);
- Java2DRenderer.renderText(text, g2d, font);
- renderTextDecoration(g2d, mapper, fontsize, text, 0, 0);
+ if (DEBUG) {
+ g2d.setBackground(Color.LIGHT_GRAY);
+ g2d.clearRect(0, 0, (int)area.getWidth(), (int)area.getHeight());
+ }
+ g2d.translate(0, -y + baselineOffset);
+
+ if (DEBUG) {
+ Rectangle rect = new Rectangle(x, y - maxAscent, 3000, maxAscent);
+ g2d.draw(rect);
+ rect = new Rectangle(x, y - ascent, 2000, ascent);
+ g2d.draw(rect);
+ rect = new Rectangle(x, y, 1000, - descent);
+ g2d.draw(rect);
+ }
+ Java2DPainter painter = new Java2DPainter(g2d,
+ getUserAgent(), parent.getFontInfo(), state);
+ try {
+ painter.drawText(x, y, dx, dy, text);
+ } catch (IFException e) {
+ //This should never happen with the Java2DPainter
+ throw new RuntimeException("Unexpected error while painting text", e);
+ }
}
public Dimension getImageSize() {
- return paintRect.getSize();
+ return dim.getSize();
}
};
- g2a.paintImage(painter, rc,
- paintRect.x, paintRect.y, paintRect.width, paintRect.height);
- currentIPPosition = saveIP + text.getAllocIPD();
- */
+ 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);
}
- /** {@inheritDoc} */
- public void setFont(String family, String style, Integer weight, String variant, Integer size,
- Color color) throws IFException {
- if (family != null) {
- state.setFontFamily(family);
- }
- if (style != null) {
- state.setFontStyle(style);
- }
- if (weight != null) {
- state.setFontWeight(weight.intValue());
- }
- if (variant != null) {
- state.setFontVariant(variant);
- }
- if (size != null) {
- state.setFontSize(size.intValue());
- }
- if (color != null) {
- state.setTextColor(color);
- }
- }
-
- //----------------------------------------------------------------------------------------------
-
/** Saves the current graphics state on the stack. */
private void saveGraphicsState() {
graphicContextStack.push(graphicContext);
}
private Point2D transformedPoint(int x, int y) {
- AffineTransform at = graphicContext.getTransform();
- if (log.isTraceEnabled()) {
- log.trace("Current transform: " + at);
- }
- Point2D.Float orgPoint = new Point2D.Float(x, y);
- Point2D.Float transPoint = new Point2D.Float();
- at.transform(orgPoint, transPoint);
- //At this point we have the absolute position in FOP's coordinate system
-
- //Now get PCL coordinates taking the current print direction and the logical page
- //into account.
- Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
- Rectangle logRect = currentPageDefinition.getLogicalPageRect();
- switch (currentPrintDirection) {
- case 0:
- transPoint.x -= logRect.x;
- transPoint.y -= logRect.y;
- break;
- case 90:
- float ty = transPoint.x;
- transPoint.x = pageSize.height - transPoint.y;
- transPoint.y = ty;
- transPoint.x -= logRect.y;
- transPoint.y -= logRect.x;
- break;
- case 180:
- transPoint.x = pageSize.width - transPoint.x;
- transPoint.y = pageSize.height - transPoint.y;
- transPoint.x -= pageSize.width - logRect.x - logRect.width;
- transPoint.y -= pageSize.height - logRect.y - logRect.height;
- //The next line is odd and is probably necessary due to the default value of the
- //Text Length command: "1/2 inch less than maximum text length"
- //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
- transPoint.y -= UnitConv.in2mpt(0.5);
- break;
- case 270:
- float tx = transPoint.y;
- transPoint.y = pageSize.width - transPoint.x;
- transPoint.x = tx;
- transPoint.x -= pageSize.height - logRect.y - logRect.height;
- transPoint.y -= pageSize.width - logRect.x - logRect.width;
- break;
- default:
- throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
- }
- return transPoint;
+ return PCLRenderingUtil.transformedPoint(x, y, graphicContext.getTransform(),
+ currentPageDefinition, currentPrintDirection);
}
private void changePrintDirection() throws IOException {
gen.setCursorPos(transPoint.getX(), transPoint.getY());
}
- /**
- * 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 (in millipoints)
- * @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, int 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 {
- fontcode = Integer.parseInt(name.substring(1));
- } catch (Exception e) {
- log.error(e);
- }
- }
- //Note "(ON" selects ISO 8859-1 symbol set as used by PCLGenerator
- String formattedSize = gen.formatDouble2(size / 1000.0);
- switch (fontcode) {
- case 1: // F1 = Helvetica
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
- // Arial is more common among PCL5 printers than Helvetica - so use Arial
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
- break;
- case 2: // F2 = Helvetica Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
- break;
- case 3: // F3 = Helvetica Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
- break;
- case 4: // F4 = Helvetica Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
- break;
- case 5: // F5 = Times Roman
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
- // Times New is more common among PCL5 printers than Times - so use Times New
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
- break;
- case 6: // F6 = Times Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
- break;
- case 7: // F7 = Times Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
- break;
- case 8: // F8 = Times Bold Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
- break;
- case 9: // F9 = Courier
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s0b4099T");
- break;
- case 10: // F10 = Courier Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s0b4099T");
- break;
- case 11: // F11 = Courier Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s3b4099T");
- break;
- case 12: // F12 = Courier Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s3b4099T");
- break;
- case 13: // F13 = Symbol
-
- 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;
- case 14: // F14 = Zapf Dingbats
-
- return false;
- //gen.writeCommand("(14L");
- //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
- //break;
- default:
- //gen.writeCommand("(0N");
- //gen.writeCommand("(s" + formattedSize + "V");
- return false;
- }
- return true;
- }
-
}
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
-import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.xmlgraphics.util.UnitConv;
import org.apache.fop.apps.FOPException;
+import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.MimeConstants;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.render.java2d.ConfiguredFontCollection;
import org.apache.fop.render.java2d.FontMetricsMapper;
import org.apache.fop.render.java2d.InstalledFontCollection;
+import org.apache.fop.render.java2d.Java2DFontMetrics;
import org.apache.fop.render.java2d.Java2DRenderer;
import org.apache.fop.render.pcl.extensions.PCLElementMapping;
import org.apache.fop.traits.BorderProps;
private java.awt.Color currentFillColor = null;
/**
- * Controls whether appearance is more important than speed. False can cause some FO feature
- * to be ignored (like the advanced borders).
+ * Utility class which enables all sorts of features that are not directly connected to the
+ * normal rendering process.
*/
- 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;
-
- /**
- * Controls whether an RGB canvas is used when converting Java2D graphics to bitmaps.
- * This can be used to work around problems with Apache Batik, for example, but setting
- * this to true will increase memory consumption.
- */
- private final boolean useColorCanvas = false;
-
- /**
- * Controls whether the generation of PJL commands gets disabled.
- */
- private boolean disabledPJL = false;
+ private PCLRenderingUtil pclUtil;
/** contains the pageWith of the last printed page */
private long pageWidth = 0;
public PCLRenderer() {
}
+ /** {@inheritDoc} */
+ public void setUserAgent(FOUserAgent agent) {
+ super.setUserAgent(agent);
+ this.pclUtil = new PCLRenderingUtil(getUserAgent());
+ }
+
+ PCLRenderingUtil getPCLUtil() {
+ return this.pclUtil;
+ }
+
/**
* 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
*/
public void setQualityBeforeSpeed(boolean qualityBeforeSpeed) {
- this.qualityBeforeSpeed = qualityBeforeSpeed;
+ pclUtil.setQualityBeforeSpeed(qualityBeforeSpeed);
}
/**
* @param disable true to disable PJL commands
*/
public void setPJLDisabled(boolean disable) {
- this.disabledPJL = disable;
+ pclUtil.setPJLDisabled(disable);
}
/**
* @return true if PJL generation is disabled.
*/
public boolean isPJLDisabled() {
- return this.disabledPJL;
+ return pclUtil.isPJLDisabled();
+ }
+
+ /**
+ * Controls whether all text should be generated as bitmaps or only text for which there's
+ * no native font.
+ * @param allTextAsBitmaps true if all text should be painted as bitmaps
+ */
+ public void setAllTextAsBitmaps(boolean allTextAsBitmaps) {
+ pclUtil.setAllTextAsBitmaps(allTextAsBitmaps);
}
/**
//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 graphics2D = fontImage.createGraphics();
- //The next line is important to get accurate font metrics!
- graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
- RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D();
FontCollection[] fontCollections = new FontCollection[] {
new Base14FontCollection(graphics2D),
}
}
- /**
- * 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, 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 {
- fontcode = Integer.parseInt(name.substring(1));
- } catch (Exception e) {
- 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
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b24580T");
- // Arial is more common among PCL5 printers than Helvetica - so use Arial
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16602T");
- break;
- case 2: // F2 = Helvetica Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16602T");
- break;
- case 3: // F3 = Helvetica Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16602T");
- break;
- case 4: // F4 = Helvetica Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16602T");
- break;
- case 5: // F5 = Times Roman
- // gen.writeCommand("(8U");
- // gen.writeCommand("(s1p" + formattedSize + "v0s0b25093T");
- // Times New is more common among PCL5 printers than Times - so use Times New
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s0b16901T");
- break;
- case 6: // F6 = Times Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s0b16901T");
- break;
- case 7: // F7 = Times Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v0s3b16901T");
- break;
- case 8: // F8 = Times Bold Italic
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s1p" + formattedSize + "v1s3b16901T");
- break;
- case 9: // F9 = Courier
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s0b4099T");
- break;
- case 10: // F10 = Courier Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s0b4099T");
- break;
- case 11: // F11 = Courier Bold
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h0s3b4099T");
- break;
- case 12: // F12 = Courier Bold Oblique
-
- gen.writeCommand("(0N");
- gen.writeCommand("(s0p" + gen.formatDouble2(120.01f / (size / 1000.00f))
- + "h1s3b4099T");
- break;
- case 13: // F13 = Symbol
-
- 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;
- case 14: // F14 = Zapf Dingbats
-
- return false;
- //gen.writeCommand("(14L");
- //gen.writeCommand("(s1p" + formattedSize + "v0s0b45101T");
- //break;
- default:
- //gen.writeCommand("(0N");
- //gen.writeCommand("(s" + formattedSize + "V");
- return false;
- }
- return true;
- }
-
/** {@inheritDoc} */
public void startRenderer(OutputStream outputStream) throws IOException {
log.debug("Rendering areas to PCL...");
}
private Point2D transformedPoint(int x, int y) {
- AffineTransform at = graphicContext.getTransform();
- if (log.isTraceEnabled()) {
- log.trace("Current transform: " + at);
- }
- Point2D.Float orgPoint = new Point2D.Float(x, y);
- Point2D.Float transPoint = new Point2D.Float();
- at.transform(orgPoint, transPoint);
- //At this point we have the absolute position in FOP's coordinate system
-
- //Now get PCL coordinates taking the current print direction and the logical page
- //into account.
- Dimension pageSize = currentPageDefinition.getPhysicalPageSize();
- Rectangle logRect = currentPageDefinition.getLogicalPageRect();
- switch (currentPrintDirection) {
- case 0:
- transPoint.x -= logRect.x;
- transPoint.y -= logRect.y;
- break;
- case 90:
- float ty = transPoint.x;
- transPoint.x = pageSize.height - transPoint.y;
- transPoint.y = ty;
- transPoint.x -= logRect.y;
- transPoint.y -= logRect.x;
- break;
- case 180:
- transPoint.x = pageSize.width - transPoint.x;
- transPoint.y = pageSize.height - transPoint.y;
- transPoint.x -= pageSize.width - logRect.x - logRect.width;
- transPoint.y -= pageSize.height - logRect.y - logRect.height;
- //The next line is odd and is probably necessary due to the default value of the
- //Text Length command: "1/2 inch less than maximum text length"
- //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
- transPoint.y -= UnitConv.in2mpt(0.5);
- break;
- case 270:
- float tx = transPoint.y;
- transPoint.y = pageSize.width - transPoint.x;
- transPoint.x = tx;
- transPoint.x -= pageSize.height - logRect.y - logRect.height;
- transPoint.y -= pageSize.width - logRect.x - logRect.width;
- break;
- default:
- throw new IllegalStateException("Illegal print direction: " + currentPrintDirection);
- }
- return transPoint;
+ return PCLRenderingUtil.transformedPoint(x, y, graphicContext.getTransform(),
+ currentPageDefinition, currentPrintDirection);
}
private void changePrintDirection() {
try {
final Color col = (Color)text.getTrait(Trait.COLOR);
- boolean pclFont = allTextAsBitmaps
+ boolean pclFont = pclUtil.isAllTextAsBitmaps()
? false
- : setFont(fontname, fontsize, text.getText());
+ : HardcodedFonts.setFont(gen, fontname, fontsize, text.getText());
if (pclFont) {
//this.currentFill = col;
if (col != null) {
RendererContext context = super.createRendererContext(
x, y, width, height, foreignAttributes);
context.setProperty(PCLRendererContextConstants.PCL_COLOR_CANVAS,
- Boolean.valueOf(this.useColorCanvas));
+ Boolean.valueOf(pclUtil.isColorCanvasEnabled()));
return context;
}
if (bpsBefore == null && bpsAfter == null && bpsStart == null && bpsEnd == null) {
return; //no borders to paint
}
- if (qualityBeforeSpeed) {
+ if (pclUtil.isQualityBeforeSpeed()) {
drawQualityBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
} else {
drawFastBorders(borderRect, bpsBefore, bpsAfter, bpsStart, bpsEnd);
super.renderLeader(area);
}
- /**
- * Controls whether all text should be generated as bitmaps or only text for which there's
- * no native font.
- * @param allTextAsBitmaps true if all text should be painted as bitmaps
- */
- public void setAllTextAsBitmaps(boolean allTextAsBitmaps) {
- this.allTextAsBitmaps = allTextAsBitmaps;
- }
-
-
-
}
package org.apache.fop.render.pcl;
+import java.awt.Graphics2D;
+import java.util.List;
+
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.fonts.FontCollection;
+import org.apache.fop.fonts.FontEventAdapter;
+import org.apache.fop.fonts.FontEventListener;
+import org.apache.fop.fonts.FontInfo;
+import org.apache.fop.fonts.FontManager;
+import org.apache.fop.fonts.FontResolver;
+import org.apache.fop.render.DefaultFontResolver;
import org.apache.fop.render.PrintRendererConfigurator;
import org.apache.fop.render.Renderer;
+import org.apache.fop.render.intermediate.IFDocumentHandler;
+import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator;
+import org.apache.fop.render.java2d.Base14FontCollection;
+import org.apache.fop.render.java2d.ConfiguredFontCollection;
+import org.apache.fop.render.java2d.InstalledFontCollection;
+import org.apache.fop.render.java2d.Java2DFontMetrics;
/**
* PCL Renderer configurator
*/
-public class PCLRendererConfigurator extends PrintRendererConfigurator {
+public class PCLRendererConfigurator extends PrintRendererConfigurator
+ implements IFDocumentHandlerConfigurator {
/**
* Default constructor
if (cfg != null) {
PCLRenderer pclRenderer = (PCLRenderer)renderer;
- String rendering = cfg.getChild("rendering").getValue(null);
- if ("quality".equalsIgnoreCase(rendering)) {
- pclRenderer.setQualityBeforeSpeed(true);
- } else if ("speed".equalsIgnoreCase(rendering)) {
- pclRenderer.setQualityBeforeSpeed(false);
- } else if (rendering != null) {
- throw new FOPException(
- "Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
- + rendering);
- }
-
- String textRendering = cfg.getChild("text-rendering").getValue(null);
- if ("bitmap".equalsIgnoreCase(textRendering)) {
- pclRenderer.setAllTextAsBitmaps(true);
- } else if ("auto".equalsIgnoreCase(textRendering)) {
- pclRenderer.setAllTextAsBitmaps(false);
- } else if (textRendering != null) {
- throw new FOPException(
- "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: "
- + textRendering);
- }
-
- pclRenderer.setPJLDisabled(cfg.getChild("disable-pjl").getValueAsBoolean(false));
+ PCLRenderingUtil pclUtil = pclRenderer.getPCLUtil();
+ configure(cfg, pclUtil);
}
super.configure(renderer);
}
+
+ 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) {
+ throw new FOPException(
+ "Valid values for 'rendering' are 'quality' and 'speed'. Value found: "
+ + rendering);
+ }
+
+ String textRendering = cfg.getChild("text-rendering").getValue(null);
+ if ("bitmap".equalsIgnoreCase(textRendering)) {
+ pclUtil.setAllTextAsBitmaps(true);
+ } else if ("auto".equalsIgnoreCase(textRendering)) {
+ pclUtil.setAllTextAsBitmaps(false);
+ } else if (textRendering != null) {
+ throw new FOPException(
+ "Valid values for 'text-rendering' are 'auto' and 'bitmap'. Value found: "
+ + textRendering);
+ }
+
+ pclUtil.setPJLDisabled(cfg.getChild("disable-pjl").getValueAsBoolean(false));
+ }
+
+ // ---=== IFDocumentHandler configuration ===---
+
+ /** {@inheritDoc} */
+ public void configure(IFDocumentHandler documentHandler) throws FOPException {
+ Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
+ if (cfg != null) {
+ PCLDocumentHandler pclDocumentHandler = (PCLDocumentHandler)documentHandler;
+ PCLRenderingUtil pclUtil = pclDocumentHandler.getPCLUtil();
+ configure(cfg, pclUtil);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void setupFontInfo(IFDocumentHandler documentHandler, FontInfo fontInfo)
+ throws FOPException {
+ FontManager fontManager = userAgent.getFactory().getFontManager();
+
+ Graphics2D graphics2D = Java2DFontMetrics.createFontMetricsGraphics2D();
+
+ List fontCollections = new java.util.ArrayList();
+ fontCollections.add(new Base14FontCollection(graphics2D));
+ fontCollections.add(new InstalledFontCollection(graphics2D));
+
+ Configuration cfg = super.getRendererConfig(documentHandler.getMimeType());
+ if (cfg != null) {
+ FontResolver fontResolver = new DefaultFontResolver(userAgent);
+ FontEventListener listener = new FontEventAdapter(
+ userAgent.getEventBroadcaster());
+ List fontList = buildFontList(cfg, fontResolver, listener);
+ fontCollections.add(new ConfiguredFontCollection(fontResolver, fontList));
+ }
+
+ fontManager.setup(fontInfo,
+ (FontCollection[])fontCollections.toArray(
+ new FontCollection[fontCollections.size()]));
+ documentHandler.setFontInfo(fontInfo);
+ }
+
+
}
--- /dev/null
+/*
+ * 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.awt.geom.Point2D;
+
+import org.apache.xmlgraphics.util.MimeConstants;
+
+import org.apache.fop.apps.FOUserAgent;
+import org.apache.fop.render.AbstractRenderingContext;
+
+/**
+ * Rendering context for PCL production. The class is abstract and must be subclassed to
+ * provide the missing functionality.
+ */
+public abstract class PCLRenderingContext extends AbstractRenderingContext {
+
+ private PCLGenerator generator;
+ private PCLRenderingUtil pclUtil;
+ private boolean sourceTransparency = false;
+
+ /**
+ * Main constructor.
+ * @param userAgent the user agent
+ * @param generator the PCL generator
+ */
+ public PCLRenderingContext(FOUserAgent userAgent,
+ PCLGenerator generator, PCLRenderingUtil pclUtil) {
+ super(userAgent);
+ this.generator = generator;
+ this.pclUtil = pclUtil;
+ }
+
+ /** {@inheritDoc} */
+ public String getMimeType() {
+ return MimeConstants.MIME_PCL; //not applicable
+ }
+
+ /**
+ * Returns the PCL generator.
+ * @return the PCL generator
+ */
+ public PCLGenerator getPCLGenerator() {
+ return this.generator;
+ }
+
+ /**
+ * Returns the PCL rendering utility.
+ * @return the PCL rendering utility.
+ */
+ public PCLRenderingUtil getPCLUtil() {
+ return this.pclUtil;
+ }
+
+ /**
+ * Indicates whether source transparency should be enabled when painting bitmaps.
+ * @return true when source transparency is enabled
+ */
+ public boolean isSourceTransparencyEnabled() {
+ return this.sourceTransparency;
+ }
+
+ /**
+ * Enables or disables source transparency when painting bitmaps.
+ * @param value true to enable source transparency, false to disable
+ */
+ public void setSourceTransparencyEnabled(boolean value) {
+ this.sourceTransparency = value;
+ }
+
+ /**
+ * Transforms a point into the PCL coordinate system.
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @return the transformed point in PCL coordinates
+ */
+ public abstract Point2D transformedPoint(int x, int y);
+
+}
package org.apache.fop.render.pcl;
+import java.awt.Dimension;
+import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.xmlgraphics.util.UnitConv;
+
import org.apache.fop.apps.FOUserAgent;
/**
initialize();
}
- private static boolean booleanValueOf(Object obj) {
- if (obj instanceof Boolean) {
- return ((Boolean)obj).booleanValue();
- } else if (obj instanceof String) {
- return Boolean.valueOf((String)obj).booleanValue();
- } else {
- throw new IllegalArgumentException("Boolean or \"true\" or \"false\" expected.");
- }
- }
-
private void initialize() {
}
this.qualityBeforeSpeed = qualityBeforeSpeed;
}
+ /**
+ * Indicates whether quality is more important than speed.
+ * @return true if quality is favored over speed
+ */
+ public boolean isQualityBeforeSpeed() {
+ return this.qualityBeforeSpeed;
+ }
+
/**
* Controls whether PJL commands shall be generated by the PCL renderer.
* @param disable true to disable PJL commands
return this.disabledPJL;
}
+ /**
+ * Controls whether all text should be generated as bitmaps or only text for which there's
+ * no native font.
+ * @param allTextAsBitmaps true if all text should be painted as bitmaps
+ */
+ public void setAllTextAsBitmaps(boolean allTextAsBitmaps) {
+ this.allTextAsBitmaps = allTextAsBitmaps;
+ }
+
/**
* Indicates whether all text shall be painted as bitmaps.
* @return true if all text shall be painted as bitmaps
return this.allTextAsBitmaps;
}
+ /**
+ * Indicates whether a color canvas is used when creating bitmap images.
+ * @return true if a color canvas is used.
+ */
+ public boolean isColorCanvasEnabled() {
+ return this.useColorCanvas;
+ }
+
/**
* Determines the print direction based on the given transformation matrix. This method
* only detects right angles (0, 90, 180, 270). If any other angle is determined, 0 is
return newDir;
}
+ /**
+ * Returns a coordinate in PCL's coordinate system when given a coordinate in the user
+ * coordinate system.
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ * @param transform the currently valid transformation matrix
+ * @param pageDefinition the currently valid page definition
+ * @param printDirection the currently valid print direction
+ * @return the transformed point
+ */
+ public static Point2D transformedPoint(int x, int y, AffineTransform transform,
+ PCLPageDefinition pageDefinition, int printDirection) {
+ if (log.isTraceEnabled()) {
+ log.trace("Current transform: " + transform);
+ }
+ Point2D.Float orgPoint = new Point2D.Float(x, y);
+ Point2D.Float transPoint = new Point2D.Float();
+ transform.transform(orgPoint, transPoint);
+ //At this point we have the absolute position in FOP's coordinate system
+
+ //Now get PCL coordinates taking the current print direction and the logical page
+ //into account.
+ Dimension pageSize = pageDefinition.getPhysicalPageSize();
+ Rectangle logRect = pageDefinition.getLogicalPageRect();
+ switch (printDirection) {
+ case 0:
+ transPoint.x -= logRect.x;
+ transPoint.y -= logRect.y;
+ break;
+ case 90:
+ float ty = transPoint.x;
+ transPoint.x = pageSize.height - transPoint.y;
+ transPoint.y = ty;
+ transPoint.x -= logRect.y;
+ transPoint.y -= logRect.x;
+ break;
+ case 180:
+ transPoint.x = pageSize.width - transPoint.x;
+ transPoint.y = pageSize.height - transPoint.y;
+ transPoint.x -= pageSize.width - logRect.x - logRect.width;
+ transPoint.y -= pageSize.height - logRect.y - logRect.height;
+ //The next line is odd and is probably necessary due to the default value of the
+ //Text Length command: "1/2 inch less than maximum text length"
+ //I wonder why this isn't necessary for the 90 degree rotation. *shrug*
+ transPoint.y -= UnitConv.in2mpt(0.5);
+ break;
+ case 270:
+ float tx = transPoint.y;
+ transPoint.y = pageSize.width - transPoint.x;
+ transPoint.x = tx;
+ transPoint.x -= pageSize.height - logRect.y - logRect.height;
+ transPoint.y -= pageSize.width - logRect.x - logRect.width;
+ break;
+ default:
+ throw new IllegalStateException("Illegal print direction: " + printDirection);
+ }
+ return transPoint;
+ }
}
private PDFDocumentHandler documentHandler;
- /** Holds the intermediate format state */
- protected IFState state;
-
/** The current content generator */
protected PDFContentGenerator generator;
textutil.writeTJ();
}
- /** {@inheritDoc} */
- public void setFont(String family, String style, Integer weight, String variant, Integer size,
- Color color) throws IFException {
- if (family != null) {
- state.setFontFamily(family);
- }
- if (style != null) {
- state.setFontStyle(style);
- }
- if (weight != null) {
- state.setFontWeight(weight.intValue());
- }
- if (variant != null) {
- state.setFontVariant(variant);
- }
- if (size != null) {
- state.setFontSize(size.intValue());
- }
- if (color != null) {
- state.setTextColor(color);
- }
- }
-
}
/** logging instance */
private static Log log = LogFactory.getLog(SVGPainter.class);
- /** Holds the intermediate format state */
- protected IFState state;
-
private AbstractSVGDocumentHandler parent;
/** The SAX content handler that receives the generated XML events. */
}
}
- /** {@inheritDoc} */
- public void setFont(String family, String style, Integer weight, String variant, Integer size,
- Color color) throws IFException {
- if (family != null) {
- state.setFontFamily(family);
- }
- if (style != null) {
- state.setFontStyle(style);
- }
- if (weight != null) {
- state.setFontWeight(weight.intValue());
- }
- if (variant != null) {
- state.setFontVariant(variant);
- }
- if (size != null) {
- state.setFontSize(size.intValue());
- }
- if (color != null) {
- state.setTextColor(color);
- }
- }
-
private void leaveTextMode() throws SAXException {
assert this.mode == MODE_TEXT;
handler.endElement("g");