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 2014/03/20 21:22:03 UTC
svn commit: r1579729 - in /pdfbox/trunk/pdfbox/src:
main/java/org/apache/pdfbox/pdmodel/graphics/image/
test/java/org/apache/pdfbox/pdmodel/graphics/image/
Author: tilman
Date: Thu Mar 20 20:22:02 2014
New Revision: 1579729
URL: http://svn.apache.org/r1579729
Log:
PDFBOX-1990, PDFBOX-1969: solution for extracting the alpha part of ARGB image, improved tests, some refactoring per DRY
Added:
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java (with props)
Modified:
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/ImageFactory.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactory.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactoryTest.java
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/ImageFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/ImageFactory.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/ImageFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/ImageFactory.java Thu Mar 20 20:22:02 2014
@@ -76,6 +76,10 @@ class ImageFactory
// returns the alpha channel of an image
protected static BufferedImage getAlphaImage(BufferedImage image)
{
+ //FIXME This doesn't work. The raster returned has a
+ // SinglePixelPackedSampleModel, and ComponentColorModel created is not
+ // compatible with it, because the BufferedImage constructor expects a
+ // ComponentSampleModel, and with the same number of bands.
if (!image.getColorModel().hasAlpha())
{
return null;
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactory.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactory.java Thu Mar 20 20:22:02 2014
@@ -27,7 +27,6 @@ import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.filter.MissingImageReaderException;
import org.apache.pdfbox.io.IOUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.pdmodel.common.PDStream;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactory.java Thu Mar 20 20:22:02 2014
@@ -17,6 +17,7 @@ package org.apache.pdfbox.pdmodel.graphi
import java.awt.Color;
import java.awt.image.BufferedImage;
+import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -25,7 +26,9 @@ import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.filter.Filter;
import org.apache.pdfbox.filter.FilterFactory;
import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
+import static org.apache.pdfbox.pdmodel.graphics.image.ImageFactory.getColorImage;
/**
* Factory for creating a PDImageXObject containing a lossless compressed image.
@@ -45,16 +48,19 @@ public class LosslessFactory
public static PDImageXObject createFromImage(PDDocument document, BufferedImage image)
throws IOException
{
+ // extract color channel
+ BufferedImage awtColorImage = getColorImage(image);
+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//TODO use bit writing, indexed, etc
- int h = image.getHeight();
- int w = image.getWidth();
+ int h = awtColorImage.getHeight();
+ int w = awtColorImage.getWidth();
for (int y = 0; y < h; ++y)
{
for (int x = 0; x < w; ++x)
{
- Color color = new Color(image.getRGB(x, y));
+ Color color = new Color(awtColorImage.getRGB(x, y));
bos.write(color.getRed());
bos.write(color.getGreen());
bos.write(color.getBlue());
@@ -72,10 +78,76 @@ public class LosslessFactory
COSDictionary dict = pdImage.getCOSStream();
dict.setItem(COSName.FILTER, COSName.FLATE_DECODE);
- pdImage.setColorSpace(PDDeviceRGB.INSTANCE); //TODO from image
+
+ pdImage.setColorSpace(PDDeviceRGB.INSTANCE); //TODO from awtColorImage
pdImage.setBitsPerComponent(8); //TODO other sizes
+ pdImage.setHeight(awtColorImage.getHeight());
+ pdImage.setWidth(awtColorImage.getWidth());
+
+ // alpha -> soft mask
+ PDImage xAlpha = createAlphaFromARGBImage(document, image);
+ if (xAlpha != null)
+ {
+ dict.setItem(COSName.SMASK, xAlpha);
+ }
+
+ return pdImage;
+ }
+
+ /**
+ * Creates a grayscale PDImageXObject from the alpha channel of an image.
+ *
+ * @param document the document where the image will be created.
+ * @param image an ARGB image.
+ *
+ * @return the alpha channel of an image as a grayscale image.
+ *
+ * @throws IOException if something goes wrong
+ */
+ private static PDImageXObject createAlphaFromARGBImage(PDDocument document, BufferedImage image)
+ throws IOException
+ {
+ // this implementation makes the assumption that the raster uses
+ // SinglePixelPackedSampleModel, i.e. the values can be used 1:1 for
+ // the stream.
+ // Sadly the type of the databuffer is TYPE_INT and not TYPE_BYTE.
+ //TODO: optimize this to lessen the memory footprint.
+ // possible idea? Derive an inputStream that reads from the raster.
+
+ if (!image.getColorModel().hasAlpha())
+ {
+ return null;
+ }
+
+ // extract the alpha information
+ WritableRaster alphaRaster = image.getAlphaRaster();
+
+ int[] pixels = alphaRaster.getPixels(0, 0,
+ alphaRaster.getSampleModel().getWidth(),
+ alphaRaster.getSampleModel().getHeight(),
+ (int[]) null);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ for (int pixel : pixels)
+ {
+ bos.write(pixel);
+ }
+ ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
+
+ Filter filter = FilterFactory.INSTANCE.getFilter(COSName.FLATE_DECODE);
+ ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
+ filter.encode(bais, bos2, new COSDictionary(), 0);
+
+ ByteArrayInputStream filteredByteStream = new ByteArrayInputStream(bos2.toByteArray());
+ PDImageXObject pdImage = new PDImageXObject(document, filteredByteStream);
+
+ COSDictionary dict = pdImage.getCOSStream();
+ dict.setItem(COSName.FILTER, COSName.FLATE_DECODE);
+
+ pdImage.setColorSpace(PDDeviceGray.INSTANCE);
+ pdImage.setBitsPerComponent(8);
pdImage.setHeight(image.getHeight());
pdImage.setWidth(image.getWidth());
+
return pdImage;
}
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/CCITTFactoryTest.java Thu Mar 20 20:22:02 2014
@@ -19,20 +19,21 @@ import java.io.File;
import java.io.IOException;
import junit.framework.TestCase;
-import static junit.framework.TestCase.assertTrue;
import org.apache.pdfbox.io.RandomAccess;
import org.apache.pdfbox.io.RandomAccessFile;
import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.util.ImageIOUtil;
+import static org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage.validate;
/**
* Unit tests for CCITTFactory
+ *
* @author Tilman Hausherr
*/
public class CCITTFactoryTest extends TestCase
{
/**
- * Tests CCITTFactory#createFromRandomAccess(PDDocument document, RandomAccess reader)
+ * Tests CCITTFactory#createFromRandomAccess(PDDocument document,
+ * RandomAccess reader)
*/
public void testCreateFromRandomAccess() throws IOException
{
@@ -40,25 +41,7 @@ public class CCITTFactoryTest extends Te
PDDocument document = new PDDocument();
RandomAccess reader = new RandomAccessFile(new File(tiffPath), "r");
PDImageXObject ximage = CCITTFactory.createFromRandomAccess(document, reader);
-
- // check the dictionary
- assertNotNull(ximage);
- assertNotNull(ximage.getCOSStream());
- assertTrue(ximage.getCOSStream().getFilteredLength() > 0);
- assertEquals(1, ximage.getBitsPerComponent());
- assertEquals(344, ximage.getWidth());
- assertEquals(287, ximage.getHeight());
- assertEquals("tiff", ximage.getSuffix());
-
- // check the image
- assertNotNull(ximage.getImage());
- assertEquals(344, ximage.getImage().getWidth());
- assertEquals(287, ximage.getImage().getHeight());
-
- // dummy write the image
- boolean writeOk = ImageIOUtil.writeImage(ximage.getImage(), "png", new NullOutputStream());
- assertTrue(writeOk);
-
+ validate(ximage, 1, 344, 287, "tiff");
document.close();
}
}
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactoryTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactoryTest.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactoryTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/JPEGFactoryTest.java Thu Mar 20 20:22:02 2014
@@ -22,40 +22,44 @@ import java.io.InputStream;
import javax.imageio.ImageIO;
import junit.framework.TestCase;
import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.util.ImageIOUtil;
+import static org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage.validate;
/**
* Unit tests for JPEGFactory
+ *
* @author Tilman Hausherr
*/
public class JPEGFactoryTest extends TestCase
{
/**
- * Tests JPEGFactory#createFromStream(PDDocument document, InputStream stream)
+ * Tests JPEGFactory#createFromStream(PDDocument document, InputStream
+ * stream)
*/
public void testCreateFromStream() throws IOException
{
PDDocument document = new PDDocument();
InputStream stream = JPEGFactoryTest.class.getResourceAsStream("jpeg.jpg");
PDImageXObject ximage = JPEGFactory.createFromStream(document, stream);
- validate(ximage);
+ validate(ximage, 8, 344, 287, "jpg");
document.close();
}
/**
- * Tests RGB JPEGFactory#createFromImage(PDDocument document, BufferedImage image)
+ * Tests RGB JPEGFactory#createFromImage(PDDocument document, BufferedImage
+ * image)
*/
public void testCreateFromImageRGB() throws IOException
{
PDDocument document = new PDDocument();
BufferedImage image = ImageIO.read(JPEGFactoryTest.class.getResourceAsStream("jpeg.jpg"));
PDImageXObject ximage = JPEGFactory.createFromImage(document, image);
- validate(ximage);
+ validate(ximage, 8, 344, 287, "jpg");
document.close();
}
/**
- * Tests ARGB JPEGFactory#createFromImage(PDDocument document, BufferedImage image)
+ * Tests ARGB JPEGFactory#createFromImage(PDDocument document, BufferedImage
+ * image)
*/
public void testCreateFromImageARGB() throws IOException
{
@@ -70,40 +74,21 @@ public class JPEGFactoryTest extends Tes
ag.drawImage(image, 0, 0, null);
ag.dispose();
- // left half of image with 50% alpha
- for (int x = 0; x < w / 2; ++x)
+ // create a weird transparency triangle
+ for (int y = 0; y < h; ++y)
{
- for (int y = 0; y < h; ++y)
+ for (int x = 0; x < Math.min(y, w); ++x)
{
- argbImage.setRGB(x, y, image.getRGB(x, y) & 0x7FFFFFFF);
+ argbImage.setRGB(x, y, image.getRGB(x, y) & 0xFFFFFF | ((x * 255 / w) << 24));
}
}
- PDImageXObject ximage = JPEGFactory.createFromImage(document, image);
- validate(ximage);
- assertNull(ximage.getSoftMask());
-
+ //TODO uncomment if ImageFactory.getAlphaImage() ever works
+// PDImageXObject ximage = JPEGFactory.createFromImage(document, argbImage);
+// validate(ximage, 8, 344, 287, "jpg");
+// assertNotNull(ximage.getSoftMask());
+// validate(ximage.getSoftMask(), 8, 344, 287, "jpg");
document.close();
}
- private void validate(PDImageXObject ximage) throws IOException
- {
- // check the dictionary
- assertNotNull(ximage);
- assertNotNull(ximage.getCOSStream());
- assertTrue(ximage.getCOSStream().getFilteredLength() > 0);
- assertEquals(8, ximage.getBitsPerComponent());
- assertEquals(344, ximage.getWidth());
- assertEquals(287, ximage.getHeight());
- assertEquals("jpg", ximage.getSuffix());
-
- // check the image
- assertNotNull(ximage.getImage());
- assertEquals(344, ximage.getImage().getWidth());
- assertEquals(287, ximage.getImage().getHeight());
-
- // dummy write the image
- boolean writeOk = ImageIOUtil.writeImage(ximage.getImage(), "png", new NullOutputStream());
- assertTrue(writeOk);
- }
}
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java?rev=1579729&r1=1579728&r2=1579729&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/LosslessFactoryTest.java Thu Mar 20 20:22:02 2014
@@ -15,45 +15,71 @@
*/
package org.apache.pdfbox.pdmodel.graphics.image;
+import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import junit.framework.TestCase;
import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.util.ImageIOUtil;
+import static org.apache.pdfbox.pdmodel.graphics.image.ValidateXImage.validate;
/**
- * Unit tests for JPEGFactory
+ * Unit tests for LosslessFactory
*
* @author Tilman Hausherr
*/
public class LosslessFactoryTest extends TestCase
{
/**
- * Tests LosslessFactoryTest#createFromImage(PDDocument document,
+ * Tests RGB LosslessFactoryTest#createFromImage(PDDocument document,
* BufferedImage image)
+ *
+ * @throws java.io.IOException
*/
- public void testCreateLosslessFromImage() throws IOException
+ public void testCreateLosslessFromImageRGB() throws IOException
{
PDDocument document = new PDDocument();
- BufferedImage image = ImageIO.read(JPEGFactoryTest.class.getResourceAsStream("png.png"));
+ BufferedImage image = ImageIO.read(this.getClass().getResourceAsStream("png.png"));
PDImageXObject ximage = LosslessFactory.createFromImage(document, image);
- assertNotNull(ximage);
- assertNotNull(ximage.getCOSStream());
- assertTrue(ximage.getCOSStream().getFilteredLength() > 0);
- assertEquals(8, ximage.getBitsPerComponent());
- assertEquals(344, ximage.getWidth());
- assertEquals(287, ximage.getHeight());
- assertEquals("png", ximage.getSuffix());
-
- // check the image
- assertNotNull(ximage.getImage());
- assertEquals(ximage.getWidth(), ximage.getImage().getWidth());
- assertEquals(ximage.getHeight(), ximage.getImage().getHeight());
+ validate(ximage, 8, 344, 287, "png");
+ document.close();
+ }
+
+ /**
+ * Tests ARGB LosslessFactoryTest#createFromImage(PDDocument document,
+ * BufferedImage image)
+ *
+ * @throws java.io.IOException
+ */
+ public void testCreateLosslessFromImageARGB() throws IOException
+ {
+ PDDocument document = new PDDocument();
+ BufferedImage image = ImageIO.read(this.getClass().getResourceAsStream("png.png"));
+
+ // create an ARGB image
+ int w = image.getWidth();
+ int h = image.getHeight();
+ BufferedImage argbImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ Graphics ag = argbImage.getGraphics();
+ ag.drawImage(image, 0, 0, null);
+ ag.dispose();
- boolean writeOk = ImageIOUtil.writeImage(ximage.getImage(), "png", new NullOutputStream());
- assertTrue(writeOk);
+ // create a weird transparency triangle
+ for (int y = 0; y < h; ++y)
+ {
+ for (int x = 0; x < Math.min(y, w); ++x)
+ {
+ argbImage.setRGB(x, y, image.getRGB(x, y) & 0xFFFFFF | ((x * 255 / w) << 24));
+ }
+ }
+
+ PDImageXObject ximage = LosslessFactory.createFromImage(document, argbImage);
+ validate(ximage, 8, 344, 287, "png");
+
+ assertNotNull(ximage.getSoftMask());
+ validate(ximage.getSoftMask(), 8, 344, 287, "png");
document.close();
}
+
}
Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java?rev=1579729&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java Thu Mar 20 20:22:02 2014
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 The Apache Software Foundation.
+ *
+ * Licensed 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.image;
+
+import java.io.IOException;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import org.apache.pdfbox.util.ImageIOUtil;
+
+/**
+ * Helper class to do some validations for PDImageXObject.
+ *
+ * @author Tilman Hausherr
+ */
+public class ValidateXImage
+{
+ static public void validate(PDImageXObject ximage, int bpc, int width, int height, String format) throws IOException
+ {
+ // check the dictionary
+ assertNotNull(ximage);
+ assertNotNull(ximage.getCOSStream());
+ assertTrue(ximage.getCOSStream().getFilteredLength() > 0);
+ assertEquals(bpc, ximage.getBitsPerComponent());
+ assertEquals(width, ximage.getWidth());
+ assertEquals(height, ximage.getHeight());
+ assertEquals(format, ximage.getSuffix());
+
+ // check the image
+ assertNotNull(ximage.getImage());
+ assertEquals(ximage.getWidth(), ximage.getImage().getWidth());
+ assertEquals(ximage.getHeight(), ximage.getImage().getHeight());
+
+ boolean writeOk = ImageIOUtil.writeImage(ximage.getImage(), format, new NullOutputStream());
+ assertTrue(writeOk);
+ }
+
+}
Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/graphics/image/ValidateXImage.java
------------------------------------------------------------------------------
svn:eol-style = native