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 2018/08/18 13:56:43 UTC

svn commit: r1838328 - in /pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox: cos/COSName.java pdmodel/graphics/image/PDImageXObject.java

Author: tilman
Date: Sat Aug 18 13:56:43 2018
New Revision: 1838328

URL: http://svn.apache.org/viewvc?rev=1838328&view=rev
Log:
PDFBOX-4267: consider /Matte entry when applying soft masks, as suggested by Jani Pehkonen

Modified:
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1838328&r1=1838327&r2=1838328&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Sat Aug 18 13:56:43 2018
@@ -343,6 +343,7 @@ public final class COSName extends COSBa
     public static final COSName MARK_INFO = new COSName("MarkInfo");
     public static final COSName MASK = new COSName("Mask");
     public static final COSName MATRIX = new COSName("Matrix");
+    public static final COSName MATTE = new COSName("Matte");
     public static final COSName MAX_LEN = new COSName("MaxLen");
     public static final COSName MAX_WIDTH = new COSName("MaxWidth");
     public static final COSName MCID = new COSName("MCID");

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java?rev=1838328&r1=1838327&r2=1838328&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java Sat Aug 18 13:56:43 2018
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.SoftReference;
+import java.util.Arrays;
 import java.util.List;
 import javax.imageio.ImageIO;
 import org.apache.commons.logging.Log;
@@ -446,7 +447,29 @@ public final class PDImageXObject extend
         PDImageXObject softMask = getSoftMask();
         if (softMask != null)
         {
-            image = applyMask(image, softMask.getOpaqueImage(), true);
+            COSBase base = softMask.getCOSObject().getItem(COSName.MATTE);
+            float[] matte = null;
+            if (base instanceof COSArray)
+            {
+                // PDFBOX-4267: process /Matte
+                // see PDF specification 1.7, 11.6.5.3 Soft-Mask Images
+                matte = ((COSArray) base).toFloatArray();
+                if (getColorSpace().getNumberOfComponents() == 1 &&
+                    matte.length >= 1)
+                {
+                    // /DeviceGray has only one element in Matte
+                    // See file from PDFBOX-1359, page 14
+                    // Root/Pages/Kids/[2]/Kids/[2]/Resources/XObject/Im1/Resources/XObject/Im0
+                    matte = new float[] { matte[0], matte[0], matte[0] };
+                }
+                if (matte.length != 3)
+                {
+                    LOG.warn("/Matte entry " + Arrays.toString(matte) + 
+                             " for Soft-Mask may not work properly");
+                    matte = Arrays.copyOf(matte, 3);
+                }
+            }
+            image = applyMask(image, softMask.getOpaqueImage(), true, matte);
         }
         else
         {
@@ -454,7 +477,7 @@ public final class PDImageXObject extend
             PDImageXObject mask = getMask();
             if (mask != null && mask.isStencil())
             {
-                image = applyMask(image, mask.getOpaqueImage(), false);
+                image = applyMask(image, mask.getOpaqueImage(), false, null);
             }
         }
 
@@ -496,7 +519,8 @@ public final class PDImageXObject extend
 
     // explicit mask: RGB + Binary -> ARGB
     // soft mask: RGB + Gray -> ARGB
-    private BufferedImage applyMask(BufferedImage image, BufferedImage mask, boolean isSoft)
+    private BufferedImage applyMask(BufferedImage image, BufferedImage mask,
+                                    boolean isSoft, float[] matte)
             throws IOException
     {
         if (mask == null)
@@ -542,6 +566,12 @@ public final class PDImageXObject extend
                 if (isSoft)
                 {
                     rgba[3] = alphaPixel[0];
+                    if (matte != null && alphaPixel[0] != 0)
+                    {
+                        rgba[0] = clampColor(((rgba[0] / 255 - matte[0]) / (alphaPixel[0] / 255) + matte[0]) * 255);
+                        rgba[1] = clampColor(((rgba[1] / 255 - matte[1]) / (alphaPixel[0] / 255) + matte[1]) * 255);
+                        rgba[2] = clampColor(((rgba[2] / 255 - matte[2]) / (alphaPixel[0] / 255) + matte[2]) * 255);
+                    }
                 }
                 else
                 {
@@ -555,6 +585,11 @@ public final class PDImageXObject extend
         return masked;
     }
 
+    private float clampColor(float color)
+    {
+        return color < 0 ? 0 : (color > 255 ? 255 : color);        
+    }
+
     /**
      * High-quality image scaling.
      */