You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by ga...@apache.org on 2012/06/15 04:56:22 UTC

svn commit: r1350455 - in /xmlgraphics/fop/trunk: ./ lib/ src/java/META-INF/services/ src/java/org/apache/fop/pdf/ src/java/org/apache/fop/render/pdf/ src/java/org/apache/fop/render/ps/ test/java/org/apache/fop/render/ test/java/org/apache/fop/render/p...

Author: gadams
Date: Fri Jun 15 02:56:21 2012
New Revision: 1350455

URL: http://svn.apache.org/viewvc?rev=1350455&view=rev
Log:
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.

Added:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java
      - copied, changed from r1350379, xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
    xmlgraphics/fop/trunk/test/java/org/apache/fop/render/RawPNGTestUtil.java
    xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java
    xmlgraphics/fop/trunk/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java
Modified:
    xmlgraphics/fop/trunk/lib/xmlgraphics-commons-1.5svn.jar
    xmlgraphics/fop/trunk/src/java/META-INF/services/org.apache.fop.render.ImageHandler
    xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/BitmapImage.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
    xmlgraphics/fop/trunk/status.xml

Modified: xmlgraphics/fop/trunk/lib/xmlgraphics-commons-1.5svn.jar
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/lib/xmlgraphics-commons-1.5svn.jar?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
Binary files - no diff available.

Modified: xmlgraphics/fop/trunk/src/java/META-INF/services/org.apache.fop.render.ImageHandler
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/META-INF/services/org.apache.fop.render.ImageHandler?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/META-INF/services/org.apache.fop.render.ImageHandler (original)
+++ xmlgraphics/fop/trunk/src/java/META-INF/services/org.apache.fop.render.ImageHandler Fri Jun 15 02:56:21 2012
@@ -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.PSImageHandlerR
 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

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/BitmapImage.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/BitmapImage.java?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/BitmapImage.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/pdf/BitmapImage.java Fri Jun 15 02:56:21 2012
@@ -37,6 +37,7 @@ public class BitmapImage implements PDFI
     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 PDFI
      * {@inheritDoc}
      */
     public PDFFilter getPDFFilter() {
-        return null;
+        return pdfFilter;
     }
 
+    public void setPDFFilter(PDFFilter pdfFilter) {
+        this.pdfFilter = pdfFilter;
+    }
 }
 
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/AbstractImageAdapter.java Fri Jun 15 02:56:21 2012
@@ -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 AbstractImageAdapt
     /** 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 @@ public abstract class AbstractImageAdapt
     }
 
     /**
+     * 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

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRawPNGAdapter.java Fri Jun 15 02:56:21 2012
@@ -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);
+        }
+    }
+}

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/ImageRenderedAdapter.java Fri Jun 15 02:56:21 2012
@@ -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.load
 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 extend
         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 extend
         }
     }
 
-    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);
         }
     }
 

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/pdf/PDFImageHandlerRawPNG.java Fri Jun 15 02:56:21 2012
@@ -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;
+    }
+
+}

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/ImageEncoderPNG.java Fri Jun 15 02:56:21 2012
@@ -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;
+    }
+}

Copied: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java (from r1350379, xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java)
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java?p2=xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java&p1=xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java&r1=1350379&r2=1350455&rev=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRawPNG.java Fri Jun 15 02:56:21 2012
@@ -19,15 +19,18 @@
 
 package org.apache.fop.render.ps;
 
+import java.awt.Dimension;
 import java.awt.Rectangle;
-import java.awt.image.RenderedImage;
+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.ImageRendered;
+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;
@@ -35,56 +38,57 @@ import org.apache.xmlgraphics.ps.PSImage
 import org.apache.fop.render.RenderingContext;
 
 /**
- * Image handler implementation which handles RenderedImage instances for PostScript output.
+ * Image handler implementation which handles raw (not decoded) PNG images for PostScript output.
  */
-public class PSImageHandlerRenderedImage implements PSImageHandler {
+public class PSImageHandlerRawPNG implements PSImageHandler {
 
-    private static final ImageFlavor[] FLAVORS = new ImageFlavor[] {
-        ImageFlavor.BUFFERED_IMAGE,
-        ImageFlavor.RENDERED_IMAGE
-    };
+    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;
+    public void handleImage(RenderingContext context, Image image, Rectangle pos) throws IOException {
+        PSRenderingContext psContext = (PSRenderingContext) context;
         PSGenerator gen = psContext.getGenerator();
-        ImageRendered imageRend = (ImageRendered)image;
+        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;
+        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);
 
-        RenderedImage ri = imageRend.getRenderedImage();
-        PSImageUtils.renderBitmapImage(ri, x, y, w, h, gen);
+        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;
+        PSRenderingContext psContext = (PSRenderingContext) context;
         PSGenerator gen = psContext.getGenerator();
-        ImageRendered imageRend = (ImageRendered)image;
+        ImageRawPNG png = (ImageRawPNG) image;
         ImageInfo info = image.getInfo();
         String imageDescription = info.getMimeType() + " " + info.getOriginalURI();
 
-        RenderedImage ri = imageRend.getRenderedImage();
-        FormGenerator formGen = new ImageFormGenerator(
-                form.getName(), imageDescription,
-                info.getSize().getDimensionPt(),
-                ri, false);
+        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 300;
+        return 200;
     }
 
     /** {@inheritDoc} */
-    public Class getSupportedImageClass() {
-        return ImageRendered.class;
+    public Class<ImageRawPNG> getSupportedImageClass() {
+        return ImageRawPNG.class;
     }
 
     /** {@inheritDoc} */
@@ -94,8 +98,14 @@ public class PSImageHandlerRenderedImage
 
     /** {@inheritDoc} */
     public boolean isCompatible(RenderingContext targetContext, Image image) {
-        return (image == null || image instanceof ImageRendered)
-                && targetContext instanceof PSRenderingContext;
+        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;
     }
 
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/render/ps/PSImageHandlerRenderedImage.java Fri Jun 15 02:56:21 2012
@@ -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.load
 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
     /** {@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} */

Modified: xmlgraphics/fop/trunk/status.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/status.xml?rev=1350455&r1=1350454&r2=1350455&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/status.xml (original)
+++ xmlgraphics/fop/trunk/status.xml Fri Jun 15 02:56:21 2012
@@ -63,6 +63,9 @@
       documents. Example: the fix of marks layering will be such a case when it's done.
     -->
     <release version="FOP Trunk" date="TBD">
+      <action context="Images" dev="GA" type="fix" fixes-bug="40676" due-to="Luis Bernardo, Matthias Reischenbacher">
+        Support use of ImageLoaderRawPNG decoder in order to prevent re-encoding of PNG images (and unnecssary output file bloat).
+      </action>
       <action context="Code" dev="GA" type="fix" fixes-bug="53412" due-to="Alexios Giotis">
         Eliminate incorrect use of object identity which produces excessive property cache collisions.
       </action>

Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/render/RawPNGTestUtil.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/render/RawPNGTestUtil.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/render/RawPNGTestUtil.java (added)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/render/RawPNGTestUtil.java Fri Jun 15 02:56:21 2012
@@ -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);
+    }
+}

Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java (added)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/render/pdf/ImageRawPNGAdapterTestCase.java Fri Jun 15 02:56:21 2012
@@ -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());
+        }
+    }
+
+}

Added: xmlgraphics/fop/trunk/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java?rev=1350455&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java (added)
+++ xmlgraphics/fop/trunk/test/java/org/apache/fop/render/ps/ImageEncoderPNGTestCase.java Fri Jun 15 02:56:21 2012
@@ -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());
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org