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/29 11:32:15 UTC

svn commit: r1881293 - in /pdfbox/branches/issue45/pdfbox/src: main/java/org/apache/pdfbox/pdmodel/graphics/color/ main/java/org/apache/pdfbox/pdmodel/graphics/image/ test/java/org/apache/pdfbox/pdmodel/graphics/image/

Author: tilman
Date: Sat Aug 29 11:32:15 2020
New Revision: 1881293

URL: http://svn.apache.org/viewvc?rev=1881293&view=rev
Log:
PDFBOX-4847: implements (optional) access to raw images as BufferedImage, by Emmeran Seehuber

Modified:
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceGray.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDIndexed.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
    pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java
    pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java
    pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java
    pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDCIEBasedColorSpace.java Sat Aug 29 11:32:15 2020
@@ -1,80 +1,88 @@
-/*
- * 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.
- */
-package org.apache.pdfbox.pdmodel.graphics.color;
-
-import java.awt.image.BufferedImage;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-
-/**
- * CIE-based colour spaces specify colours in a way that is independent of the characteristics
- * of any particular output device. They are based on an international standard for colour
- * specification created by the Commission Internationale de l'Éclairage (CIE).
- *
- * @author John Hewson
- */
-public abstract class PDCIEBasedColorSpace extends PDColorSpace
-{
-    //
-    // WARNING: this method is performance sensitive, modify with care!
-    //
-    @Override
-    public BufferedImage toRGBImage(WritableRaster raster) throws IOException
-    {
-        // This method calls toRGB to convert images one pixel at a time. For matrix-based
-        // CIE color spaces this is fast enough. However, it should not be used with any
-        // color space which uses an ICC Profile as it will be far too slow.
-
-        int width = raster.getWidth();
-        int height = raster.getHeight();
-
-        BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
-        WritableRaster rgbRaster = rgbImage.getRaster();
-
-        // always three components: ABC
-        float[] abc = new float[3];
-        for (int y = 0; y < height; y++)
-        {
-            for (int x = 0; x < width; x++)
-            {
-                raster.getPixel(x, y, abc);
-
-                // 0..255 -> 0..1
-                abc[0] /= 255;
-                abc[1] /= 255;
-                abc[2] /= 255;
-
-                float[] rgb = toRGB(abc);
-
-                // 0..1 -> 0..255
-                rgb[0] *= 255;
-                rgb[1] *= 255;
-                rgb[2] *= 255;
-
-                rgbRaster.setPixel(x, y, rgb);
-            }
-        }
-
-        return rgbImage;
-    }
-
-    @Override
-    public String toString()
-    {
-        return getName();   // TODO return more info
-    }
-}
+/*
+ * 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.
+ */
+package org.apache.pdfbox.pdmodel.graphics.color;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+/**
+ * CIE-based colour spaces specify colours in a way that is independent of the characteristics
+ * of any particular output device. They are based on an international standard for colour
+ * specification created by the Commission Internationale de l'Éclairage (CIE).
+ *
+ * @author John Hewson
+ */
+public abstract class PDCIEBasedColorSpace extends PDColorSpace
+{
+    //
+    // WARNING: this method is performance sensitive, modify with care!
+    //
+    @Override
+    public BufferedImage toRGBImage(WritableRaster raster) throws IOException
+    {
+        // This method calls toRGB to convert images one pixel at a time. For matrix-based
+        // CIE color spaces this is fast enough. However, it should not be used with any
+        // color space which uses an ICC Profile as it will be far too slow.
+
+        int width = raster.getWidth();
+        int height = raster.getHeight();
+
+        BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        WritableRaster rgbRaster = rgbImage.getRaster();
+
+        // always three components: ABC
+        float[] abc = new float[3];
+        for (int y = 0; y < height; y++)
+        {
+            for (int x = 0; x < width; x++)
+            {
+                raster.getPixel(x, y, abc);
+
+                // 0..255 -> 0..1
+                abc[0] /= 255;
+                abc[1] /= 255;
+                abc[2] /= 255;
+
+                float[] rgb = toRGB(abc);
+
+                // 0..1 -> 0..255
+                rgb[0] *= 255;
+                rgb[1] *= 255;
+                rgb[2] *= 255;
+
+                rgbRaster.setPixel(x, y, rgb);
+            }
+        }
+
+        return rgbImage;
+    }
+
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        // There is no direct equivalent of a CIE colorspace in Java. So we can
+        // not do anything here.
+        return null;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getName();   // TODO return more info
+    }
+}

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDColorSpace.java Sat Aug 29 11:32:15 2020
@@ -298,6 +298,35 @@ public abstract class PDColorSpace imple
     public abstract BufferedImage toRGBImage(WritableRaster raster) throws IOException;
 
     /**
+     * Returns the image in this colorspace or null. No conversion is performed.
+     *
+     * For special colorspaces like PDSeparation the image is returned in the gray colorspace.
+     * For undefined colorspaces like DeviceCMYK/DeviceRGB and DeviceGray null is returned.
+     *
+     * You can always fallback to {@link #toRGBImage(WritableRaster)} if this returns null.
+     *
+     * @param raster the source raster
+     * @return an buffered image in this colorspace. Or null if it is not possible to extract
+     * that image with the original colorspace without conversion.
+     */
+    public abstract BufferedImage toRawImage(WritableRaster raster) throws IOException;
+
+    /**
+     * Returns the given raster as BufferedImage with the given awtColorSpace using a
+     * ComponentColorModel.
+     * @param raster the source raster
+     * @param awtColorSpace the AWT colorspace
+     * @return a BufferedImage in this colorspace
+     */
+    protected final BufferedImage toRawImage(WritableRaster raster, ColorSpace awtColorSpace)
+    {
+        ColorModel colorModel = new ComponentColorModel(awtColorSpace,
+                false, false, Transparency.OPAQUE, raster.getDataBuffer().getDataType());
+        return new BufferedImage(colorModel, raster, false, null);
+    }
+
+
+    /**
      * Returns the (A)RGB equivalent of the given raster, using the given AWT color space
      * to perform the conversion.
      * @param raster the source raster

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceCMYK.java Sat Aug 29 11:32:15 2020
@@ -136,6 +136,14 @@ public class PDDeviceCMYK extends PDDevi
     }
 
     @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        // Device CMYK is not specified, as its the colors of whatever device you use.
+        // The user should fallback to the RGB image
+        return null;
+    }
+
+    @Override
     public BufferedImage toRGBImage(WritableRaster raster) throws IOException
     {
         init();

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceGray.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceGray.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceGray.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceGray.java Sat Aug 29 11:32:15 2020
@@ -70,6 +70,14 @@ public final class PDDeviceGray extends
     }
 
     @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        // DeviceGray is whatever the output device chooses. We have no Java colorspace
+        // for this.
+        return null;
+    }
+
+    @Override
     public BufferedImage toRGBImage(WritableRaster raster) throws IOException
     {
         int width = raster.getWidth();

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java Sat Aug 29 11:32:15 2020
@@ -414,6 +414,13 @@ public class PDDeviceN extends PDSpecial
         return alternateColorSpace.toRGB(altValue);
     }
 
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster)
+    {
+        // We don't know how to convert that.
+        return null;
+    }
+
     /**
      * Returns true if this color space has the NChannel subtype.
      * @return true if subtype is NChannel

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceRGB.java Sat Aug 29 11:32:15 2020
@@ -117,4 +117,12 @@ public final class PDDeviceRGB extends P
         image.setData(raster);
         return image;
     }
+
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        // Device RGB is not specified, as its the colors of whatever device you use. The user
+        // should use the toRGBImage().
+        return null;
+    }
 }

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDICCBased.java Sat Aug 29 11:32:15 2020
@@ -381,6 +381,16 @@ public final class PDICCBased extends PD
     }
 
     @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        if(awtColorSpace == null)
+        {
+            return alternateColorSpace.toRawImage(raster);
+        }
+        return toRawImage(raster, awtColorSpace);
+    }
+
+    @Override
     public int getNumberOfComponents()
     {
         if (numberOfComponents < 0)
@@ -595,6 +605,15 @@ public final class PDICCBased extends PD
         stream.getCOSObject().setItem(COSName.METADATA, metadata);
     }
 
+    /**
+     * Internal accessor to support indexed raw images.
+     * @return true if this colorspace is sRGB.
+     */
+    boolean isSRGB()
+    {
+        return isRGB;
+    }
+
     @Override
     public String toString()
     {

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDIndexed.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDIndexed.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDIndexed.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDIndexed.java Sat Aug 29 11:32:15 2020
@@ -18,7 +18,9 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Point;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
 import java.awt.image.DataBuffer;
+import java.awt.image.IndexColorModel;
 import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
 import java.io.IOException;
@@ -210,6 +212,32 @@ public final class PDIndexed extends PDS
         return rgbImage;
     }
 
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster)
+    {
+        // We can only convert sRGB index colorspaces, depending on the base colorspace
+        if (baseColorSpace instanceof PDICCBased)
+        {
+            if (((PDICCBased) baseColorSpace).isSRGB())
+            {
+                byte[] r = new byte[colorTable.length];
+                byte[] g = new byte[colorTable.length];
+                byte[] b = new byte[colorTable.length];
+                for (int i = 0; i < colorTable.length; i++)
+                {
+                    r[i] = (byte) ((int) (colorTable[i][0] * 255) & 0xFF);
+                    g[i] = (byte) ((int) (colorTable[i][1] * 255) & 0xFF);
+                    b[i] = (byte) ((int) (colorTable[i][2] * 255) & 0xFF);
+                }
+                ColorModel colorModel = new IndexColorModel(8, colorTable.length, r, g, b);
+                return new BufferedImage(colorModel, raster, false, null);
+            }
+        }
+
+        // We can't handle all other cases at the moment.
+        return null;
+    }
+
     /**
      * Returns the base color space.
      * @return the base color space.

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDJPXColorSpace.java Sat Aug 29 11:32:15 2020
@@ -1,93 +1,99 @@
-/*
- * 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.
- */
-package org.apache.pdfbox.pdmodel.graphics.color;
-
-import org.apache.pdfbox.cos.COSBase;
-
-import java.awt.color.ColorSpace;
-import java.awt.image.BufferedImage;
-import java.awt.image.WritableRaster;
-import java.io.IOException;
-
-/**
- * A color space embedded in a JPX file.
- * This wraps the AWT ColorSpace which is obtained after JAI Image I/O reads a JPX stream.
- *
- * @author John Hewson
- */
-public final class PDJPXColorSpace extends PDColorSpace
-{
-    private final ColorSpace awtColorSpace;
-
-    /**
-     * Creates a new JPX color space from the given AWT color space.
-     * @param colorSpace AWT color space from a JPX image
-     */
-    public PDJPXColorSpace(ColorSpace colorSpace)
-    {
-        this.awtColorSpace = colorSpace;
-    }
-
-    @Override
-    public String getName()
-    {
-        return "JPX";
-    }
-
-    @Override
-    public int getNumberOfComponents()
-    {
-        return awtColorSpace.getNumComponents();
-    }
-
-    @Override
-    public float[] getDefaultDecode(int bitsPerComponent)
-    {
-        int n = getNumberOfComponents();
-        float[] decode = new float[n * 2];
-        for (int i = 0; i < n; i++)
-        {
-            decode[i * 2] = awtColorSpace.getMinValue(i);
-            decode[i * 2 + 1] = awtColorSpace.getMaxValue(i);
-        }
-        return decode;
-    }
-
-    @Override
-    public PDColor getInitialColor()
-    {
-        throw new UnsupportedOperationException("JPX color spaces don't support drawing");
-    }
-
-    @Override
-    public float[] toRGB(float[] value)
-    {
-        throw new UnsupportedOperationException("JPX color spaces don't support drawing");
-    }
-
-    @Override
-    public BufferedImage toRGBImage(WritableRaster raster) throws IOException
-    {
-        return toRGBImageAWT(raster, awtColorSpace);
-    }
-
-    @Override
-    public COSBase getCOSObject()
-    {
-        throw new UnsupportedOperationException("JPX color spaces don't have COS objects");
-    }
-}
+/*
+ * 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.
+ */
+package org.apache.pdfbox.pdmodel.graphics.color;
+
+import org.apache.pdfbox.cos.COSBase;
+
+import java.awt.color.ColorSpace;
+import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+/**
+ * A color space embedded in a JPX file.
+ * This wraps the AWT ColorSpace which is obtained after JAI Image I/O reads a JPX stream.
+ *
+ * @author John Hewson
+ */
+public final class PDJPXColorSpace extends PDColorSpace
+{
+    private final ColorSpace awtColorSpace;
+
+    /**
+     * Creates a new JPX color space from the given AWT color space.
+     * @param colorSpace AWT color space from a JPX image
+     */
+    public PDJPXColorSpace(ColorSpace colorSpace)
+    {
+        this.awtColorSpace = colorSpace;
+    }
+
+    @Override
+    public String getName()
+    {
+        return "JPX";
+    }
+
+    @Override
+    public int getNumberOfComponents()
+    {
+        return awtColorSpace.getNumComponents();
+    }
+
+    @Override
+    public float[] getDefaultDecode(int bitsPerComponent)
+    {
+        int n = getNumberOfComponents();
+        float[] decode = new float[n * 2];
+        for (int i = 0; i < n; i++)
+        {
+            decode[i * 2] = awtColorSpace.getMinValue(i);
+            decode[i * 2 + 1] = awtColorSpace.getMaxValue(i);
+        }
+        return decode;
+    }
+
+    @Override
+    public PDColor getInitialColor()
+    {
+        throw new UnsupportedOperationException("JPX color spaces don't support drawing");
+    }
+
+    @Override
+    public float[] toRGB(float[] value)
+    {
+        throw new UnsupportedOperationException("JPX color spaces don't support drawing");
+    }
+
+    @Override
+    public BufferedImage toRGBImage(WritableRaster raster) throws IOException
+    {
+        return toRGBImageAWT(raster, awtColorSpace);
+    }
+
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster)
+    {
+        return toRawImage(raster, this.awtColorSpace);
+    }
+
+    @Override
+    public COSBase getCOSObject()
+    {
+        throw new UnsupportedOperationException("JPX color spaces don't have COS objects");
+    }
+}

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDLab.java Sat Aug 29 11:32:15 2020
@@ -20,6 +20,7 @@ import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSFloat;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.common.PDRange;
+
 import java.awt.image.BufferedImage;
 import java.awt.image.WritableRaster;
 import java.io.IOException;
@@ -107,6 +108,13 @@ public final class PDLab extends PDCIEDi
     }
 
     @Override
+    public BufferedImage toRawImage(WritableRaster raster)
+    {
+        // Not handled at the moment.
+       return null;
+    }
+
+    @Override
     public float[] toRGB(float[] value)
     {
         // CIE LAB to RGB, see http://en.wikipedia.org/wiki/Lab_color_space

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDPattern.java Sat Aug 29 11:32:15 2020
@@ -101,6 +101,12 @@ public final class PDPattern extends PDS
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster) throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * Returns the pattern for the given color.
      * 

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java Sat Aug 29 11:32:15 2020
@@ -17,6 +17,7 @@
 package org.apache.pdfbox.pdmodel.graphics.color;
 
 import java.awt.Point;
+import java.awt.color.ColorSpace;
 import java.awt.image.BufferedImage;
 import java.awt.image.DataBuffer;
 import java.awt.image.Raster;
@@ -222,6 +223,12 @@ public class PDSeparation extends PDSpec
         }
     }
 
+    @Override
+    public BufferedImage toRawImage(WritableRaster raster)
+    {
+        return toRawImage(raster, ColorSpace.getInstance(ColorSpace.CS_GRAY));
+    }
+
     /**
      * Returns the colorant name.
      * @return the name of the colorant

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java Sat Aug 29 11:32:15 2020
@@ -56,6 +56,28 @@ public interface PDImage extends COSObje
     WritableRaster getRawRaster() throws IOException;
 
     /**
+     * Try to get the raw image as AWT buffered image with it's original colorspace. No
+     * color conversion is performed.
+     *
+     * You could use the returned BufferedImage for draw operations. But this would be very
+     * slow as the color conversion would happen on demand. You rather should use
+     * {@link #getImage()} for that.
+     *
+     * This method returns null if it is not possible to map the underlying colorspace into a
+     * java.awt.ColorSpace.
+     *
+     * Use this method if you want to extract the image without loosing any color information, as
+     * no color conversion will be performed.
+     *
+     * You can alwoys use {@link #getRawRaster()}, if you want to access the raw data even if
+     * no matching java.awt.ColorSpace exists
+     *
+     * @return the raw image with a java.awt.ColorSpace or null
+     * @throws IOException
+     */
+    BufferedImage getRawImage() throws IOException;
+
+    /**
      * Returns the content of this image as an AWT buffered image with an (A)RGB colored space. Only
      * the subregion specified is rendered, and is subsampled by advancing the specified amount of
      * rows and columns in the source image for every resulting pixel.

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java Sat Aug 29 11:32:15 2020
@@ -507,6 +507,12 @@ public final class PDImageXObject extend
     }
 
     @Override
+    public BufferedImage getRawImage() throws IOException
+    {
+        return getColorSpace().toRawImage(getRawRaster());
+    }
+
+    @Override
     public WritableRaster getRawRaster() throws IOException
     {
         return SampledImageReader.getRawRaster(this);

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java Sat Aug 29 11:32:15 2020
@@ -363,6 +363,12 @@ public final class PDInlineImage impleme
     }
 
     @Override
+    public BufferedImage getRawImage() throws IOException
+    {
+        return getColorSpace().toRawImage(getRawRaster());
+    }
+
+    @Override
     public BufferedImage getStencilImage(Paint paint) throws IOException
     {
         if (!isStencil())

Modified: pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java Sat Aug 29 11:32:15 2020
@@ -37,8 +37,6 @@ import java.util.Hashtable;
 import java.util.Random;
 import javax.imageio.ImageIO;
 import junit.framework.TestCase;
-import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertNotNull;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDPage;
 import org.apache.pdfbox.pdmodel.PDPageContentStream;
@@ -375,6 +373,56 @@ public class LosslessFactoryTest extends
         }
     }
 
+    /**
+     * Check whether the raw data of images are identical.
+     *  @param expectedImage
+     * @param actualImage
+     */
+    static void checkIdentRaw(BufferedImage expectedImage, PDImageXObject actualImage)
+            throws IOException
+    {
+        WritableRaster expectedRaster = expectedImage.getRaster();
+        WritableRaster actualRaster = actualImage.getRawRaster();
+        int w = expectedRaster.getWidth();
+        int h = expectedRaster.getHeight();
+        assertEquals(w, actualRaster.getWidth());
+        assertEquals(h, actualRaster.getHeight());
+        assertEquals(expectedRaster.getDataBuffer().getDataType(), actualRaster.getDataBuffer().getDataType());
+        int numDataElements = expectedRaster.getNumDataElements();
+        int numDataElementsToCompare;
+        if (expectedImage.getAlphaRaster() != null)
+        {
+            // We do not compare the alpha channel, as this is stored extra
+            numDataElementsToCompare = numDataElements - 1;
+            assertEquals(numDataElementsToCompare, actualRaster.getNumDataElements());
+        } else
+        {
+            numDataElementsToCompare = numDataElements;
+            assertEquals(numDataElements, actualRaster.getNumDataElements());
+        }
+        int[] expectedData = new int[numDataElements];
+        int[] actualData = new int[numDataElements];
+        for (int y = 0; y < h; ++y)
+        {
+            for (int x = 0; x < w; ++x)
+            {
+                expectedRaster.getPixel(x, y, expectedData);
+                actualRaster.getPixel(x, y, actualData);
+                for (int i = 0; i < numDataElementsToCompare; i++)
+                {
+                    int expectedValue = expectedData[i];
+                    int actualValue = actualData[i];
+                    if (expectedValue != actualValue)
+                    {
+                        String errMsg = String.format("(%d,%d) Channel %d %04X != %04X", x, y, i, expectedValue,
+                                actualValue);
+                        assertEquals(errMsg, expectedValue, actualValue);
+                    }
+                }
+            }
+        }
+    }
+
     private void doBitmaskTransparencyTest(int imageType, String pdfFilename) throws IOException
     {
         PDDocument document = new PDDocument();
@@ -587,6 +635,7 @@ public class LosslessFactoryTest extends
         validate(ximage, 16, w, h, "png", PDDeviceRGB.INSTANCE.getName());
         checkIdent(image, ximage.getImage());
         checkIdentRGB(image, ximage.getOpaqueImage());
+        checkIdentRaw(image, ximage);
 
         assertNotNull(ximage.getSoftMask());
         validate(ximage.getSoftMask(), 16, w, h, "png", PDDeviceGray.INSTANCE.getName());

Modified: pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/PNGConverterTest.java Sat Aug 29 11:32:15 2020
@@ -41,13 +41,16 @@ import org.apache.pdfbox.pdmodel.PDPageC
 import org.apache.pdfbox.pdmodel.graphics.color.PDICCBased;
 import org.apache.pdfbox.pdmodel.graphics.color.PDIndexed;
 
+import static org.apache.pdfbox.pdmodel.graphics.image.LosslessFactoryTest.checkIdentRaw;
 import static org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage.checkIdent;
 import org.junit.Assert;
 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.assertNotNull;
 import static org.junit.Assert.assertTrue;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -173,6 +176,7 @@ public class PNGConverterTest
     {
         PDDocument doc = new PDDocument();
         byte[] imageBytes = IOUtils.toByteArray(PNGConverterTest.class.getResourceAsStream(name));
+
         PDImageXObject pdImageXObject = PNGConverter.convertPNGImage(doc, imageBytes);
         assertNotNull(pdImageXObject);
 
@@ -196,6 +200,8 @@ public class PNGConverterTest
         doc.save(new File(parentDir, name + ".pdf"));
         BufferedImage image = pdImageXObject.getImage();
 
+        assertNotNull(pdImageXObject.getRawRaster());
+
         BufferedImage expectedImage = ImageIO.read(new ByteArrayInputStream(imageBytes));
         if (imageProfile != null && expectedImage.getColorModel().getColorSpace().isCS_sRGB())
         {
@@ -206,6 +212,15 @@ public class PNGConverterTest
 
         checkIdent(expectedImage, image);
 
+        BufferedImage rawImage = pdImageXObject.getRawImage();
+        if (rawImage != null)
+        {
+            assertEquals(rawImage.getWidth(), pdImageXObject.getWidth());
+            assertEquals(rawImage.getHeight(), pdImageXObject.getHeight());
+            // We compare the raw data
+            checkIdentRaw(expectedImage, pdImageXObject);
+        }
+
         doc.close();
     }
 

Modified: pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java?rev=1881293&r1=1881292&r2=1881293&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java Sat Aug 29 11:32:15 2020
@@ -70,6 +70,17 @@ public class ValidateXImage
         assertNotNull(ximage.getImage());
         assertEquals(ximage.getWidth(), ximage.getImage().getWidth());
         assertEquals(ximage.getHeight(), ximage.getImage().getHeight());
+        WritableRaster rawRaster = ximage.getRawRaster();
+        assertNotNull(rawRaster);
+        assertEquals(rawRaster.getWidth(), ximage.getWidth());
+        assertEquals(rawRaster.getHeight(), ximage.getHeight());
+        if (colorSpaceName.equals("ICCBased"))
+        {
+            BufferedImage rawImage = ximage.getRawImage();
+            assertNotNull(rawImage);
+            assertEquals(rawImage.getWidth(), ximage.getWidth());
+            assertEquals(rawImage.getHeight(), ximage.getHeight());
+        }
 
         boolean canEncode = true;
         boolean writeOk;