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 2022/01/04 12:08:59 UTC

[pdfbox-jbig2] branch master updated: PDFBOX-5220, closes #4: optimize bitmaps based on a proposal by gunnar-ifp

This is an automated email from the ASF dual-hosted git repository.

lehmi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pdfbox-jbig2.git


The following commit(s) were added to refs/heads/master by this push:
     new cc22e49  PDFBOX-5220, closes #4: optimize bitmaps based on a proposal by gunnar-ifp
cc22e49 is described below

commit cc22e4940f1f29400cd610d7f5e4105fa5fba7a9
Author: Andreas Lehmkühler <an...@lehmi.de>
AuthorDate: Tue Jan 4 13:08:25 2022 +0100

    PDFBOX-5220, closes #4: optimize bitmaps based on a proposal by
    gunnar-ifp
---
 src/main/java/org/apache/pdfbox/jbig2/Bitmap.java  | 14 ++++
 .../org/apache/pdfbox/jbig2/image/Bitmaps.java     | 87 +++++++++++++---------
 2 files changed, 65 insertions(+), 36 deletions(-)

diff --git a/src/main/java/org/apache/pdfbox/jbig2/Bitmap.java b/src/main/java/org/apache/pdfbox/jbig2/Bitmap.java
index b186e9f..7784285 100644
--- a/src/main/java/org/apache/pdfbox/jbig2/Bitmap.java
+++ b/src/main/java/org/apache/pdfbox/jbig2/Bitmap.java
@@ -248,4 +248,18 @@ public class Bitmap
         Bitmap other = (Bitmap)obj;
         return Arrays.equals(bitmap, other.bitmap);
     }
+    
+    /**
+     * Copy parts of the underlying array of a Bitmap to another Bitmap.
+     *  
+     * @param src the source Bitmap
+     * @param srcPos start position within the source Bitmap
+     * @param dest the destination Bitmap
+     * @param destPos start position within the destination Bitmap
+     * @param length the number of bytes to be copied
+     */
+    public static void arraycopy(Bitmap src, int srcPos, Bitmap dest, int destPos,  int length)
+    {
+        System.arraycopy(src.bitmap, srcPos, dest.bitmap, destPos, length);
+    }
 }
diff --git a/src/main/java/org/apache/pdfbox/jbig2/image/Bitmaps.java b/src/main/java/org/apache/pdfbox/jbig2/image/Bitmaps.java
index c32aeaa..3842efe 100644
--- a/src/main/java/org/apache/pdfbox/jbig2/image/Bitmaps.java
+++ b/src/main/java/org/apache/pdfbox/jbig2/image/Bitmaps.java
@@ -23,7 +23,9 @@ import java.awt.Rectangle;
 import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
 import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
 import java.awt.image.IndexColorModel;
+import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
 
 import javax.imageio.ImageReadParam;
@@ -170,47 +172,45 @@ public class Bitmaps
     private static WritableRaster buildRaster(final Bitmap bitmap, final FilterType filterType,
             final double scaleX, final double scaleY)
     {
-        final Rectangle dstBounds = new Rectangle(0, 0, //
-                (int) Math.round(bitmap.getWidth() * scaleX), //
-                (int) Math.round(bitmap.getHeight() * scaleY));
-
-        WritableRaster dst;
-
+        final int height = bitmap.getHeight();
+        final int width = bitmap.getWidth();
+        final WritableRaster raster;
+        
         if (scaleX != 1 || scaleY != 1)
         {
-            dst = WritableRaster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
-                    dstBounds.width, dstBounds.height, 1, new Point());
+            final Rectangle bounds = new Rectangle(0, 0, //
+                    (int) Math.round(width * scaleX), //
+                    (int) Math.round(height * scaleY));
+
+            raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
+                    bounds.width, bounds.height, 1, new Point());
 
-            // scaling required
             final Resizer resizer = new Resizer(scaleX, scaleY);
             final Filter filter = Filter.byType(filterType);
-            resizer.resize(bitmap, bitmap.getBounds() /* sourceRegion */, dst, dstBounds, filter,
+            resizer.resize(bitmap, bitmap.getBounds() /* sourceRegion */, raster, bounds, filter,
                     filter);
         }
         else
         {
-            dst = WritableRaster.createPackedRaster(DataBuffer.TYPE_BYTE,
-                    dstBounds.width, dstBounds.height, 1, 1, new Point());
-
-            // scaling not required, paste bitmap into raster pixel per pixel
-            int byteIndex = 0;
-            for (int y = 0; y < bitmap.getHeight(); y++)
+            // scaling not required: clone and invert bitmap into packed raster
+            // extra care is taken to ensure padding bits are set to zero
+            final int bytes = width / 8;
+            final int bits = (~0xff >> (width & 7)) & 0xff;
+            final byte[] dst = new byte[height * bitmap.getRowStride()];
+            for ( int idx = 0, row = height; row>0; row-- ) 
             {
-                for (int x = 0; x < bitmap.getWidth(); byteIndex++)
+                for ( int count = bytes; count>0; count-- ) 
                 {
-                    final int pixels = (~bitmap.getByte(byteIndex)) & 0xFF;
-                    final int relevantPixels = bitmap.getWidth() - x > 8 ? 8
-                            : bitmap.getWidth() - x;
-                    final int endIdx = 7 - relevantPixels;
-                    for (int bytePosition = 7; bytePosition > endIdx; bytePosition--, x++)
-                    {
-                        dst.setSample(x, y, 0, (pixels >> bytePosition) & 0x1);
-                    }
+                    dst[idx] = (byte)~bitmap.getByte(idx++);
+                }
+                if ( bits!=0 )
+                {
+                    dst[idx] = (byte)(~bitmap.getByte(idx++) & bits);
                 }
             }
+            raster = Raster.createPackedRaster(new DataBufferByte(dst, dst.length), width, height, 1, new Point());
         }
-
-        return dst;
+        return raster;
     }
 
     /**
@@ -594,19 +594,34 @@ public class Bitmaps
     private static void blitUnshifted(Bitmap src, Bitmap dst, int startLine, int lastLine,
             int dstStartIdx, int srcStartIdx, int srcEndIdx, CombinationOperator op)
     {
-
-        for (int dstLine = startLine; dstLine < lastLine; dstLine++, dstStartIdx += dst
-                .getRowStride(), srcStartIdx += src.getRowStride(), srcEndIdx += src.getRowStride())
+        final int length = srcEndIdx - srcStartIdx + 1; // srcEndIdx is inclusive 
+        int srcStartOffset = srcStartIdx;
+        int dstStartOffset = dstStartIdx;
+        for ( int lines = lastLine - startLine; lines > 0; lines-- ) 
         {
-            int dstIdx = dstStartIdx;
-
+            int srcIdx = srcStartOffset;
+            int dstIdx = dstStartOffset;
+            int count = length;
             // Go through the bytes in a line of the Symbol
-            for (int srcIdx = srcStartIdx; srcIdx <= srcEndIdx; srcIdx++)
+            switch (op) 
             {
-                byte oldByte = dst.getByte(dstIdx);
-                byte newByte = src.getByte(srcIdx);
-                dst.setByte(dstIdx++, Bitmaps.combineBytes(oldByte, newByte, op));
+                case OR:   
+                case AND:  
+                case XOR:  
+                case XNOR: 
+                    while ( count-- > 0 ) 
+                    {
+                        dst.setByte(dstIdx, combineBytes(src.getByte(srcIdx++), dst.getByte(dstIdx++), op));
+                    }
+                    break;
+                case REPLACE:
+                    Bitmap.arraycopy(src, srcIdx, dst, dstIdx, count);
+                    break;
+                default:
+                    break;
             }
+            srcStartOffset += src.getRowStride();
+            dstStartOffset += dst.getRowStride();
         }
     }