diff options
author | Jeremias Maerki <jeremias@apache.org> | 2010-06-12 08:19:48 +0000 |
---|---|---|
committer | Jeremias Maerki <jeremias@apache.org> | 2010-06-12 08:19:48 +0000 |
commit | 97aa2c35b008616df914162cb398ee017cc5169c (patch) | |
tree | 9739e69937acb88c337e0707aebbe535f237d630 /src/java/org/apache | |
parent | 1fae69d5fdafcf8ba313087e5afa67d203af6482 (diff) | |
download | xmlgraphics-fop-97aa2c35b008616df914162cb398ee017cc5169c.tar.gz xmlgraphics-fop-97aa2c35b008616df914162cb398ee017cc5169c.zip |
AFP Output Changes:
- Fixed positioning of Java2D-based images (when GOCA is enabled). GraphicsDataDescriptor had a bit order bug. The Graphics2D image handler didn't save state and reposition the image origin.
- Switched bitmap image handling in AFPGraphics2D to (re-)use AFPImageHandlerRenderedImage so it can profit from it's advanced image conversion functionality. This also avoids some bugs with certain image formats.
- Added enhanced dithering functionality for images that need to be converted to bi-level images.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@953952 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
10 files changed, 144 insertions, 88 deletions
diff --git a/src/java/org/apache/fop/afp/AFPGraphics2D.java b/src/java/org/apache/fop/afp/AFPGraphics2D.java index b8d7158cf..fa9c0d7bf 100644 --- a/src/java/org/apache/fop/afp/AFPGraphics2D.java +++ b/src/java/org/apache/fop/afp/AFPGraphics2D.java @@ -45,7 +45,6 @@ import java.awt.image.RenderedImage; import java.awt.image.renderable.RenderableImage; import java.io.IOException; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -56,8 +55,6 @@ import org.apache.xmlgraphics.java2d.AbstractGraphics2D; import org.apache.xmlgraphics.java2d.GraphicContext; import org.apache.xmlgraphics.java2d.StrokingTextHandler; import org.apache.xmlgraphics.java2d.TextHandler; -import org.apache.xmlgraphics.ps.ImageEncodingHelper; -import org.apache.xmlgraphics.util.MimeConstants; import org.apache.xmlgraphics.util.UnitConv; import org.apache.fop.afp.goca.GraphicsSetLineType; @@ -65,6 +62,8 @@ import org.apache.fop.afp.modca.GraphicsObject; import org.apache.fop.afp.svg.AFPGraphicsConfiguration; import org.apache.fop.afp.util.CubicBezierApproximator; import org.apache.fop.fonts.FontInfo; +import org.apache.fop.render.afp.AFPImageHandlerRenderedImage; +import org.apache.fop.render.afp.AFPRenderingContext; import org.apache.fop.svg.NativeImageHandler; /** @@ -559,75 +558,6 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand BufferedImage.TYPE_INT_ARGB); } - private AFPImageObjectInfo createImageObjectInfo( - RenderedImage img, int x, int y, int width, int height) throws IOException { - ImageInfo imageInfo = new ImageInfo(null, "image/unknown"); - ImageSize size = new ImageSize(img.getWidth(), img.getHeight(), 72); - imageInfo.setSize(size); - - ImageRendered imageRendered = new ImageRendered(imageInfo, img, null); - RenderedImage renderedImage = imageRendered.getRenderedImage(); - - // create image object info - AFPImageObjectInfo imageObjectInfo = new AFPImageObjectInfo(); - - imageObjectInfo.setMimeType(MimeConstants.MIME_AFP_IOCA_FS45); - - int bitsPerPixel = paintingState.getBitsPerPixel(); - imageObjectInfo.setBitsPerPixel(bitsPerPixel); - - imageObjectInfo.setResourceInfo(resourceInfo); - - int dataHeight = renderedImage.getHeight(); - imageObjectInfo.setDataHeight(dataHeight); - - int dataWidth = renderedImage.getWidth(); - imageObjectInfo.setDataWidth(dataWidth); - - int resolution = paintingState.getResolution(); - imageObjectInfo.setDataWidthRes(resolution); - imageObjectInfo.setDataHeightRes(resolution); - - boolean colorImages = paintingState.isColorImages(); - imageObjectInfo.setColor(colorImages); - - ByteArrayOutputStream boas = new ByteArrayOutputStream(); - ImageEncodingHelper.encodeRenderedImageAsRGB(renderedImage, boas); - byte[] imageData = boas.toByteArray(); - - // convert to grayscale - if (!colorImages) { - boas.reset(); - imageObjectInfo.setBitsPerPixel(bitsPerPixel); - ImageEncodingHelper.encodeRGBAsGrayScale( - imageData, dataWidth, dataHeight, bitsPerPixel, boas); - imageData = boas.toByteArray(); - if (bitsPerPixel == 1) { - //FS10 should generate a page seqment to avoid problems - imageObjectInfo.setCreatePageSegment(true); - } - } - imageObjectInfo.setData(imageData); - - if (imageInfo != null) { - imageObjectInfo.setUri(imageInfo.getOriginalURI()); - } - - // create object area info - AFPObjectAreaInfo objectAreaInfo = new AFPObjectAreaInfo(); - objectAreaInfo.setX(x); - objectAreaInfo.setY(y); - objectAreaInfo.setWidth(width); - objectAreaInfo.setHeight(height); - - objectAreaInfo.setWidthRes(resolution); - objectAreaInfo.setHeightRes(resolution); - - imageObjectInfo.setObjectAreaInfo(objectAreaInfo); - - return imageObjectInfo; - } - /** * Draws an AWT image into a BufferedImage using an AWT Graphics2D implementation * @@ -667,7 +597,6 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand /** {@inheritDoc} */ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { - // draw with AWT Graphics2D Dimension imageSize = new Dimension(width, height); BufferedImage bufferedImage = buildBufferedImage(imageSize); @@ -684,20 +613,33 @@ public class AFPGraphics2D extends AbstractGraphics2D implements NativeImageHand int imgWidth = img.getWidth(); int imgHeight = img.getHeight(); - AffineTransform at = paintingState.getData().getTransform(); AffineTransform gat = gc.getTransform(); int graphicsObjectHeight = graphicsObj.getObjectEnvironmentGroup().getObjectAreaDescriptor().getHeight(); - int x = (int)Math.round(at.getTranslateX() + gat.getTranslateX()); - int y = (int)Math.round(at.getTranslateY() - (gat.getTranslateY() - graphicsObjectHeight)); - int width = (int)Math.round(imgWidth * gat.getScaleX()); - int height = (int)Math.round(imgHeight * -gat.getScaleY()); + + double toMillipointFactor = UnitConv.IN2PT * 1000 / (double)paintingState.getResolution(); + double x = gat.getTranslateX(); + double y = -(gat.getTranslateY() - graphicsObjectHeight); + x = toMillipointFactor * x; + y = toMillipointFactor * y; + double w = toMillipointFactor * imgWidth * gat.getScaleX(); + double h = toMillipointFactor * imgHeight * -gat.getScaleY(); + + AFPImageHandlerRenderedImage handler = new AFPImageHandlerRenderedImage(); + ImageInfo imageInfo = new ImageInfo(null, null); + imageInfo.setSize(new ImageSize( + img.getWidth(), img.getHeight(), paintingState.getResolution())); + imageInfo.getSize().calcSizeFromPixels(); + ImageRendered red = new ImageRendered(imageInfo, img, null); + Rectangle targetPos = new Rectangle( + (int)Math.round(x), + (int)Math.round(y), + (int)Math.round(w), + (int)Math.round(h)); + AFPRenderingContext context = new AFPRenderingContext(null, + resourceManager, paintingState, fontInfo, null); try { - // get image object info - AFPImageObjectInfo imageObjectInfo - = createImageObjectInfo(img, x, y, width, height); - // create image resource - resourceManager.createObject(imageObjectInfo); + handler.handleImage(context, red, targetPos); } catch (IOException ioe) { handleIOException(ioe); } diff --git a/src/java/org/apache/fop/afp/AFPPaintingState.java b/src/java/org/apache/fop/afp/AFPPaintingState.java index a19874183..4e314e5d9 100644 --- a/src/java/org/apache/fop/afp/AFPPaintingState.java +++ b/src/java/org/apache/fop/afp/AFPPaintingState.java @@ -51,6 +51,9 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState /** color image support */ private boolean colorImages = false; + /** dithering quality setting (0.0f..1.0f) */ + private float ditheringQuality; + /** color image handler */ private ColorConverter colorConverter = GrayScaleColorConverter.getInstance(); @@ -234,6 +237,25 @@ public class AFPPaintingState extends org.apache.fop.util.AbstractPaintingState } /** + * Gets the dithering quality setting to use when converting images to monochrome images. + * @return the dithering quality (a value between 0.0f and 1.0f) + */ + public float getDitheringQuality() { + return this.ditheringQuality; + } + + /** + * Sets the dithering quality setting to use when converting images to monochrome images. + * @param quality Defines the desired quality level for the conversion. + * Valid values: a value between 0.0f (fastest) and 1.0f (best) + */ + public void setDitheringQuality(float quality) { + quality = Math.max(quality, 0.0f); + quality = Math.min(quality, 1.0f); + this.ditheringQuality = quality; + } + + /** * Sets the output/device resolution * * @param resolution diff --git a/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java b/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java index 5495e2e9c..5fa3b70a9 100644 --- a/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java +++ b/src/java/org/apache/fop/afp/modca/GraphicsDataDescriptor.java @@ -104,8 +104,8 @@ public class GraphicsDataDescriptor extends AbstractDescriptor { return data; } - private static final int ABS = 2; - private static final int IMGRES = 8; + private static final int ABS = 64; + private static final int IMGRES = 16; /** * Returns the window specification data diff --git a/src/java/org/apache/fop/render/afp/AFPCustomizable.java b/src/java/org/apache/fop/render/afp/AFPCustomizable.java index 5f3fe6823..93aaa8b1a 100644 --- a/src/java/org/apache/fop/render/afp/AFPCustomizable.java +++ b/src/java/org/apache/fop/render/afp/AFPCustomizable.java @@ -65,6 +65,13 @@ public interface AFPCustomizable { void setShadingMode(AFPShadingMode shadingMode); /** + * Sets the dithering quality setting to use when converting images to monochrome images. + * @param quality Defines the desired quality level for the conversion. + * Valid values: a value between 0.0f (fastest) and 1.0f (best) + */ + void setDitheringQuality(float quality); + + /** * Sets the output/device resolution * * @param resolution diff --git a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java index 3fec25d8d..21d4faf56 100644 --- a/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java +++ b/src/java/org/apache/fop/render/afp/AFPDocumentHandler.java @@ -46,8 +46,8 @@ import org.apache.fop.fonts.FontManager; import org.apache.fop.render.afp.extensions.AFPElementMapping; import org.apache.fop.render.afp.extensions.AFPIncludeFormMap; import org.apache.fop.render.afp.extensions.AFPInvokeMediumMap; -import org.apache.fop.render.afp.extensions.AFPPageSetup; import org.apache.fop.render.afp.extensions.AFPPageOverlay; +import org.apache.fop.render.afp.extensions.AFPPageSetup; import org.apache.fop.render.intermediate.AbstractBinaryWritingIFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandler; import org.apache.fop.render.intermediate.IFDocumentHandlerConfigurator; @@ -362,6 +362,11 @@ public class AFPDocumentHandler extends AbstractBinaryWritingIFDocumentHandler } /** {@inheritDoc} */ + public void setDitheringQuality(float quality) { + this.paintingState.setDitheringQuality(quality); + } + + /** {@inheritDoc} */ public void setShadingMode(AFPShadingMode shadingMode) { this.shadingMode = shadingMode; } diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java index 32a95b445..aaaecf2ea 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerGraphics2D.java @@ -20,6 +20,7 @@ package org.apache.fop.render.afp; import java.awt.Rectangle; +import java.awt.geom.AffineTransform; import java.io.IOException; import org.apache.xmlgraphics.image.loader.Image; @@ -136,6 +137,12 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler implements ImageH setDefaultResourceLevel(graphicsObjectInfo, afpContext.getResourceManager()); + AFPPaintingState paintingState = afpContext.getPaintingState(); + paintingState.save(); // save + AffineTransform placement = new AffineTransform(); + placement.translate(pos.x, pos.y); + paintingState.concatenate(placement); + // Image content ImageGraphics2D imageG2D = (ImageGraphics2D)image; boolean textAsShapes = false; //TODO Make configurable @@ -152,6 +159,8 @@ public class AFPImageHandlerGraphics2D extends AFPImageHandler implements ImageH // Create image afpContext.getResourceManager().createObject(graphicsObjectInfo); + + paintingState.restore(); // resume } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java index 330f78d63..cb7b23da2 100644 --- a/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/afp/AFPImageHandlerRenderedImage.java @@ -101,6 +101,7 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima maxPixelSize *= 3; //RGB is maximum } } + float ditheringQuality = paintingState.getDitheringQuality(); RenderedImage renderedImage = imageRendered.getRenderedImage(); ImageInfo imageInfo = imageRendered.getInfo(); @@ -130,9 +131,13 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima log.debug("Resample from " + intrinsicSize.getDimensionPx() + " to " + resampledDim); } - renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage, resampledDim); + renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage, + resampledDim, ditheringQuality); effIntrinsicSize = new ImageSize( resampledDim.width, resampledDim.height, resolution); + } else if (ditheringQuality >= 0.5f) { + renderedImage = BitmapImageUtil.convertToMonochrome(renderedImage, + intrinsicSize.getDimensionPx(), ditheringQuality); } } @@ -157,7 +162,6 @@ public class AFPImageHandlerRenderedImage extends AFPImageHandler implements Ima if (cm.hasAlpha()) { pixelSize -= 8; } - //TODO Add support for CMYK images byte[] imageData = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/src/java/org/apache/fop/render/afp/AFPRenderer.java b/src/java/org/apache/fop/render/afp/AFPRenderer.java index d88deadfe..1f373023c 100644 --- a/src/java/org/apache/fop/render/afp/AFPRenderer.java +++ b/src/java/org/apache/fop/render/afp/AFPRenderer.java @@ -839,6 +839,11 @@ public class AFPRenderer extends AbstractPathOrientedRenderer implements AFPCust } /** {@inheritDoc} */ + public void setDitheringQuality(float quality) { + this.paintingState.setDitheringQuality(quality); + } + + /** {@inheritDoc} */ public void setShadingMode(AFPShadingMode shadingMode) { this.shadingMode = shadingMode; } diff --git a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java index 23f413813..1720667df 100644 --- a/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java +++ b/src/java/org/apache/fop/render/afp/AFPRendererConfigurator.java @@ -390,6 +390,21 @@ public class AFPRendererConfigurator extends PrintRendererConfigurator customizable.setBitsPerPixel(bitsPerPixel); } + String dithering = imagesCfg.getAttribute("dithering-quality", "medium"); + float dq = 0.5f; + if (dithering.startsWith("min")) { + dq = 0.0f; + } else if (dithering.startsWith("max")) { + dq = 1.0f; + } else { + try { + dq = Float.parseFloat(dithering); + } catch (NumberFormatException nfe) { + //ignore and leave the default above + } + } + customizable.setDitheringQuality(dq); + // native image support boolean nativeImageSupport = imagesCfg.getAttributeAsBoolean("native", false); customizable.setNativeImagesSupported(nativeImageSupport); diff --git a/src/java/org/apache/fop/util/bitmap/BitmapImageUtil.java b/src/java/org/apache/fop/util/bitmap/BitmapImageUtil.java index cb46395ca..c08076316 100644 --- a/src/java/org/apache/fop/util/bitmap/BitmapImageUtil.java +++ b/src/java/org/apache/fop/util/bitmap/BitmapImageUtil.java @@ -135,6 +135,53 @@ public class BitmapImageUtil { */ public static final BufferedImage convertToMonochrome(RenderedImage img, Dimension targetDimension) { + return toBufferedImage(convertToMonochrome(img, targetDimension, 0.0f)); + } + + /** + * Converts an image to a monochrome 1-bit image. Optionally, the image can be scaled. + * @param img the image to be converted + * @param targetDimension the new target dimensions or null if no scaling is necessary + * @param quality Defines the desired quality level for the conversion. + * Valid values: a value between 0.0f (fastest) and 1.0f (best) + * @return the monochrome image + */ + public static final RenderedImage convertToMonochrome(RenderedImage img, + Dimension targetDimension, float quality) { + if (!isMonochromeImage(img)) { + if (quality >= 0.5f) { + BufferedImage bi; + Dimension orgDim = new Dimension(img.getWidth(), img.getHeight()); + if (targetDimension != null && !orgDim.equals(targetDimension)) { + //Scale only before dithering + ColorModel cm = img.getColorModel(); + BufferedImage tgt = new BufferedImage(cm, + cm.createCompatibleWritableRaster( + targetDimension.width, targetDimension.height), + cm.isAlphaPremultiplied(), null); + transferImage(img, tgt); + bi = tgt; + } else { + bi = toBufferedImage(img); + } + //Now convert to monochrome (dithering if available) + MonochromeBitmapConverter converter = createDefaultMonochromeBitmapConverter(); + if (quality >= 0.8f) { + //Activates error diffusion if JAI is available + converter.setHint("quality", Boolean.TRUE.toString()); + //Need to convert to grayscale first since otherwise, there may be encoding + //problems later with the images JAI can generate. + bi = convertToGrayscale(bi, targetDimension); + } + try { + return converter.convertToMonochrome(bi); + } catch (Exception e) { + //Provide a fallback if exotic formats are encountered + bi = convertToGrayscale(bi, targetDimension); + return converter.convertToMonochrome(bi); + } + } + } return convertAndScaleImage(img, targetDimension, BufferedImage.TYPE_BYTE_BINARY); } |