diff options
Diffstat (limited to 'src/java/org/apache/fop/render')
8 files changed, 241 insertions, 10 deletions
diff --git a/src/java/org/apache/fop/render/AbstractRenderingContext.java b/src/java/org/apache/fop/render/AbstractRenderingContext.java index 7bacac58d..365fec871 100644 --- a/src/java/org/apache/fop/render/AbstractRenderingContext.java +++ b/src/java/org/apache/fop/render/AbstractRenderingContext.java @@ -19,6 +19,9 @@ package org.apache.fop.render; +import java.util.Collections; +import java.util.Map; + import org.apache.fop.apps.FOUserAgent; /** @@ -27,6 +30,7 @@ import org.apache.fop.apps.FOUserAgent; public abstract class AbstractRenderingContext implements RenderingContext { private FOUserAgent userAgent; + private Map hints; /** * Main constructor. @@ -45,5 +49,33 @@ public abstract class AbstractRenderingContext implements RenderingContext { return userAgent; } + /** {@inheritDoc} */ + public void putHints(Map hints) { + if (hints == null) { + return; + } + if (this.hints == null) { + this.hints = new java.util.HashMap(); + } + this.hints.putAll(hints); + } + + /** {@inheritDoc} */ + public Map getHints() { + if (this.hints == null) { + return Collections.EMPTY_MAP; + } else { + return Collections.unmodifiableMap(this.hints); + } + } + + /** {@inheritDoc} */ + public Object getHint(Object key) { + if (this.hints == null) { + return null; + } else { + return this.hints.get(key); + } + } } diff --git a/src/java/org/apache/fop/render/RendererContext.java b/src/java/org/apache/fop/render/RendererContext.java index e52588176..595bdd7c2 100644 --- a/src/java/org/apache/fop/render/RendererContext.java +++ b/src/java/org/apache/fop/render/RendererContext.java @@ -29,7 +29,7 @@ import org.apache.fop.apps.FOUserAgent; * so that external handlers can get information to be able to render to the * render target. */ -public class RendererContext implements RenderingContext { +public class RendererContext { private String mime; private AbstractRenderer renderer; diff --git a/src/java/org/apache/fop/render/RenderingContext.java b/src/java/org/apache/fop/render/RenderingContext.java index a6f958328..5122841b7 100644 --- a/src/java/org/apache/fop/render/RenderingContext.java +++ b/src/java/org/apache/fop/render/RenderingContext.java @@ -19,6 +19,8 @@ package org.apache.fop.render; +import java.util.Map; + import org.apache.fop.apps.FOUserAgent; /** @@ -40,4 +42,10 @@ public interface RenderingContext { */ FOUserAgent getUserAgent(); + void putHints(Map hints); + + Map getHints(); + + Object getHint(Object key); + } diff --git a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java index 8380e69cc..105a2a426 100644 --- a/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java +++ b/src/java/org/apache/fop/render/intermediate/AbstractIFPainter.java @@ -127,6 +127,7 @@ public abstract class AbstractIFPainter implements IFPainter { //Load and convert the image to a supported format RenderingContext context = createRenderingContext(); Map hints = createDefaultImageProcessingHints(sessionContext); + context.putHints(hints); org.apache.xmlgraphics.image.loader.Image img = manager.getImage( info, imageHandlerRegistry.getSupportedFlavors(context), hints, sessionContext); @@ -179,6 +180,7 @@ public abstract class AbstractIFPainter implements IFPainter { ImageHandlerRegistry imageHandlerRegistry = getFopFactory().getImageHandlerRegistry(); Image effImage; + context.putHints(additionalHints); if (convert) { Map hints = createDefaultImageProcessingHints(getUserAgent().getImageSessionContext()); if (additionalHints != null) { diff --git a/src/java/org/apache/fop/render/pcl/PCLGenerator.java b/src/java/org/apache/fop/render/pcl/PCLGenerator.java index 36d1fe079..67dcce1fb 100644 --- a/src/java/org/apache/fop/render/pcl/PCLGenerator.java +++ b/src/java/org/apache/fop/render/pcl/PCLGenerator.java @@ -22,12 +22,10 @@ package org.apache.fop.render.pcl; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; -import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ByteLookupTable; -import java.awt.image.ColorConvertOp; import java.awt.image.ColorModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; @@ -767,11 +765,20 @@ public class PCLGenerator { */ public void paintBitmap(RenderedImage img, Dimension targetDim, boolean sourceTransparency) throws IOException { - double targetResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width); + double targetHResolution = img.getWidth() / UnitConv.mpt2in(targetDim.width); + double targetVResolution = img.getHeight() / UnitConv.mpt2in(targetDim.height); + double targetResolution = Math.max(targetHResolution, targetVResolution); int resolution = (int)Math.round(targetResolution); int effResolution = calculatePCLResolution(resolution, true); Dimension orgDim = new Dimension(img.getWidth(), img.getHeight()); - Dimension effDim = getAdjustedDimension(orgDim, targetResolution, effResolution); + Dimension effDim; + if (targetResolution == effResolution) { + effDim = orgDim; //avoid scaling side-effects + } else { + effDim = new Dimension( + (int)Math.ceil(UnitConv.mpt2px(targetDim.width, effResolution)), + (int)Math.ceil(UnitConv.mpt2px(targetDim.height, effResolution))); + } boolean scaled = !orgDim.equals(effDim); //ImageWriterUtil.saveAsPNG(img, new java.io.File("D:/text-0-org.png")); @@ -791,6 +798,7 @@ public class PCLGenerator { BufferedImage src = null; if (img instanceof BufferedImage && !scaled) { if (!isGrayscaleImage(img) || img.getColorModel().hasAlpha()) { + /* Disabled as this doesn't work reliably, use the fallback below src = new BufferedImage(effDim.width, effDim.height, BufferedImage.TYPE_BYTE_GRAY); Graphics2D g2d = src.createGraphics(); @@ -802,6 +810,7 @@ public class PCLGenerator { ColorConvertOp op = new ColorConvertOp( ColorSpace.getInstance(ColorSpace.CS_GRAY), null); op.filter((BufferedImage)img, src); + */ } else { src = (BufferedImage)img; } @@ -1018,7 +1027,7 @@ public class PCLGenerator { } public void endLine() throws IOException { - if (zeroRow) { + if (zeroRow && PCLGenerator.this.currentSourceTransparency) { writeCommand("*b1Y"); } else if (rlewidth < bytewidth) { writeCommand("*b1m" + rlewidth + "W"); diff --git a/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java new file mode 100644 index 000000000..c24dfd7dc --- /dev/null +++ b/src/java/org/apache/fop/render/pcl/PCLImageHandlerGraphics2D.java @@ -0,0 +1,157 @@ +/* + * 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.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.IOException; + +import org.apache.commons.io.output.ByteArrayOutputStream; +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.ImageFlavor; +import org.apache.xmlgraphics.image.loader.ImageManager; +import org.apache.xmlgraphics.image.loader.impl.ImageGraphics2D; +import org.apache.xmlgraphics.image.loader.impl.ImageRendered; +import org.apache.xmlgraphics.java2d.GraphicContext; +import org.apache.xmlgraphics.util.UnitConv; + +import org.apache.fop.apps.FOUserAgent; +import org.apache.fop.render.ImageHandler; +import org.apache.fop.render.RenderingContext; + +/** + * Image handler implementation that paints Graphics2D images in PCL. Since PCL is limited in its + * vector graphics capabilities, there's a fallback built in that switches to bitmap painting + * if an advanced feature is encountered. + */ +public class PCLImageHandlerGraphics2D implements ImageHandler { + + /** logging instance */ + private static Log log = LogFactory.getLog(PCLImageHandlerGraphics2D.class); + + /** {@inheritDoc} */ + public int getPriority() { + return 400; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageGraphics2D.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return new ImageFlavor[] { + ImageFlavor.GRAPHICS2D + }; + } + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) + throws IOException { + PCLRenderingContext pclContext = (PCLRenderingContext)context; + ImageGraphics2D imageG2D = (ImageGraphics2D)image; + Dimension imageDim = imageG2D.getSize().getDimensionMpt(); + PCLGenerator gen = pclContext.getPCLGenerator(); + + Point2D transPoint = pclContext.transformedPoint(pos.x, pos.y); + gen.setCursorPos(transPoint.getX(), transPoint.getY()); + + boolean painted = false; + ByteArrayOutputStream baout = new ByteArrayOutputStream(); + PCLGenerator tempGen = new PCLGenerator(baout, gen.getMaximumBitmapResolution()); + try { + GraphicContext ctx = (GraphicContext)pclContext.getGraphicContext().clone(); + + AffineTransform prepareHPGL2 = new AffineTransform(); + prepareHPGL2.scale(0.001, 0.001); + ctx.setTransform(prepareHPGL2); + + PCLGraphics2D graphics = new PCLGraphics2D(tempGen); + graphics.setGraphicContext(ctx); + graphics.setClippingDisabled(false /*pclContext.isClippingDisabled()*/); + Rectangle2D area = new Rectangle2D.Double( + 0.0, 0.0, imageDim.getWidth(), imageDim.getHeight()); + imageG2D.getGraphics2DImagePainter().paint(graphics, area); + + //If we arrive here, the graphic is natively paintable, so write the graphic + gen.writeCommand("*c" + gen.formatDouble4(pos.width / 100f) + "x" + + gen.formatDouble4(pos.height / 100f) + "Y"); + gen.writeCommand("*c0T"); + gen.enterHPGL2Mode(false); + gen.writeText("\nIN;"); + gen.writeText("SP1;"); + //One Plotter unit is 0.025mm! + double scale = imageDim.getWidth() / UnitConv.mm2pt(imageDim.getWidth() * 0.025); + gen.writeText("SC0," + gen.formatDouble4(scale) + + ",0,-" + gen.formatDouble4(scale) + ",2;"); + gen.writeText("IR0,100,0,100;"); + gen.writeText("PU;PA0,0;\n"); + baout.writeTo(gen.getOutputStream()); //Buffer is written to output stream + gen.writeText("\n"); + + gen.enterPCLMode(false); + painted = true; + } catch (UnsupportedOperationException uoe) { + log.debug( + "Cannot paint graphic natively. Falling back to bitmap painting. Reason: " + + uoe.getMessage()); + } + + if (!painted) { + //Fallback solution: Paint to a BufferedImage + FOUserAgent ua = context.getUserAgent(); + ImageManager imageManager = ua.getFactory().getImageManager(); + ImageRendered imgRend; + try { + imgRend = (ImageRendered)imageManager.convertImage( + imageG2D, new ImageFlavor[] {ImageFlavor.RENDERED_IMAGE}/*, hints*/); + } catch (ImageException e) { + throw new IOException( + "Image conversion error while converting the image to a bitmap" + + " as a fallback measure: " + e.getMessage()); + } + + gen.paintBitmap(imgRend.getRenderedImage(), new Dimension(pos.width, pos.height), + pclContext.isSourceTransparencyEnabled()); + } + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + boolean supported = (image == null || image instanceof ImageGraphics2D) + && targetContext instanceof PCLRenderingContext; + if (supported) { + Object hint = targetContext.getHint(PCLConstants.CONV_MODE); + if ("bitmap".equals(hint)) { + return false; + } + } + return supported; + } + +} diff --git a/src/java/org/apache/fop/render/pcl/PCLPainter.java b/src/java/org/apache/fop/render/pcl/PCLPainter.java index 7ad6ea931..b709c28f3 100644 --- a/src/java/org/apache/fop/render/pcl/PCLPainter.java +++ b/src/java/org/apache/fop/render/pcl/PCLPainter.java @@ -110,6 +110,10 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { } } + private boolean isSpeedOptimized() { + return getPCLUtil().getRenderingMode() == PCLRenderingMode.SPEED; + } + //---------------------------------------------------------------------------------------------- /** {@inheritDoc} */ @@ -161,6 +165,10 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { return PCLPainter.this.transformedPoint(x, y); } + public GraphicContext getGraphicContext() { + return PCLPainter.this.graphicContext; + } + }; return pdfContext; } @@ -203,7 +211,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { 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) { + if (isSpeedOptimized()) { super.drawBorderRect(rect, before, after, start, end); return; } @@ -239,7 +247,7 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { public void drawLine(final Point start, final Point end, final int width, final Color color, final RuleStyle style) throws IFException { - if (getPCLUtil().getRenderingMode() == PCLRenderingMode.SPEED) { + if (isSpeedOptimized()) { super.drawLine(start, end, width, color, style); return; } @@ -278,8 +286,16 @@ public class PCLPainter extends AbstractIFPainter implements PCLConstants { ImageGraphics2D img = new ImageGraphics2D(info, painter); Map hints = new java.util.HashMap(); - hints.put(ImageProcessingHints.BITMAP_TYPE_INTENT, - ImageProcessingHints.BITMAP_TYPE_INTENT_GRAY); + if (isSpeedOptimized()) { + //Gray text may not be painted in this case! We don't get dithering in Sun JREs. + //But this approach is about twice as fast as the grayscale image. + hints.put(ImageProcessingHints.BITMAP_TYPE_INTENT, + ImageProcessingHints.BITMAP_TYPE_INTENT_MONO); + } else { + hints.put(ImageProcessingHints.BITMAP_TYPE_INTENT, + ImageProcessingHints.BITMAP_TYPE_INTENT_GRAY); + } + hints.put(PCLConstants.CONV_MODE, "bitmap"); PCLRenderingContext context = (PCLRenderingContext)createRenderingContext(); context.setSourceTransparencyEnabled(true); try { diff --git a/src/java/org/apache/fop/render/pcl/PCLRenderingContext.java b/src/java/org/apache/fop/render/pcl/PCLRenderingContext.java index 4c41cbf58..9212770fc 100644 --- a/src/java/org/apache/fop/render/pcl/PCLRenderingContext.java +++ b/src/java/org/apache/fop/render/pcl/PCLRenderingContext.java @@ -21,6 +21,7 @@ package org.apache.fop.render.pcl; import java.awt.geom.Point2D; +import org.apache.xmlgraphics.java2d.GraphicContext; import org.apache.xmlgraphics.util.MimeConstants; import org.apache.fop.apps.FOUserAgent; @@ -93,4 +94,10 @@ public abstract class PCLRenderingContext extends AbstractRenderingContext { */ public abstract Point2D transformedPoint(int x, int y); + /** + * Returns the current {@code GraphicContext} instance. + * @return the graphic context + */ + public abstract GraphicContext getGraphicContext(); + } |