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 2010/06/19 17:39:44 UTC

svn commit: r956239 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject: CompositeImage.java PDJpeg.java PDPixelMap.java PDXObjectImage.java

Author: lehmi
Date: Sat Jun 19 15:39:42 2010
New Revision: 956239

URL: http://svn.apache.org/viewvc?rev=956239&view=rev
Log:
PDFBOX-323: added transparency/opacity for images. Patch by Neil McErlean (neil dot mcerlean at gmail dot com)

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/CompositeImage.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/CompositeImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/CompositeImage.java?rev=956239&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/CompositeImage.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/CompositeImage.java Sat Jun 19 15:39:42 2010
@@ -0,0 +1,104 @@
+/*
+ * 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.xobject;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+import org.apache.pdfbox.cos.COSArray;
+
+
+/**
+ * This class is responsible for combining a base image with an SMask-based transparency
+ * image to form a composite image.
+ * See section 11.5 of the pdf specification for details on Soft Masks.
+ * <p/>
+ * Briefly however, an Smask is a supplementary greyscale image whose RGB-values define
+ * a transparency mask which, when combined appropriately with the base image,
+ * allows per-pixel transparency to be applied.
+ * <p/>
+ * Note that Smasks are not required for any image and if the smask is not present
+ * in the pdf file, the image will have no transparent pixels.
+ *
+ * @author Neil McErlean
+ */
+public class CompositeImage
+{
+	private BufferedImage baseImage;
+	private BufferedImage smaskImage;
+	
+    /**
+     * Standard constructor.
+     * @param baseImage the base Image.
+     * @param smaskImage the transparency image.
+     *
+     */
+    public CompositeImage(BufferedImage baseImage, BufferedImage smaskImage)
+    {
+    	this.baseImage = baseImage;
+    	this.smaskImage = smaskImage;
+    }
+    
+    /**
+     * This method applies the specified transparency mask to a given image and returns a new BufferedImage
+     * whose alpha values are computed from the transparency mask (smask) image.
+     */
+    public BufferedImage createMaskedImage(COSArray decodeArray) throws IOException
+    {
+    	// The decode array should only be [0 1] or [1 0]. See PDF spec.
+    	// [0 1] means the smask's RGB values give transparency. Default: see PDF spec section 8.9.5.1
+    	// [1 0] means the smask's RGB values give opacity.
+
+    	boolean isOpaque = false;
+    	if (decodeArray != null)
+    	{
+    	    isOpaque = decodeArray.getInt(0) > decodeArray.getInt(1);
+    	}
+    	
+    	final int baseImageWidth = baseImage.getWidth();
+    	final int baseImageHeight = baseImage.getHeight();
+    	
+    	BufferedImage result = new BufferedImage(baseImageWidth, baseImageHeight, BufferedImage.TYPE_INT_ARGB);
+    	for (int x = 0; x < baseImageWidth; x++)
+    	{
+    		for (int y = 0; y < baseImageHeight; y++)
+    		{
+    			int rgb = baseImage.getRGB(x, y);
+    			int alpha = smaskImage.getRGB(x, y);
+    			
+    			// The smask image defines a transparency mask but it has no alpha values itself, instead
+    			// using the greyscale values to indicate transparency.
+    			// 0xAARRGGBB
+    			
+    			// We need to remove any alpha value in the main image.
+    			int rgbOnly = 0x00FFFFFF & rgb;
+    			
+    			// We need to use one of the rgb values as the new alpha value for the main image.
+    			// It seems the mask is greyscale, so it shouldn't matter whether we use R, G or B
+    			// as the indicator of transparency.
+    			if (isOpaque)
+    			{
+    				alpha = ~alpha;
+    			}
+    			int alphaOnly = alpha << 24;
+    			
+    			result.setRGB(x, y, rgbOnly | alphaOnly);
+    		}
+    	}
+    	return result;
+    }
+}

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=956239&r1=956238&r2=956239&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 Sat Jun 19 15:39:42 2010
@@ -33,6 +33,7 @@ import java.util.List;
 import javax.imageio.ImageIO;
 import javax.imageio.IIOException;
 
+import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 
@@ -50,7 +51,7 @@ import org.apache.pdfbox.pdmodel.graphic
 public class PDJpeg extends PDXObjectImage
 {
 
-    private static final List<String> DCT_FILTERS = new ArrayList();
+    private static final List<String> DCT_FILTERS = new ArrayList<String>();
 
     static
     {
@@ -198,7 +199,8 @@ public class PDJpeg extends PDXObjectIma
                 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.
@@ -232,9 +234,26 @@ public class PDJpeg extends PDXObjectIma
                 imgFile.delete();
             }
         }
-        return bi;
-    }
+        
+        // If there is a 'soft mask' image then we use that as a transparency mask.
+        PDXObjectImage smask = getSMaskImage();
+        if (smask != null)
+        {
+            BufferedImage smaskBI = smask.getRGBImage();
+            
+           	COSArray decodeArray = smask.getDecode();
+           	CompositeImage compositeImage = new CompositeImage(bi, smaskBI);
+           	BufferedImage rgbImage = compositeImage.createMaskedImage(decodeArray);
 
+            return rgbImage;
+        }
+        else
+        {
+        	// But if there is no soft mask, use the unaltered image.
+            return bi;
+        }
+    }
+    
     /**
      * This writes the JPeg to out.
      * {@inheritDoc}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java?rev=956239&r1=956238&r2=956239&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDPixelMap.java Sat Jun 19 15:39:42 2010
@@ -227,7 +227,24 @@ public class PDPixelMap extends PDXObjec
                     (array.length<bufferData.length?array.length: bufferData.length) );
             image = new BufferedImage(cm, raster, false, null);
             
-            return image;
+	        // If there is a 'soft mask' image then we use that as a transparency mask.
+	        PDXObjectImage smask = getSMaskImage();
+	        if (smask != null)
+	        {
+                BufferedImage smaskBI = smask.getRGBImage();
+                
+               	COSArray decodeArray = smask.getDecode();
+               	
+               	CompositeImage compositeImage = new CompositeImage(image, smaskBI);
+               	BufferedImage rgbImage = compositeImage.createMaskedImage(decodeArray);
+
+                return rgbImage;
+	        }
+	        else
+	        {
+	        	// But if there is no soft mask, use the unaltered image.
+	            return image;
+	        }
         } 
         catch (Exception exception)
         {

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java?rev=956239&r1=956238&r2=956239&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDXObjectImage.java Sat Jun 19 15:39:42 2010
@@ -27,6 +27,7 @@ import org.apache.commons.logging.LogFac
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
@@ -96,6 +97,27 @@ public abstract class PDXObjectImage ext
     public abstract BufferedImage getRGBImage() throws IOException;
 
     /**
+     * Returns a PDXObjectImage of the SMask image, if there is one.
+     * See section 11.5 of the pdf specification for details on Soft Masks.
+     *
+     * @return the PDXObjectImage of the SMask if there is one, else <code>null</code>.
+     */
+    public PDXObjectImage getSMaskImage() throws IOException
+    {
+    	COSStream cosStream = getPDStream().getStream();
+    	COSBase smask = cosStream.getDictionaryObject(COSName.SMASK);
+    	
+    	if (smask == null)
+    	{
+    		return null;
+    	}
+    	else
+    	{
+    		return (PDXObjectImage)PDXObject.createXObject(smask);
+    	}
+    }
+    
+    /**
      * Writes the Image to out.
      * @param out the OutputStream that the Image is written to.
      * @throws IOException when somethings wrong with out