You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2020/08/21 17:21:09 UTC

svn commit: r1881063 - in /pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image: PNGConverterTest.java ValidateXImage.java

Author: tilman
Date: Fri Aug 21 17:21:09 2020
New Revision: 1881063

URL: http://svn.apache.org/viewvc?rev=1881063&view=rev
Log:
PDFBOX-4847: convert non sRGB images to sRGB and enable testImageConversionRGB16BitICC, by Emmeran Seehuber

Modified:
    pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java
    pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java

Modified: pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java?rev=1881063&r1=1881062&r2=1881063&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java Fri Aug 21 17:21:09 2020
@@ -17,14 +17,19 @@
 package org.apache.pdfbox.pdmodel.graphics.image;
 
 import java.awt.Color;
+import java.awt.color.ICC_ColorSpace;
 import java.awt.color.ICC_Profile;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.WritableRaster;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.Hashtable;
 import javax.imageio.ImageIO;
 
 import org.apache.pdfbox.cos.COSName;
@@ -37,6 +42,7 @@ import org.apache.pdfbox.pdmodel.graphic
 import static org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage.checkIdent;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import org.junit.Before;
@@ -87,7 +93,7 @@ public class PNGConverterTest
         checkImageConvert("png_rgb_gamma.png");
     }
 
-    // @Test
+    @Test
     public void testImageConversionRGB16BitICC() throws IOException
     {
         checkImageConvert("png_rgb_romm_16bit.png");
@@ -165,11 +171,14 @@ public class PNGConverterTest
         PDDocument doc = new PDDocument();
         byte[] imageBytes = IOUtils.toByteArray(PNGConverterTest.class.getResourceAsStream(name));
         PDImageXObject pdImageXObject = PNGConverter.convertPNGImage(doc, imageBytes);
+        assertNotNull(pdImageXObject);
+
+        ICC_Profile imageProfile = null;
         if (pdImageXObject.getColorSpace() instanceof PDICCBased)
         {
             // Make sure that ICC profile is a valid one
             PDICCBased iccColorSpace = (PDICCBased) pdImageXObject.getColorSpace();
-            ICC_Profile.getInstance(iccColorSpace.getPDStream().toByteArray());
+            imageProfile = ICC_Profile.getInstance(iccColorSpace.getPDStream().toByteArray());
         }
         PDPage page = new PDPage();
         doc.addPage(page);
@@ -183,10 +192,45 @@ public class PNGConverterTest
         contentStream.close();
         doc.save(new File(parentDir, name + ".pdf"));
         BufferedImage image = pdImageXObject.getImage();
-        checkIdent(ImageIO.read(new ByteArrayInputStream(imageBytes)), image);
+
+        BufferedImage expectedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
+        if (imageProfile != null && expectedImage.getColorModel().getColorSpace().isCS_sRGB())
+        {
+            // The image has an embedded ICC Profile, but the default java PNG
+            // reader does not correctly read that.
+            expectedImage = getImageWithProfileData(expectedImage, imageProfile);
+        }
+
+        checkIdent(expectedImage, image);
+
         doc.close();
     }
 
+    public static BufferedImage getImageWithProfileData(BufferedImage sourceImage,
+             ICC_Profile realProfile)
+    {
+        Hashtable<String, Object> properties = new Hashtable<String, Object>();
+        String[] propertyNames = sourceImage.getPropertyNames();
+        if (propertyNames != null)
+        {
+            for (String propertyName : propertyNames)
+            {
+                properties.put(propertyName, sourceImage.getProperty(propertyName));
+            }
+        }
+        ComponentColorModel oldColorModel = (ComponentColorModel) sourceImage.getColorModel();
+        boolean hasAlpha = oldColorModel.hasAlpha();
+        int transparency = oldColorModel.getTransparency();
+        boolean alphaPremultiplied = oldColorModel.isAlphaPremultiplied();
+        WritableRaster raster = sourceImage.getRaster();
+        int dataType = raster.getDataBuffer().getDataType();
+        int[] componentSize = oldColorModel.getComponentSize();
+        final ColorModel colorModel = new ComponentColorModel(new ICC_ColorSpace(realProfile),
+                componentSize, hasAlpha, alphaPremultiplied, transparency, dataType);
+        return new BufferedImage(colorModel, raster, sourceImage.isAlphaPremultiplied(),
+                properties);
+    }
+
     @Test
     public void testCheckConverterState()
     {

Modified: pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java?rev=1881063&r1=1881062&r2=1881063&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java Fri Aug 21 17:21:09 2020
@@ -15,15 +15,24 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.image;
 
+import java.awt.Point;
+import java.awt.color.ColorSpace;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.DataBuffer;
+import java.awt.image.DirectColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.Set;
 import javax.imageio.ImageIO;
 import javax.imageio.ImageWriter;
 import javax.imageio.spi.ImageWriterSpi;
+import static junit.framework.TestCase.assertEquals;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.PDDocument;
@@ -32,7 +41,6 @@ import org.apache.pdfbox.pdmodel.PDPageC
 import org.apache.pdfbox.rendering.PDFRenderer;
 import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
 
-import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertNotNull;
 import static junit.framework.TestCase.assertTrue;
 
@@ -155,6 +163,9 @@ public class ValidateXImage
     {
         String errMsg = "";
 
+        expectedImage = convertToSRGB(expectedImage);
+        actualImage = convertToSRGB(actualImage);
+
         int w = expectedImage.getWidth();
         int h = expectedImage.getHeight();
         assertEquals(w, actualImage.getWidth());
@@ -171,7 +182,73 @@ public class ValidateXImage
             }
         }
     }
-
     
+    public static BufferedImage convertToSRGB(BufferedImage image)
+    {
+        // The image is already sRGB - we don't need to do anything
+        if (image.getColorModel().getColorSpace().isCS_sRGB())
+        {
+            return image;
+        }
+        // 16-Bit images need to converted to 8 bit first, to avoid rounding differences
+        if (image.getRaster().getDataBuffer().getDataType() == DataBuffer.TYPE_USHORT)
+        {
+            final int width = image.getWidth();
+            final boolean hasAlpha = image.getColorModel().hasAlpha();
+
+            final DirectColorModel colorModel = new DirectColorModel(
+                    image.getColorModel().getColorSpace(), 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000,
+                    false, DataBuffer.TYPE_INT);
+            WritableRaster targetRaster = Raster
+                    .createPackedRaster(DataBuffer.TYPE_INT, image.getWidth(), image.getHeight(),
+                            colorModel.getMasks(), new Point(0, 0));
 
+            BufferedImage image8Bit = new BufferedImage(colorModel, targetRaster, false,
+                    new Hashtable<String, Object>());
+
+            WritableRaster sourceRaster = image.getRaster();
+
+            final int numShortPixelElements = hasAlpha ? 3 : 4;
+            // 3 or 4 short per pixel
+            short[] pixelShort = new short[numShortPixelElements * width];
+            // Packed RGB
+            int[] pixelInt = new int[width];
+            for (int y = 0; y < image.getHeight(); y++)
+            {
+                sourceRaster.getDataElements(0, y, width, 1, pixelShort);
+                int ptrShort = 0;
+                for (int x = 0; x < width; x++)
+                {
+                    int r = pixelShort[ptrShort++] & 0xFFFF;
+                    int g = pixelShort[ptrShort++] & 0xFFFF;
+                    int b = pixelShort[ptrShort++] & 0xFFFF;
+                    if (hasAlpha)
+                        ptrShort++;
+
+                    // We devide using a float exactly the same way as SampledImageReader
+                    // to get from 16 bit to 8 bit sample values
+                    int r8bit = convert16To8Bit(r);
+                    int g8bit = convert16To8Bit(g);
+                    int b8bit = convert16To8Bit(b);
+                    int v = r8bit | (g8bit << 8) | (b8bit << 16) | 0xFF000000;
+                    pixelInt[x] = v;
+                }
+                targetRaster.setDataElements(0, y, width, 1, pixelInt);
+
+            }
+            image = image8Bit;
+
+        }
+
+        BufferedImage destination = new BufferedImage(image.getWidth(), image.getHeight(),
+                BufferedImage.TYPE_INT_RGB);
+        ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null);
+        return op.filter(image, destination);
+    }
+
+    private static int convert16To8Bit(int v)
+    {
+        float output = (float) v / (float) 0xFFFF;
+        return Math.round(output * 0xFF);
+    }
 }