ASF Bugzilla – Attachment 28929 Details for
Bug 40676
[PATCH] png graphics are expanded/uncompressed in pdf causing massive file size increase
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
patch
apachefop.patch (text/plain), 51.04 KB, created by
Luis Bernardo
on 2012-06-13 13:06:12 UTC
(
hide
)
Description:
patch
Filename:
MIME Type:
Creator:
Luis Bernardo
Created:
2012-06-13 13:06:12 UTC
Size:
51.04 KB
patch
obsolete
>Index: src/java/META-INF/services/org.apache.fop.render.ImageHandler >=================================================================== >--- src/java/META-INF/services/org.apache.fop.render.ImageHandler (revision 1342235) >+++ src/java/META-INF/services/org.apache.fop.render.ImageHandler (working copy) >@@ -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.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 >Index: src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java >=================================================================== >--- src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java (revision 0) >+++ src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java (revision 0) >@@ -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<ImageRawPNG> 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; >+ } >+ >+} >Index: src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java >=================================================================== >--- src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java (revision 0) >+++ src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java (revision 0) >@@ -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); >+ } >+ } >+} >Index: src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java >=================================================================== >--- src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java (revision 1348759) >+++ src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java (working copy) >@@ -36,14 +36,12 @@ > 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 +160,6 @@ > 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 +204,13 @@ > } > } > >- 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); > } > } > >Index: src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java >=================================================================== >--- src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java (revision 1348759) >+++ src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java (working copy) >@@ -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 @@ > /** 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. >@@ -203,6 +208,68 @@ > } > > /** >+ * 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 > * @return PDFColorSpace new converted object >Index: src/java/org/apache/fop/render/ps/ImageEncoderPNG.java >=================================================================== >--- src/java/org/apache/fop/render/ps/ImageEncoderPNG.java (revision 0) >+++ src/java/org/apache/fop/render/ps/ImageEncoderPNG.java (revision 0) >@@ -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; >+ } >+} >Index: src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java >=================================================================== >--- src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java (revision 1348759) >+++ src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java (working copy) >@@ -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.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 @@ > /** {@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} */ >Index: src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java >=================================================================== >--- src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java (revision 0) >+++ src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java (revision 0) >@@ -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<ImageRawPNG> 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; >+ } >+ >+} >Index: src/java/org/apache/fop/pdf/BitmapImage.java >=================================================================== >--- src/java/org/apache/fop/pdf/BitmapImage.java (revision 1348759) >+++ src/java/org/apache/fop/pdf/BitmapImage.java (working copy) >@@ -37,6 +37,7 @@ > private PDFColor transparent = null; > private String key; > private PDFDocument pdfDoc; >+ private PDFFilter pdfFilter; > > /** > * Create a bitmap image. >@@ -208,9 +209,12 @@ > * {@inheritDoc} > */ > public PDFFilter getPDFFilter() { >- return null; >+ return pdfFilter; > } > >+ public void setPDFFilter(PDFFilter pdfFilter) { >+ this.pdfFilter = pdfFilter; >+ } > } > > >Index: test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java >=================================================================== >--- test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java (revision 0) >+++ test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java (revision 0) >@@ -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()); >+ } >+ } >+ >+} >Index: test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java >=================================================================== >--- test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java (revision 0) >+++ test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java (revision 0) >@@ -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()); >+ } >+ >+} >Index: test/java/org/apache/fop/render/RawPNGTestUtil.java >=================================================================== >--- test/java/org/apache/fop/render/RawPNGTestUtil.java (revision 0) >+++ test/java/org/apache/fop/render/RawPNGTestUtil.java (revision 0) >@@ -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); >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 40676
:
28771
| 28929 |
28930
|
28932
|
28944
|
28950
|
28988
|
28989
|
28990
|
29132
|
29133
|
29134
|
29135
|
29136