You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2011/10/23 16:59:30 UTC

svn commit: r1187901 - /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java

Author: lehmi
Date: Sun Oct 23 14:59:29 2011
New Revision: 1187901

URL: http://svn.apache.org/viewvc?rev=1187901&view=rev
Log:
PDFBOX-1116: added a color conversion for CMYK based jpegs

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java?rev=1187901&r1=1187900&r2=1187901&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java Sun Oct 23 14:59:29 2011
@@ -18,7 +18,15 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Color;
 import java.awt.Graphics2D;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
 import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -35,9 +43,11 @@ import java.util.Locale;
 import javax.imageio.IIOImage;
 import javax.imageio.ImageIO;
 import javax.imageio.IIOException;
+import javax.imageio.ImageReader;
 import javax.imageio.ImageWriteParam;
 import javax.imageio.ImageWriter;
 import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
+import javax.imageio.stream.ImageInputStream;
 import javax.imageio.stream.ImageOutputStream;
 
 import org.apache.pdfbox.cos.COSArray;
@@ -46,6 +56,8 @@ import org.apache.pdfbox.cos.COSName;
 
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceCMYK;
 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
 
@@ -230,41 +242,37 @@ public class PDJpeg extends PDXObjectIma
     {   //TODO PKOCH
         BufferedImage bi = null;
         boolean readError = false;
-        try
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        write2OutputStream(os);
+        os.close();
+        byte[] img = os.toByteArray();
+        
+        PDColorSpace cs = getColorSpace();
+        try 
         {
-            ByteArrayOutputStream os = new ByteArrayOutputStream();
-            write2OutputStream(os);
-            os.close();
-            byte[] img = os.toByteArray();
-
-            // 1. try to read jpeg image
-            try
+            if (cs instanceof PDDeviceCMYK)
             {
-                bi = ImageIO.read(new ByteArrayInputStream(img));
+                bi = readImage(img, cs);
             }
-            catch (IIOException iioe)
+            else 
             {
-                // cannot read jpeg
-                readError = true;
-            }
-            catch (Exception ignore)
-            {
-            }
-
-            // 2. try to read jpeg again. some jpegs have some strange header containing
-            //    "Adobe " at some place. so just replace the header with a valid jpeg header.
-            // TODO : not sure if it works for all cases
-            if (bi == null && readError)
-            {
-                byte[] newImage = replaceHeader(img);
-
-                ByteArrayInputStream bai = new ByteArrayInputStream(newImage);
-
+                ByteArrayInputStream bai = new ByteArrayInputStream(img);
                 bi = ImageIO.read(bai);
             }
+                
         }
-        finally
+        catch(IIOException exception) 
+        {
+            readError = true;
+        }
+        // 2. try to read jpeg again. some jpegs have some strange header containing
+        //    "Adobe " at some place. so just replace the header with a valid jpeg header.
+        // TODO : not sure if it works for all cases
+        if (bi == null && readError)
         {
+            byte[] newImage = replaceHeader(img);
+            ByteArrayInputStream bai = new ByteArrayInputStream(newImage);
+            bi = ImageIO.read(bai);
         }
 
         // If there is a 'soft mask' image then we use that as a transparency mask.
@@ -305,7 +313,7 @@ public class PDJpeg extends PDXObjectIma
      * Returns the given file as byte array.
      * @param file File to be read
      * @return given file as byte array
-     * @throws IOException if somethin went wrong during reading the file
+     * @throws IOException if something went wrong during reading the file
      */
     public static byte[] getBytesFromFile(File file) throws IOException
     {
@@ -371,5 +379,71 @@ public class PDJpeg extends PDXObjectIma
 
         return newImage;
     }
+
+    // CMYK jpegs are not supported by JAI, so that we have the conversion on our own
+    private BufferedImage readImage(byte[] bytes, PDColorSpace colorspace) throws IOException 
+    {
+        ImageInputStream input = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes));
+        Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
+        if (readers == null || !readers.hasNext()) 
+        {
+            throw new RuntimeException("No ImageReaders found");
+        }
+
+        // read the raster information only
+        // avoid to access the meta information
+        ImageReader reader = (ImageReader) readers.next();
+        reader.setInput(input);
+        Raster raster = reader.readRaster(0, reader.getDefaultReadParam());
+        if (input != null) 
+        {
+            input.close();
+        }
+        reader.dispose();
+        int w = raster.getWidth();
+        int h = raster.getHeight();
+
+        // create a java color space to be used for conversion
+        ColorSpace cs = colorspace.getJavaColorSpace();
+        // target data array
+        byte[] rgb = new byte[w * h * 3];
+        int numberOfComponents = colorspace.getNumberOfComponents();
+        // pointer into the target array
+        int rgbIndex = 0;
+        for (int i = 0; i < h; i++) 
+        {
+            for (int j = 0; j < w; j++)
+            {
+                // get the source color values
+                float[] srcColorValues = raster.getPixel(j,i, (float[])null);
+                // convert values from 0..255 to 0..1
+                for (int k = 0; k < numberOfComponents; k++)
+                {
+                    srcColorValues[k] /= 255f; 
+                }
+                // convert CMYK to RGB
+                float[] rgbValues = cs.toRGB(srcColorValues);
+                // convert values from 0..1 to 0..255
+                for (int k = 0; k < 3; k++)
+                {
+                    rgb[rgbIndex+k] = (byte)(rgbValues[k] * 255); 
+                }
+                rgbIndex +=3;
+            }
+        }
+        // create a RGB color model
+        ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 
+                false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+        // create the target raster
+        WritableRaster writeableRaster = cm.createCompatibleWritableRaster(w, h);
+        // get the data buffer of the raster
+        DataBufferByte buffer = (DataBufferByte)writeableRaster.getDataBuffer();
+        byte[] bufferData = buffer.getData();
+        // copy all the converted data to the raster buffer
+        System.arraycopy( rgb, 0,bufferData, 0,rgb.length );
+        // create an image using the converted color values
+        return new BufferedImage(cm, writeableRaster, true, null);
+    }
+
 }