From 4bba95be2e5bd480bd5adec9e9b1083d5fb9a561 Mon Sep 17 00:00:00 2001 From: Glenn Adams Date: Fri, 15 Jun 2012 02:56:21 +0000 Subject: [PATCH] Bugzilla #40676: Support use of ImageLoaderRawPNG decoder in order to prevent re-encoding of PNG images (and unnecssary output file bloat). Submitted by Luis Bernardo, Matthias Reischenbacher. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1350455 13f79535-47bb-0310-9956-ffa450edef68 --- lib/xmlgraphics-commons-1.5svn.jar | Bin 587046 -> 597674 bytes .../org.apache.fop.render.ImageHandler | 2 + src/java/org/apache/fop/pdf/BitmapImage.java | 6 +- .../fop/render/pdf/AbstractImageAdapter.java | 69 ++++- .../fop/render/pdf/ImageRawPNGAdapter.java | 258 ++++++++++++++++++ .../fop/render/pdf/ImageRenderedAdapter.java | 73 +---- .../fop/render/pdf/PDFImageHandlerRawPNG.java | 65 +++++ .../apache/fop/render/ps/ImageEncoderPNG.java | 113 ++++++++ .../fop/render/ps/PSImageHandlerRawPNG.java | 111 ++++++++ .../ps/PSImageHandlerRenderedImage.java | 26 +- status.xml | 3 + .../org/apache/fop/render/RawPNGTestUtil.java | 92 +++++++ .../pdf/ImageRawPNGAdapterTestCase.java | 142 ++++++++++ .../render/ps/ImageEncoderPNGTestCase.java | 133 +++++++++ 14 files changed, 1013 insertions(+), 80 deletions(-) create mode 100644 src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java create mode 100644 src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java create mode 100644 src/java/org/apache/fop/render/ps/ImageEncoderPNG.java create mode 100644 src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java create mode 100644 test/java/org/apache/fop/render/RawPNGTestUtil.java create mode 100644 test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java create mode 100644 test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java diff --git a/lib/xmlgraphics-commons-1.5svn.jar b/lib/xmlgraphics-commons-1.5svn.jar index 867ecb6e09be10435472b2469ce799d038768a06..c11f186081188cf819fcc5026a3add1a6d34ecd5 100644 GIT binary patch delta 58942 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 Bzsmps delta 48438 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

?_Y2N*D`U#b?gz#@1TCOh?8ZoaYxvJHML9e3(} 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 On+#roKZFSuo$mhy0U_i7 diff --git a/src/java/META-INF/services/org.apache.fop.render.ImageHandler b/src/java/META-INF/services/org.apache.fop.render.ImageHandler index f9b890c8e..9066913ad 100644 --- a/src/java/META-INF/services/org.apache.fop.render.ImageHandler +++ b/src/java/META-INF/services/org.apache.fop.render.ImageHandler @@ -1,6 +1,7 @@ org.apache.fop.render.pdf.PDFImageHandlerGraphics2D org.apache.fop.render.pdf.PDFImageHandlerRenderedImage org.apache.fop.render.pdf.PDFImageHandlerRawJPEG +org.apache.fop.render.pdf.PDFImageHandlerRawPNG org.apache.fop.render.pdf.PDFImageHandlerRawCCITTFax org.apache.fop.render.pdf.PDFImageHandlerSVG org.apache.fop.render.java2d.Java2DImageHandlerRenderedImage @@ -11,6 +12,7 @@ org.apache.fop.render.ps.PSImageHandlerRenderedImage org.apache.fop.render.ps.PSImageHandlerEPS org.apache.fop.render.ps.PSImageHandlerRawCCITTFax org.apache.fop.render.ps.PSImageHandlerRawJPEG +org.apache.fop.render.ps.PSImageHandlerRawPNG org.apache.fop.render.ps.PSImageHandlerGraphics2D org.apache.fop.render.ps.PSImageHandlerSVG org.apache.fop.render.afp.AFPImageHandlerRenderedImage diff --git a/src/java/org/apache/fop/pdf/BitmapImage.java b/src/java/org/apache/fop/pdf/BitmapImage.java index 186c00986..0979ddf9a 100644 --- a/src/java/org/apache/fop/pdf/BitmapImage.java +++ b/src/java/org/apache/fop/pdf/BitmapImage.java @@ -37,6 +37,7 @@ public class BitmapImage implements PDFImage { private PDFColor transparent = null; private String key; private PDFDocument pdfDoc; + private PDFFilter pdfFilter; /** * Create a bitmap image. @@ -208,9 +209,12 @@ public class BitmapImage implements PDFImage { * {@inheritDoc} */ public PDFFilter getPDFFilter() { - return null; + return pdfFilter; } + public void setPDFFilter(PDFFilter pdfFilter) { + this.pdfFilter = pdfFilter; + } } diff --git a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java index 59d3930f7..ce99b9fef 100644 --- a/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java +++ b/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java @@ -20,13 +20,16 @@ package org.apache.fop.render.pdf; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import java.awt.image.IndexColorModel; +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.java2d.color.profile.ColorProfileUtil; +import org.apache.fop.pdf.PDFArray; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFConformanceException; import org.apache.fop.pdf.PDFDeviceColorSpace; @@ -50,7 +53,9 @@ public abstract class AbstractImageAdapter implements PDFImage { /** the image */ protected Image image; - private PDFICCStream pdfICCStream = null; + private PDFICCStream pdfICCStream; + + private static final int MAX_HIVAL = 255; /** * Creates a new PDFImage from an Image instance. @@ -202,6 +207,68 @@ public abstract class AbstractImageAdapter implements PDFImage { //nop } + /** + * This is to be used by populateXObjectDictionary() when the image is palette based. + * @param dict the dictionary to fill in + * @param icm the image color model + */ + protected void populateXObjectDictionaryForIndexColorModel(PDFDictionary dict, IndexColorModel icm) { + PDFArray indexed = new PDFArray(dict); + indexed.add(new PDFName("Indexed")); + if (icm.getColorSpace().getType() != ColorSpace.TYPE_RGB) { + log.warn("Indexed color space is not using RGB as base color space." + + " The image may not be handled correctly." + " Base color space: " + + icm.getColorSpace() + " Image: " + image.getInfo()); + } + indexed.add(new PDFName(toPDFColorSpace(icm.getColorSpace()).getName())); + int c = icm.getMapSize(); + int hival = c - 1; + if (hival > MAX_HIVAL) { + throw new UnsupportedOperationException("hival must not go beyond " + MAX_HIVAL); + } + indexed.add(new Integer(hival)); + int[] palette = new int[c]; + icm.getRGBs(palette); + ByteArrayOutputStream baout = new ByteArrayOutputStream(); + for (int i = 0; i < c; i++) { + // TODO Probably doesn't work for non RGB based color spaces + // See log warning above + int entry = palette[i]; + baout.write((entry & 0xFF0000) >> 16); + baout.write((entry & 0xFF00) >> 8); + baout.write(entry & 0xFF); + } + indexed.add(baout.toByteArray()); + + dict.put("ColorSpace", indexed); + dict.put("BitsPerComponent", icm.getPixelSize()); + + Integer index = getIndexOfFirstTransparentColorInPalette(icm); + if (index != null) { + PDFArray mask = new PDFArray(dict); + mask.add(index); + mask.add(index); + dict.put("Mask", mask); + } + } + + private static Integer getIndexOfFirstTransparentColorInPalette(IndexColorModel icm) { + byte[] alphas = new byte[icm.getMapSize()]; + byte[] reds = new byte[icm.getMapSize()]; + byte[] greens = new byte[icm.getMapSize()]; + byte[] blues = new byte[icm.getMapSize()]; + icm.getAlphas(alphas); + icm.getReds(reds); + icm.getGreens(greens); + icm.getBlues(blues); + for (int i = 0; i < icm.getMapSize(); i++) { + if ((alphas[i] & 0xFF) == 0) { + return new Integer(i); + } + } + return null; + } + /** * Converts a ColorSpace object to a PDFColorSpace object. * @param cs ColorSpace instance diff --git a/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java new file mode 100644 index 000000000..55264e2fe --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java @@ -0,0 +1,258 @@ +/* + * 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$ */ + +// Original author: Matthias Reichenbacher + +package org.apache.fop.render.pdf; + +import java.awt.image.ColorModel; +import java.awt.image.IndexColorModel; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +import org.apache.commons.io.IOUtils; +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.impl.ImageRawPNG; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; + +import org.apache.fop.pdf.BitmapImage; +import org.apache.fop.pdf.FlateFilter; +import org.apache.fop.pdf.PDFColor; +import org.apache.fop.pdf.PDFDeviceColorSpace; +import org.apache.fop.pdf.PDFDictionary; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFFilter; +import org.apache.fop.pdf.PDFFilterException; +import org.apache.fop.pdf.PDFFilterList; +import org.apache.fop.pdf.PDFICCStream; +import org.apache.fop.pdf.PDFReference; + +public class ImageRawPNGAdapter extends AbstractImageAdapter { + + /** logging instance */ + private static Log log = LogFactory.getLog(ImageRawPNGAdapter.class); + + private PDFICCStream pdfICCStream; + private PDFFilter pdfFilter; + private String maskRef; + private PDFReference softMask; + private int numberOfInterleavedComponents; + + /** + * Creates a new PDFImage from an Image instance. + * @param image the image + * @param key XObject key + */ + public ImageRawPNGAdapter(ImageRawPNG image, String key) { + super(image, key); + } + + /** {@inheritDoc} */ + public void setup(PDFDocument doc) { + super.setup(doc); + ColorModel cm = ((ImageRawPNG) this.image).getColorModel(); + if (cm instanceof IndexColorModel) { + numberOfInterleavedComponents = 1; + } else { + // this can be 1 (gray), 2 (gray + alpha), 3 (rgb) or 4 (rgb + alpha) + // numberOfInterleavedComponents = (cm.hasAlpha() ? 1 : 0) + cm.getNumColorComponents(); + numberOfInterleavedComponents = cm.getNumComponents(); + } + + // set up image compression for non-alpha channel + FlateFilter flate; + try { + flate = new FlateFilter(); + flate.setApplied(true); + flate.setPredictor(FlateFilter.PREDICTION_PNG_OPT); + if (numberOfInterleavedComponents < 3) { + // means palette (1) or gray (1) or gray + alpha (2) + flate.setColors(1); + } else { + // means rgb (3) or rgb + alpha (4) + flate.setColors(3); + } + flate.setColumns(image.getSize().getWidthPx()); + flate.setBitsPerComponent(this.getBitsPerComponent()); + } catch (PDFFilterException e) { + throw new RuntimeException("FlateFilter configuration error", e); + } + this.pdfFilter = flate; + + // Handle transparency channel if applicable; note that for palette images the transparency is + // not TRANSLUCENT + if (cm.hasAlpha() && cm.getTransparency() == ColorModel.TRANSLUCENT) { + doc.getProfile().verifyTransparencyAllowed(image.getInfo().getOriginalURI()); + // TODO: Implement code to combine image with background color if transparency is not allowed + // here we need to inflate the PNG pixel data, which includes alpha, separate the alpha channel + // and then deflate it back again + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(baos, new Deflater()); + InputStream in = ((ImageRawStream) image).createInputStream(); + try { + InflaterInputStream infStream = new InflaterInputStream(in, new Inflater()); + DataInputStream dataStream = new DataInputStream(infStream); + // offset is the byte offset of the alpha component + int offset = numberOfInterleavedComponents - 1; // 1 for GA, 3 for RGBA + int numColumns = image.getSize().getWidthPx(); + int bytesPerRow = numberOfInterleavedComponents * numColumns; + int filter; + // read line by line; the first byte holds the filter + while ((filter = dataStream.read()) != -1) { + byte[] bytes = new byte[bytesPerRow]; + dataStream.readFully(bytes, 0, bytesPerRow); + dos.write((byte) filter); + for (int j = 0; j < numColumns; j++) { + dos.write(bytes, offset, 1); + offset += numberOfInterleavedComponents; + } + offset = numberOfInterleavedComponents - 1; + } + dos.close(); + } catch (IOException e) { + throw new RuntimeException("Error processing transparency channel:", e); + } finally { + IOUtils.closeQuietly(in); + } + // set up alpha channel compression + FlateFilter transFlate; + try { + transFlate = new FlateFilter(); + transFlate.setApplied(true); + transFlate.setPredictor(FlateFilter.PREDICTION_PNG_OPT); + transFlate.setColors(1); + transFlate.setColumns(image.getSize().getWidthPx()); + transFlate.setBitsPerComponent(this.getBitsPerComponent()); + } catch (PDFFilterException e) { + throw new RuntimeException("FlateFilter configuration error", e); + } + BitmapImage alphaMask = new BitmapImage("Mask:" + this.getKey(), image.getSize().getWidthPx(), + image.getSize().getHeightPx(), baos.toByteArray(), null); + alphaMask.setPDFFilter(transFlate); + alphaMask.setColorSpace(new PDFDeviceColorSpace(PDFDeviceColorSpace.DEVICE_GRAY)); + softMask = doc.addImage(null, alphaMask).makeReference(); + } + } + + /** {@inheritDoc} */ + public PDFDeviceColorSpace getColorSpace() { + // DeviceGray, DeviceRGB, or DeviceCMYK + return toPDFColorSpace(image.getColorSpace()); + } + + /** {@inheritDoc} */ + public int getBitsPerComponent() { + return ((ImageRawPNG) this.image).getBitDepth(); + } + + /** {@inheritDoc} */ + public boolean isTransparent() { + return ((ImageRawPNG) this.image).isTransparent(); + } + + /** {@inheritDoc} */ + public PDFColor getTransparentColor() { + return new PDFColor(((ImageRawPNG) this.image).getTransparentColor()); + } + + /** {@inheritDoc} */ + public String getMask() { + return maskRef; + } + + /** {@inheritDoc} */ + public String getSoftMask() { + return softMask.toString(); + } + + /** {@inheritDoc} */ + public PDFReference getSoftMaskReference() { + return softMask; + } + + /** {@inheritDoc} */ + public PDFFilter getPDFFilter() { + return pdfFilter; + } + + /** {@inheritDoc} */ + public void outputContents(OutputStream out) throws IOException { + InputStream in = ((ImageRawStream) image).createInputStream(); + + try { + if (numberOfInterleavedComponents == 1 || numberOfInterleavedComponents == 3) { + // means we have Gray, RGB, or Palette + IOUtils.copy(in, out); + } else { + // means we have Gray + alpha or RGB + alpha + // TODO: since we have alpha here do this when the alpha channel is extracted + int numBytes = numberOfInterleavedComponents - 1; // 1 for Gray, 3 for RGB + int numColumns = image.getSize().getWidthPx(); + InflaterInputStream infStream = new InflaterInputStream(in, new Inflater()); + DataInputStream dataStream = new DataInputStream(infStream); + int offset = 0; + int bytesPerRow = numberOfInterleavedComponents * numColumns; + int filter; + // here we need to inflate the PNG pixel data, which includes alpha, separate the alpha + // channel and then deflate the RGB channels back again + DeflaterOutputStream dos = new DeflaterOutputStream(out, new Deflater()); + while ((filter = dataStream.read()) != -1) { + byte[] bytes = new byte[bytesPerRow]; + dataStream.readFully(bytes, 0, bytesPerRow); + dos.write((byte) filter); + for (int j = 0; j < numColumns; j++) { + dos.write(bytes, offset, numBytes); + offset += numberOfInterleavedComponents; + } + offset = 0; + } + dos.close(); + } + } finally { + IOUtils.closeQuietly(in); + } + } + + /** {@inheritDoc} */ + public PDFICCStream getICCStream() { + return pdfICCStream; + } + + /** {@inheritDoc} */ + public String getFilterHint() { + return PDFFilterList.PRECOMPRESSED_FILTER; + } + + public void populateXObjectDictionary(PDFDictionary dict) { + ColorModel cm = ((ImageRawPNG) image).getColorModel(); + if (cm instanceof IndexColorModel) { + IndexColorModel icm = (IndexColorModel) cm; + super.populateXObjectDictionaryForIndexColorModel(dict, icm); + } + } +} diff --git a/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java b/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java index c38a2edaf..b0b7b79d1 100644 --- a/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java +++ b/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java @@ -27,8 +27,6 @@ import java.awt.image.RenderedImage; import java.io.IOException; import java.io.OutputStream; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,14 +34,12 @@ import org.apache.xmlgraphics.image.loader.impl.ImageRendered; import org.apache.xmlgraphics.ps.ImageEncodingHelper; import org.apache.fop.pdf.AlphaRasterImage; -import org.apache.fop.pdf.PDFArray; import org.apache.fop.pdf.PDFColor; import org.apache.fop.pdf.PDFDeviceColorSpace; import org.apache.fop.pdf.PDFDictionary; import org.apache.fop.pdf.PDFDocument; import org.apache.fop.pdf.PDFFilter; import org.apache.fop.pdf.PDFFilterList; -import org.apache.fop.pdf.PDFName; import org.apache.fop.pdf.PDFReference; /** @@ -162,30 +158,6 @@ public class ImageRenderedAdapter extends AbstractImageAdapter { return (getImage().getTransparentColor() != null); } - private static Integer getIndexOfFirstTransparentColorInPalette(RenderedImage image) { - ColorModel cm = image.getColorModel(); - if (cm instanceof IndexColorModel) { - IndexColorModel icm = (IndexColorModel)cm; - //Identify the transparent color in the palette - byte[] alphas = new byte[icm.getMapSize()]; - byte[] reds = new byte[icm.getMapSize()]; - byte[] greens = new byte[icm.getMapSize()]; - byte[] blues = new byte[icm.getMapSize()]; - icm.getAlphas(alphas); - icm.getReds(reds); - icm.getGreens(greens); - icm.getBlues(blues); - for (int i = 0; - i < ((IndexColorModel) cm).getMapSize(); - i++) { - if ((alphas[i] & 0xFF) == 0) { - return Integer.valueOf(i); - } - } - } - return null; - } - /** {@inheritDoc} */ @Override public PDFColor getTransparentColor() { @@ -230,54 +202,13 @@ public class ImageRenderedAdapter extends AbstractImageAdapter { } } - private static final int MAX_HIVAL = 255; - /** {@inheritDoc} */ @Override public void populateXObjectDictionary(PDFDictionary dict) { ColorModel cm = getEffectiveColorModel(); if (cm instanceof IndexColorModel) { - IndexColorModel icm = (IndexColorModel)cm; - PDFArray indexed = new PDFArray(dict); - indexed.add(new PDFName("Indexed")); - - if (icm.getColorSpace().getType() != ColorSpace.TYPE_RGB) { - log.warn("Indexed color space is not using RGB as base color space." - + " The image may not be handled correctly." - + " Base color space: " + icm.getColorSpace() - + " Image: " + image.getInfo()); - } - indexed.add(new PDFName(toPDFColorSpace(icm.getColorSpace()).getName())); - int c = icm.getMapSize(); - int hival = c - 1; - if (hival > MAX_HIVAL) { - throw new UnsupportedOperationException("hival must not go beyond " + MAX_HIVAL); - } - indexed.add(Integer.valueOf(hival)); - int[] palette = new int[c]; - icm.getRGBs(palette); - ByteArrayOutputStream baout = new ByteArrayOutputStream(); - for (int i = 0; i < c; i++) { - //TODO Probably doesn't work for non RGB based color spaces - //See log warning above - int entry = palette[i]; - baout.write((entry & 0xFF0000) >> 16); - baout.write((entry & 0xFF00) >> 8); - baout.write(entry & 0xFF); - } - indexed.add(baout.toByteArray()); - IOUtils.closeQuietly(baout); - - dict.put("ColorSpace", indexed); - dict.put("BitsPerComponent", icm.getPixelSize()); - - Integer index = getIndexOfFirstTransparentColorInPalette(getImage().getRenderedImage()); - if (index != null) { - PDFArray mask = new PDFArray(dict); - mask.add(index); - mask.add(index); - dict.put("Mask", mask); - } + IndexColorModel icm = (IndexColorModel) cm; + super.populateXObjectDictionaryForIndexColorModel(dict, icm); } } diff --git a/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java new file mode 100644 index 000000000..3475954a8 --- /dev/null +++ b/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java @@ -0,0 +1,65 @@ +/* + * 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$ */ + +// Original author: Matthias Reichenbacher + +package org.apache.fop.render.pdf; + +import org.apache.xmlgraphics.image.loader.Image; +import org.apache.xmlgraphics.image.loader.ImageFlavor; +import org.apache.xmlgraphics.image.loader.impl.ImageRawPNG; + +import org.apache.fop.pdf.PDFImage; +import org.apache.fop.render.RenderingContext; + +/** + * Image handler implementation which handles CCITT encoded images (CCITT fax group 3/4) + * for PDF output. + */ +public class PDFImageHandlerRawPNG extends AbstractPDFImageHandler { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {ImageFlavor.RAW_PNG}; + + @Override + PDFImage createPDFImage(Image image, String xobjectKey) { + return new ImageRawPNGAdapter((ImageRawPNG) image, xobjectKey); + } + + /** {@inheritDoc} */ + public int getPriority() { + return 100; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawPNG.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + return (image == null || image instanceof ImageRawPNG) + && targetContext instanceof PDFRenderingContext; + } + +} diff --git a/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java b/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java new file mode 100644 index 000000000..bcda90bda --- /dev/null +++ b/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java @@ -0,0 +1,113 @@ +/* + * 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.ps; + +import java.awt.image.ColorModel; +import java.awt.image.IndexColorModel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.Inflater; +import java.util.zip.InflaterInputStream; + +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.image.loader.impl.ImageRawPNG; +import org.apache.xmlgraphics.image.loader.impl.ImageRawStream; +import org.apache.xmlgraphics.ps.ImageEncoder; + +/** + * ImageEncoder implementation for PNG images. + */ +public class ImageEncoderPNG implements ImageEncoder { + private final ImageRawPNG image; + private int numberOfInterleavedComponents; + + /** + * Main constructor + * @param image the PNG image + */ + public ImageEncoderPNG(ImageRawPNG image) { + this.image = image; + ColorModel cm = ((ImageRawPNG) this.image).getColorModel(); + if (cm instanceof IndexColorModel) { + numberOfInterleavedComponents = 1; + } else { + // this can be 1 (gray), 2 (gray + alpha), 3 (rgb) or 4 (rgb + alpha) + // numberOfInterleavedComponents = (cm.hasAlpha() ? 1 : 0) + cm.getNumColorComponents(); + numberOfInterleavedComponents = cm.getNumComponents(); + } + } + + /** {@inheritDoc} */ + public void writeTo(OutputStream out) throws IOException { + // TODO: refactor this code with equivalent PDF code + InputStream in = ((ImageRawStream) image).createInputStream(); + try { + if (numberOfInterleavedComponents == 1 || numberOfInterleavedComponents == 3) { + // means we have Gray, RGB, or Palette + IOUtils.copy(in, out); + } else { + // means we have Gray + alpha or RGB + alpha + int numBytes = numberOfInterleavedComponents - 1; // 1 for Gray, 3 for RGB + int numColumns = image.getSize().getWidthPx(); + InflaterInputStream infStream = new InflaterInputStream(in, new Inflater()); + DataInputStream dataStream = new DataInputStream(infStream); + int offset = 0; + int bytesPerRow = numberOfInterleavedComponents * numColumns; + int filter; + // here we need to inflate the PNG pixel data, which includes alpha, separate the alpha + // channel and then deflate the RGB channels back again + // TODO: not using the baos below and using the original out instead (as happens in PDF) + // would be preferable but that does not work with the rest of the postscript code; this + // needs to be revisited + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(/* out */baos, new Deflater()); + while ((filter = dataStream.read()) != -1) { + byte[] bytes = new byte[bytesPerRow]; + dataStream.readFully(bytes, 0, bytesPerRow); + dos.write((byte) filter); + for (int j = 0; j < numColumns; j++) { + dos.write(bytes, offset, numBytes); + offset += numberOfInterleavedComponents; + } + offset = 0; + } + dos.close(); + IOUtils.copy(new ByteArrayInputStream(baos.toByteArray()), out); + } + } finally { + IOUtils.closeQuietly(in); + } + } + + /** {@inheritDoc} */ + public String getImplicitFilter() { + String filter = "<< /Predictor 15 /Columns " + image.getSize().getWidthPx(); + filter += " /Colors " + (numberOfInterleavedComponents > 2 ? 3 : 1); + filter += " /BitsPerComponent " + image.getBitDepth() + " >> /FlateDecode"; + return filter; + } +} diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java b/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java new file mode 100644 index 000000000..2a283e913 --- /dev/null +++ b/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java @@ -0,0 +1,111 @@ +/* + * 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.ps; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.io.IOException; + +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.ImageRawPNG; +import org.apache.xmlgraphics.ps.FormGenerator; +import org.apache.xmlgraphics.ps.ImageEncoder; +import org.apache.xmlgraphics.ps.ImageFormGenerator; +import org.apache.xmlgraphics.ps.PSGenerator; +import org.apache.xmlgraphics.ps.PSImageUtils; + +import org.apache.fop.render.RenderingContext; + +/** + * Image handler implementation which handles raw (not decoded) PNG images for PostScript output. + */ +public class PSImageHandlerRawPNG implements PSImageHandler { + + private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {ImageFlavor.RAW_PNG}; + + /** {@inheritDoc} */ + public void handleImage(RenderingContext context, Image image, Rectangle pos) throws IOException { + PSRenderingContext psContext = (PSRenderingContext) context; + PSGenerator gen = psContext.getGenerator(); + ImageRawPNG png = (ImageRawPNG) image; + + float x = (float) pos.getX() / 1000f; + float y = (float) pos.getY() / 1000f; + float w = (float) pos.getWidth() / 1000f; + float h = (float) pos.getHeight() / 1000f; + Rectangle2D targetRect = new Rectangle2D.Float(x, y, w, h); + + ImageEncoder encoder = new ImageEncoderPNG(png); + ImageInfo info = image.getInfo(); + Dimension imgDim = info.getSize().getDimensionPx(); + String imgDescription = image.getClass().getName(); + ColorModel cm = png.getColorModel(); + + PSImageUtils.writeImage(encoder, imgDim, imgDescription, targetRect, cm, gen); + } + + /** {@inheritDoc} */ + public void generateForm(RenderingContext context, Image image, PSImageFormResource form) + throws IOException { + PSRenderingContext psContext = (PSRenderingContext) context; + PSGenerator gen = psContext.getGenerator(); + ImageRawPNG png = (ImageRawPNG) image; + ImageInfo info = image.getInfo(); + String imageDescription = info.getMimeType() + " " + info.getOriginalURI(); + + ImageEncoder encoder = new ImageEncoderPNG(png); + FormGenerator formGen = new ImageFormGenerator(form.getName(), imageDescription, info.getSize() + .getDimensionPt(), info.getSize().getDimensionPx(), encoder, png.getColorSpace(), + false); + formGen.generate(gen); + } + + /** {@inheritDoc} */ + public int getPriority() { + return 200; + } + + /** {@inheritDoc} */ + public Class getSupportedImageClass() { + return ImageRawPNG.class; + } + + /** {@inheritDoc} */ + public ImageFlavor[] getSupportedImageFlavors() { + return FLAVORS; + } + + /** {@inheritDoc} */ + public boolean isCompatible(RenderingContext targetContext, Image image) { + if (targetContext instanceof PSRenderingContext) { + PSRenderingContext psContext = (PSRenderingContext) targetContext; + // The filters required for this implementation need PS level 2 or higher + if (psContext.getGenerator().getPSLevel() >= 2) { + return (image == null || image instanceof ImageRawPNG); + } + } + return false; + } + +} diff --git a/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java b/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java index 5a13c1c8e..46597e46d 100644 --- a/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java +++ b/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java @@ -19,7 +19,10 @@ package org.apache.fop.render.ps; +import java.awt.Dimension; import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; import java.awt.image.RenderedImage; import java.io.IOException; @@ -28,6 +31,8 @@ import org.apache.xmlgraphics.image.loader.ImageFlavor; import org.apache.xmlgraphics.image.loader.ImageInfo; import org.apache.xmlgraphics.image.loader.impl.ImageRendered; import org.apache.xmlgraphics.ps.FormGenerator; +import org.apache.xmlgraphics.ps.ImageEncoder; +import org.apache.xmlgraphics.ps.ImageEncodingHelper; import org.apache.xmlgraphics.ps.ImageFormGenerator; import org.apache.xmlgraphics.ps.PSGenerator; import org.apache.xmlgraphics.ps.PSImageUtils; @@ -47,17 +52,24 @@ public class PSImageHandlerRenderedImage implements PSImageHandler { /** {@inheritDoc} */ public void handleImage(RenderingContext context, Image image, Rectangle pos) throws IOException { - PSRenderingContext psContext = (PSRenderingContext)context; + PSRenderingContext psContext = (PSRenderingContext) context; PSGenerator gen = psContext.getGenerator(); - ImageRendered imageRend = (ImageRendered)image; + ImageRendered imageRend = (ImageRendered) image; - float x = (float)pos.getX() / 1000f; - float y = (float)pos.getY() / 1000f; - float w = (float)pos.getWidth() / 1000f; - float h = (float)pos.getHeight() / 1000f; + float x = (float) pos.getX() / 1000f; + float y = (float) pos.getY() / 1000f; + float w = (float) pos.getWidth() / 1000f; + float h = (float) pos.getHeight() / 1000f; + Rectangle2D targetRect = new Rectangle2D.Double(x, y, w, h); RenderedImage ri = imageRend.getRenderedImage(); - PSImageUtils.renderBitmapImage(ri, x, y, w, h, gen); + ImageEncoder encoder = ImageEncodingHelper.createRenderedImageEncoder(ri); + Dimension imgDim = new Dimension(ri.getWidth(), ri.getHeight()); + String imgDescription = ri.getClass().getName(); + ImageEncodingHelper helper = new ImageEncodingHelper(ri); + ColorModel cm = helper.getEncodedColorModel(); + + PSImageUtils.writeImage(encoder, imgDim, imgDescription, targetRect, cm, gen); } /** {@inheritDoc} */ diff --git a/status.xml b/status.xml index ba895efab..f96a9487b 100644 --- a/status.xml +++ b/status.xml @@ -63,6 +63,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Support use of ImageLoaderRawPNG decoder in order to prevent re-encoding of PNG images (and unnecssary output file bloat). + Eliminate incorrect use of object identity which produces excessive property cache collisions. diff --git a/test/java/org/apache/fop/render/RawPNGTestUtil.java b/test/java/org/apache/fop/render/RawPNGTestUtil.java new file mode 100644 index 000000000..e6660bb42 --- /dev/null +++ b/test/java/org/apache/fop/render/RawPNGTestUtil.java @@ -0,0 +1,92 @@ +/* + * 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; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; + +import org.apache.xmlgraphics.image.loader.ImageSize; + +public final class RawPNGTestUtil { + + private static int NUM_ROWS = 32; + private static int NUM_COLUMNS = 32; + private static int DPI = 72; + + private RawPNGTestUtil() { + + } + + /** + * Builds a PNG IDAT section for a square of a given color and alpha; the filter is fixed. + * @param gray the gray color; set to -1 if using RGB + * @param red the red color; ignored if gray > -1 + * @param green the green color; ignored if gray > -1 + * @param blue the blue color; ignored if gray > -1 + * @param alpha the alpha color; set to -1 if not present + * @return the PNG IDAT byte array + * @throws IOException + */ + public static byte[] buildGRGBAData(int gray, int red, int green, int blue, int alpha) throws IOException { + // build an image, 32x32, Gray or RGB, with or without alpha, and with filter + int filter = 0; + int numRows = NUM_ROWS; + int numColumns = NUM_COLUMNS; + int numComponents = (gray > -1 ? 1 : 3) + (alpha > -1 ? 1 : 0); + int numBytesPerRow = numColumns * numComponents + 1; // 1 for filter + int numBytes = numRows * numBytesPerRow; + byte[] data = new byte[numBytes]; + for (int r = 0; r < numRows; r++) { + data[r * numBytesPerRow] = (byte) filter; + for (int c = 0; c < numColumns; c++) { + if (numComponents == 1) { + data[r * numBytesPerRow + numComponents * c + 1] = (byte) gray; + } else if (numComponents == 2) { + data[r * numBytesPerRow + numComponents * c + 1] = (byte) gray; + data[r * numBytesPerRow + numComponents * c + 2] = (byte) alpha; + } else if (numComponents == 3) { + data[r * numBytesPerRow + numComponents * c + 1] = (byte) red; + data[r * numBytesPerRow + numComponents * c + 2] = (byte) green; + data[r * numBytesPerRow + numComponents * c + 3] = (byte) blue; + } else if (numComponents == 4) { + data[r * numBytesPerRow + numComponents * c + 1] = (byte) red; + data[r * numBytesPerRow + numComponents * c + 2] = (byte) green; + data[r * numBytesPerRow + numComponents * c + 3] = (byte) blue; + data[r * numBytesPerRow + numComponents * c + 4] = (byte) alpha; + } + } + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeflaterOutputStream dos = new DeflaterOutputStream(baos, new Deflater()); + dos.write(data); + dos.close(); + return baos.toByteArray(); + } + + /** + * + * @return a default ImageSize + */ + public static ImageSize getImageSize() { + return new ImageSize(NUM_ROWS, NUM_COLUMNS, DPI); + } +} diff --git a/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java b/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java new file mode 100644 index 000000000..885821f66 --- /dev/null +++ b/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java @@ -0,0 +1,142 @@ +/* + * 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.pdf; + +import java.awt.image.ComponentColorModel; +import java.awt.image.IndexColorModel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.zip.Deflater; +import java.util.zip.DeflaterOutputStream; + +import org.junit.Test; + +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRawPNG; + +import org.apache.fop.pdf.FlateFilter; +import org.apache.fop.pdf.PDFAMode; +import org.apache.fop.pdf.PDFDocument; +import org.apache.fop.pdf.PDFProfile; +import org.apache.fop.render.RawPNGTestUtil; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ImageRawPNGAdapterTestCase { + + @Test + public void testSetupWithIndexColorModel() { + IndexColorModel cm = mock(IndexColorModel.class); + ImageRawPNG irpng = mock(ImageRawPNG.class); + PDFDocument doc = mock(PDFDocument.class); + PDFProfile profile = mock(PDFProfile.class); + ImageRawPNGAdapter irpnga = new ImageRawPNGAdapter(irpng, "mock"); + ImageSize is = RawPNGTestUtil.getImageSize(); + + when(irpng.getColorModel()).thenReturn(cm); + // when(cm.hasAlpha()).thenReturn(false); + when(doc.getProfile()).thenReturn(profile); + when(profile.getPDFAMode()).thenReturn(PDFAMode.PDFA_1A); + when(irpng.getSize()).thenReturn(is); + irpnga.setup(doc); + FlateFilter filter = (FlateFilter) irpnga.getPDFFilter(); + assertEquals(1, filter.getColors()); + } + + @Test + public void testSetupWithComponentColorModel() throws IOException { + ComponentColorModel cm = mock(ComponentColorModel.class); + ImageRawPNG irpng = mock(ImageRawPNG.class); + PDFDocument doc = mock(PDFDocument.class); + PDFProfile profile = mock(PDFProfile.class); + ImageRawPNGAdapter irpnga = new ImageRawPNGAdapter(irpng, "mock"); + ImageSize is = RawPNGTestUtil.getImageSize(); + + when(irpng.getColorModel()).thenReturn(cm); + when(cm.getNumComponents()).thenReturn(3); + // when(cm.hasAlpha()).thenReturn(false); + when(doc.getProfile()).thenReturn(profile); + when(profile.getPDFAMode()).thenReturn(PDFAMode.PDFA_1A); + when(irpng.getSize()).thenReturn(is); + irpnga.setup(doc); + FlateFilter filter = (FlateFilter) irpnga.getPDFFilter(); + assertEquals(3, filter.getColors()); + } + + @Test + public void testOutputContentsWithRGBPNG() throws IOException { + testOutputContentsWithGRGBAPNG(-1, 128, 128, 128, -1); + } + + @Test + public void testOutputContentsWithRGBAPNG() throws IOException { + testOutputContentsWithGRGBAPNG(-1, 128, 128, 128, 128); + } + + @Test + public void testOutputContentsWithGPNG() throws IOException { + testOutputContentsWithGRGBAPNG(128, -1, -1, -1, -1); + } + + @Test + public void testOutputContentsWithGAPNG() throws IOException { + testOutputContentsWithGRGBAPNG(128, -1, -1, -1, 128); + } + + private void testOutputContentsWithGRGBAPNG(int gray, int red, int green, int blue, int alpha) + throws IOException { + int numColorComponents = gray > -1 ? 1 : 3; + int numComponents = numColorComponents + (alpha > -1 ? 1 : 0); + ComponentColorModel cm = mock(ComponentColorModel.class); + ImageRawPNG irpng = mock(ImageRawPNG.class); + PDFDocument doc = mock(PDFDocument.class); + PDFProfile profile = mock(PDFProfile.class); + ImageRawPNGAdapter irpnga = new ImageRawPNGAdapter(irpng, "mock"); + ImageSize is = RawPNGTestUtil.getImageSize(); + + when(irpng.getColorModel()).thenReturn(cm); + when(cm.getNumComponents()).thenReturn(numComponents); + // when(cm.hasAlpha()).thenReturn(false); + when(doc.getProfile()).thenReturn(profile); + when(profile.getPDFAMode()).thenReturn(PDFAMode.PDFA_1A); + when(irpng.getSize()).thenReturn(is); + irpnga.setup(doc); + FlateFilter filter = (FlateFilter) irpnga.getPDFFilter(); + assertEquals(numColorComponents, filter.getColors()); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] data = RawPNGTestUtil.buildGRGBAData(gray, red, green, blue, alpha); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + when(irpng.createInputStream()).thenReturn(bais); + irpnga.outputContents(baos); + if (alpha > -1) { + byte[] expected = RawPNGTestUtil.buildGRGBAData(gray, red, green, blue, -1); + assertArrayEquals(expected, baos.toByteArray()); + } else { + assertArrayEquals(data, baos.toByteArray()); + } + } + +} diff --git a/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java b/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java new file mode 100644 index 000000000..458033dad --- /dev/null +++ b/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java @@ -0,0 +1,133 @@ +/* + * 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.ps; + +import java.awt.image.ComponentColorModel; +import java.awt.image.IndexColorModel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.junit.Test; + +import org.apache.xmlgraphics.image.loader.ImageSize; +import org.apache.xmlgraphics.image.loader.impl.ImageRawPNG; + +import org.apache.fop.render.RawPNGTestUtil; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ImageEncoderPNGTestCase { + + @Test + public void testWriteToWithRGBPNG() throws IOException { + testWriteToWithGRGBAPNG(-1, 128, 128, 128, -1); + } + + @Test + public void testWriteToWithGPNG() throws IOException { + testWriteToWithGRGBAPNG(128, -1, -1, -1, -1); + } + + @Test + public void testWriteToWithRGBAPNG() throws IOException { + testWriteToWithGRGBAPNG(-1, 128, 128, 128, 128); + } + + @Test + public void testWriteToWithGAPNG() throws IOException { + testWriteToWithGRGBAPNG(128, -1, -1, -1, 128); + } + + private void testWriteToWithGRGBAPNG(int gray, int red, int green, int blue, int alpha) + throws IOException { + int numComponents = (gray > -1 ? 1 : 3) + (alpha > -1 ? 1 : 0); + ImageSize is = RawPNGTestUtil.getImageSize(); + ComponentColorModel cm = mock(ComponentColorModel.class); + when(cm.getNumComponents()).thenReturn(numComponents); + ImageRawPNG irpng = mock(ImageRawPNG.class); + when(irpng.getColorModel()).thenReturn(cm); + when(irpng.getSize()).thenReturn(is); + ImageEncoderPNG iepng = new ImageEncoderPNG(irpng); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] data = RawPNGTestUtil.buildGRGBAData(gray, red, green, blue, alpha); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + when(irpng.createInputStream()).thenReturn(bais); + iepng.writeTo(baos); + if (alpha > -1) { + byte[] expected = RawPNGTestUtil.buildGRGBAData(gray, red, green, blue, -1); + assertArrayEquals(expected, baos.toByteArray()); + } else { + assertArrayEquals(data, baos.toByteArray()); + } + } + + @Test + public void testWriteToWithPalettePNG() throws IOException { + ImageSize is = RawPNGTestUtil.getImageSize(); + IndexColorModel cm = mock(IndexColorModel.class); + ImageRawPNG irpng = mock(ImageRawPNG.class); + when(irpng.getColorModel()).thenReturn(cm); + when(irpng.getSize()).thenReturn(is); + ImageEncoderPNG iepng = new ImageEncoderPNG(irpng); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] data = RawPNGTestUtil.buildGRGBAData(128, -1, -1, -1, -1); + ByteArrayInputStream bais = new ByteArrayInputStream(data); + when(irpng.createInputStream()).thenReturn(bais); + iepng.writeTo(baos); + assertArrayEquals(data, baos.toByteArray()); + } + + @Test + public void testGetImplicitFilterWithIndexColorModel() { + ImageSize is = RawPNGTestUtil.getImageSize(); + IndexColorModel cm = mock(IndexColorModel.class); + ImageRawPNG irpng = mock(ImageRawPNG.class); + when(irpng.getColorModel()).thenReturn(cm); + when(irpng.getBitDepth()).thenReturn(8); + when(irpng.getSize()).thenReturn(is); + ImageEncoderPNG iepng = new ImageEncoderPNG(irpng); + + String expectedFilter = "<< /Predictor 15 /Columns 32 /Colors 1 /BitsPerComponent 8 >> /FlateDecode"; + assertEquals(expectedFilter, iepng.getImplicitFilter()); + } + + @Test + public void testGetImplicitFilterWithComponentColorModel() { + ImageSize is = RawPNGTestUtil.getImageSize(); + ComponentColorModel cm = mock(ComponentColorModel.class); + when(cm.getNumComponents()).thenReturn(3); + ImageRawPNG irpng = mock(ImageRawPNG.class); + when(irpng.getColorModel()).thenReturn(cm); + when(irpng.getBitDepth()).thenReturn(8); + when(irpng.getSize()).thenReturn(is); + ImageEncoderPNG iepng = new ImageEncoderPNG(irpng); + + String expectedFilter = "<< /Predictor 15 /Columns 32 /Colors 3 /BitsPerComponent 8 >> /FlateDecode"; + assertEquals(expectedFilter, iepng.getImplicitFilter()); + } + +} -- 2.39.5