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:47 UTC
svn commit: r1881256 - in
/pdfbox/trunk/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:47 2020
New Revision: 1881256
URL: http://svn.apache.org/viewvc?rev=1881256&view=rev
Log:
PDFBOX-4847: return the image data as WritableRaster, by Emmeran Seehuber
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java?rev=1881256&r1=1881255&r2=1881256&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImage.java Thu Aug 27 17:37:47 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;
@@ -44,6 +45,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/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java?rev=1881256&r1=1881255&r2=1881256&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java Thu Aug 27 17:37:47 2020
@@ -467,6 +467,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/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java?rev=1881256&r1=1881255&r2=1881256&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDInlineImage.java Thu Aug 27 17:37:47 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;
@@ -354,6 +355,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/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java?rev=1881256&r1=1881255&r2=1881256&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/SampledImageReader.java Thu Aug 27 17:37:47 2020
@@ -224,6 +224,140 @@ 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
+ try (ImageInputStream 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);
+ }
+ }
+ }
+
private static BufferedImage from1Bit(PDImage pdImage, Rectangle clipped, final int subsampling,
final int width, final int height) throws IOException
{