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 2021/03/30 17:24:53 UTC

svn commit: r1888225 - /pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/image/PDImageXObject.java

Author: tilman
Date: Tue Mar 30 17:24:53 2021
New Revision: 1888225

URL: http://svn.apache.org/viewvc?rev=1888225&view=rev
Log:
PDFBOX-5145: speed up applyMask() by using linewise bulk copy instead of per pixel, as suggested by By Oliver Schmidtmer; closes #111

Modified:
    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/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=1888225&r1=1888224&r2=1888225&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 Tue Mar 30 17:24:53 2021
@@ -31,7 +31,9 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.ref.SoftReference;
 import java.util.List;
+
 import javax.imageio.ImageIO;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.pdfbox.cos.COSArray;
@@ -586,18 +588,20 @@ public final class PDImageXObject extend
         // scale mask to fit image, or image to fit mask, whichever is larger
         if (mask.getWidth() < width || mask.getHeight() < height)
         {
-            mask = scaleImage(mask, width, height);
+            mask = scaleImage(mask, width, height, BufferedImage.TYPE_BYTE_GRAY);
         }
-        else if (mask.getWidth() > width || mask.getHeight() > height)
+
+        if (mask.getWidth() > width || mask.getHeight() > height)
         {
             width = mask.getWidth();
             height = mask.getHeight();
-            image = scaleImage(image, width, height);
+            image = scaleImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
         }
-        else if (image.getRaster().getPixel(0, 0, (int[]) null).length < 3)
+        else if (image.getType() != BufferedImage.TYPE_INT_ARGB)
         {
+            // always convert to ARGB to allow bulk read / write
             // PDFBOX-4470 bitonal image has only one element => copy into RGB
-            image = scaleImage(image, width, height);
+            image = scaleImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
         }
 
         // compose to ARGB
@@ -606,53 +610,47 @@ public final class PDImageXObject extend
         WritableRaster dest = masked.getRaster();
         WritableRaster alpha = mask.getRaster();
 
-        float[] rgb = new float[4];
-        float[] rgba = new float[4];
-        float[] alphaPixel = null;
+        int[] alphaRow = new int[width];
+        int[] rgbaRow = new int[4 * width];
         for (int y = 0; y < height; y++)
         {
+            src.getPixels(0, y, width, 1, rgbaRow);
+            alpha.getSamples(0, y, width, 1, 0, alphaRow);
             for (int x = 0; x < width; x++)
             {
-                src.getPixel(x, y, rgb);
-
-                rgba[0] = rgb[0];
-                rgba[1] = rgb[1];
-                rgba[2] = rgb[2];
-
-                alphaPixel = alpha.getPixel(x, y, alphaPixel);
+                int offset = x * 4;
                 if (isSoft)
                 {
-                    rgba[3] = alphaPixel[0];
-                    if (matte != null && Float.compare(alphaPixel[0], 0) != 0)
+                    rgbaRow[offset + 3] = alphaRow[x];
+                    if (matte != null && Integer.compare(alphaRow[x], 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);
+                        float k = alphaRow[x] / 255f;
+                        rgbaRow[offset + 0] = clampColor(((rgbaRow[offset + 0] / 255f - matte[0]) / k + matte[0]) * 255f);
+                        rgbaRow[offset + 1] = clampColor(((rgbaRow[offset + 1] / 255f - matte[1]) / k + matte[1]) * 255f);
+                        rgbaRow[offset + 2] = clampColor(((rgbaRow[offset + 2] / 255f - matte[2]) / k + matte[2]) * 255f);
                     }
                 }
                 else
                 {
-                    rgba[3] = 255 - alphaPixel[0];
+                    rgbaRow[offset + 3] = 255 - alphaRow[x];
                 }
-
-                dest.setPixel(x, y, rgba);
             }
+            dest.setPixels(0, y, width, 1, rgbaRow);
         }
-
         return masked;
     }
 
-    private float clampColor(float color)
+    private int clampColor(float color)
     {
-        return color < 0 ? 0 : (color > 255 ? 255 : color);        
+        return color < 0 ? 0 : (color > 255 ? 255 : Math.round(color));
     }
 
     /**
      * High-quality image scaling.
      */
-    private BufferedImage scaleImage(BufferedImage image, int width, int height)
+    private BufferedImage scaleImage(BufferedImage image, int width, int height, int type)
     {
-        BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        BufferedImage image2 = new BufferedImage(width, height, type);
         Graphics2D g = image2.createGraphics();
         if (getInterpolate())
         {