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/27 17:37:42 UTC

svn commit: r1881255 - in /pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image: PDImage.java PDImageXObject.java PDInlineImage.java SampledImageReader.java

Author: tilman
Date: Thu Aug 27 17:37:41 2020
New Revision: 1881255

URL: http://svn.apache.org/viewvc?rev=1881255&view=rev
Log:
PDFBOX-4847: return the image data as WritableRaster, by Emmeran Seehuber

Modified:
    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/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java

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=1881255&r1=1881254&r2=1881255&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 Thu Aug 27 17:37:41 2020
@@ -19,6 +19,7 @@ package org.apache.pdfbox.pdmodel.graphi
 import java.awt.Paint;
 import java.awt.Rectangle;
 import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.List;
@@ -43,6 +44,18 @@ public interface PDImage extends COSObje
     BufferedImage getImage() throws IOException;
 
     /**
+     * Return the image data as WritableRaster. You should consult the PDColorSpace returned
+     * by {@link #getColorSpace()} to know how to interpret the data in this WritableRaster.
+     *
+     * Use this if e.g. want access to the raw color information of a
+     * {@link org.apache.pdfbox.pdmodel.graphics.color.PDDeviceN} image.
+     *
+     * @return the raw writable raster for this image
+     * @throws IOException
+     */
+    WritableRaster getRawRaster() 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=1881255&r1=1881254&r2=1881255&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 Thu Aug 27 17:37:41 2020
@@ -506,6 +506,12 @@ public final class PDImageXObject extend
         return image;
     }
 
+    @Override
+    public WritableRaster getRawRaster() throws IOException
+    {
+        return SampledImageReader.getRawRaster(this);
+    }
+
     /**
      * Extract the matte color from a softmask.
      * 

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=1881255&r1=1881254&r2=1881255&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 Thu Aug 27 17:37:41 2020
@@ -19,6 +19,7 @@ package org.apache.pdfbox.pdmodel.graphi
 import java.awt.Paint;
 import java.awt.Rectangle;
 import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -356,6 +357,12 @@ public final class PDInlineImage impleme
     }
 
     @Override
+    public WritableRaster getRawRaster() throws IOException
+    {
+        return SampledImageReader.getRawRaster(this);
+    }
+
+    @Override
     public BufferedImage getStencilImage(Paint paint) throws IOException
     {
         if (!isStencil())

Modified: pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java?rev=1881255&r1=1881254&r2=1881255&view=diff
==============================================================================
--- pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java (original)
+++ pdfbox/branches/issue45/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java Thu Aug 27 17:37:41 2020
@@ -233,6 +233,150 @@ final class SampledImageReader
         }
     }
 
+    /**
+     * Extract the raw unconverted raster of the given image
+     * @param pdImage  The image to get the raw raster data from
+     * @return the raw raster of this image
+     * @throws IOException
+     */
+    public static WritableRaster getRawRaster(PDImage pdImage) throws IOException
+    {
+        if (pdImage.isEmpty())
+        {
+            throw new IOException("Image stream is empty");
+        }
+
+        // get parameters, they must be valid or have been repaired
+        final PDColorSpace colorSpace = pdImage.getColorSpace();
+        final int numComponents = colorSpace.getNumberOfComponents();
+        final int width = pdImage.getWidth();
+        final int height = pdImage.getHeight();
+        final int bitsPerComponent = pdImage.getBitsPerComponent();
+
+        if (width <= 0 || height <= 0)
+        {
+            throw new IOException("image width and height must be positive");
+        }
+
+        try
+        {
+            int dataBuffeType = DataBuffer.TYPE_BYTE;
+            if (bitsPerComponent > 8)
+            {
+                dataBuffeType = DataBuffer.TYPE_USHORT;
+            }
+            WritableRaster raster = Raster.createInterleavedRaster(dataBuffeType, width, height, numComponents,
+                    new Point(0, 0));
+            readRasterFromAny(pdImage, raster);
+            return raster;
+        }
+        catch (NegativeArraySizeException ex)
+        {
+            throw new IOException(ex);
+        }
+    }
+
+    private static void readRasterFromAny(PDImage pdImage, WritableRaster raster)
+            throws IOException
+    {
+        final PDColorSpace colorSpace = pdImage.getColorSpace();
+        final int numComponents = colorSpace.getNumberOfComponents();
+        final int bitsPerComponent = pdImage.getBitsPerComponent();
+        final float[] decode = getDecodeArray(pdImage);
+        DecodeOptions options = new DecodeOptions();
+
+        // read bit stream
+        ImageInputStream iis = null;
+        try
+        {
+            iis = new MemoryCacheImageInputStream(pdImage.createInputStream(options));
+
+            final int inputWidth = pdImage.getWidth();
+            final int scanWidth = pdImage.getWidth();
+            final int scanHeight = pdImage.getHeight();
+
+            // create stream
+            final float sampleMax = (float) Math.pow(2, bitsPerComponent) - 1f;
+            final boolean isIndexed = colorSpace instanceof PDIndexed;
+
+            // calculate row padding
+            int padding = 0;
+            if (inputWidth * numComponents * bitsPerComponent % 8 > 0)
+            {
+                padding = 8 - (inputWidth * numComponents * bitsPerComponent % 8);
+            }
+
+            // read stream
+            final boolean isShort = raster.getDataBuffer().getDataType() == DataBuffer.TYPE_USHORT;
+            assert !isIndexed || !isShort;
+            final byte[] srcColorValuesBytes = isShort ? null : new byte[numComponents];
+            final short[] srcColorValuesShort = isShort ? new short[numComponents] : null;
+            for (int y = 0; y < scanHeight; y++)
+            {
+                for (int x = 0; x < scanWidth; x++)
+                {
+                    for (int c = 0; c < numComponents; c++)
+                    {
+                        int value = (int) iis.readBits(bitsPerComponent);
+
+                        // decode array
+                        final float dMin = decode[c * 2];
+                        final float dMax = decode[(c * 2) + 1];
+
+                        // interpolate to domain
+                        float output = dMin + (value * ((dMax - dMin) / sampleMax));
+
+                        if (isIndexed)
+                        {
+                            // indexed color spaces get the raw value, because the TYPE_BYTE
+                            // below cannot be reversed by the color space without it having
+                            // knowledge of the number of bits per component
+                            srcColorValuesBytes[c] = (byte) Math.round(output);
+                        }
+                        else
+                        {
+                            if (isShort)
+                            {
+                                // interpolate to TYPE_SHORT
+                                int outputShort = Math
+                                        .round(((output - Math.min(dMin, dMax)) / Math.abs(dMax - dMin)) * 65535f);
+
+                                srcColorValuesShort[c] = (short) outputShort;
+                            }
+                            else
+                            {
+                                // interpolate to TYPE_BYTE
+                                int outputByte = Math
+                                        .round(((output - Math.min(dMin, dMax)) / Math.abs(dMax - dMin)) * 255f);
+
+                                srcColorValuesBytes[c] = (byte) outputByte;
+                            }
+                        }
+                    }
+
+                    if (isShort)
+                    {
+                        raster.setDataElements(x, y, srcColorValuesShort);
+                    }
+                    else
+                    {
+                        raster.setDataElements(x, y, srcColorValuesBytes);
+                    }
+                }
+
+                // rows are padded to the nearest byte
+                iis.readBits(padding);
+            }
+        }
+        finally
+        {
+            if (iis != null)
+            {
+                iis.close();
+            }
+        }
+    }
+
     private static BufferedImage from1Bit(PDImage pdImage, Rectangle clipped, final int subsampling,
                                           final int width, final int height) throws IOException
     {