Author: lehmi
Date: Sat Nov  2 13:43:59 2013
New Revision: 1538191

URL: http://svn.apache.org/r1538191
Log:
PDFBOX-1764: optimize the calculation of function values/shading values to 
speed up rendering

Modified:
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType0.java
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java
    
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java?rev=1538191&r1=1538190&r2=1538191&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunction.java
 Sat Nov  2 13:43:59 2013
@@ -18,11 +18,11 @@ package org.apache.pdfbox.pdmodel.common
 
 import java.io.IOException;
 
+import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSObject;
-import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
 import org.apache.pdfbox.pdmodel.common.PDRange;
@@ -32,7 +32,7 @@ import org.apache.pdfbox.pdmodel.common.
  * This class represents a function in a PDF document.
  *
  * @author <a href="mailto:[email protected]";>Ben Litchfield</a>
- * @version $Revision: 1.3 $
+ * 
  */
 public abstract class PDFunction implements COSObjectable
 {
@@ -41,6 +41,8 @@ public abstract class PDFunction impleme
     private COSDictionary functionDictionary = null;
     private COSArray domain = null;
     private COSArray range = null;
+    private int numberOfInputValues = -1;
+    private int numberOfOutputValues = -1;
 
     /**
      * Constructor.
@@ -53,7 +55,7 @@ public abstract class PDFunction impleme
         if (function instanceof COSStream)
         {
             functionStream = new PDStream( (COSStream)function );
-            functionStream.getStream().setName( COSName.TYPE, "Function" );
+            functionStream.getStream().setItem( COSName.TYPE, COSName.FUNCTION 
);
         }
         else if (function instanceof COSDictionary)
         {
@@ -169,8 +171,12 @@ public abstract class PDFunction impleme
      */
     public int getNumberOfOutputParameters()
     {
-        COSArray rangeValues = getRangeValues();
-        return rangeValues.size() / 2;
+        if (numberOfOutputValues == -1)
+        {
+            COSArray rangeValues = getRangeValues();
+            numberOfOutputValues = rangeValues.size() / 2;
+        }
+        return numberOfOutputValues;
     }
 
     /**
@@ -208,8 +214,12 @@ public abstract class PDFunction impleme
      */
     public int getNumberOfInputParameters()
     {
-        COSArray array = getDomainValues();
-        return array.size() / 2;
+        if (numberOfInputValues == -1)
+        {
+            COSArray array = getDomainValues();
+            numberOfInputValues = array.size() / 2;
+        }
+        return numberOfInputValues;
     }
 
     /**

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType0.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType0.java?rev=1538191&r1=1538190&r2=1538191&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType0.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType0.java
 Sat Nov  2 13:43:59 2013
@@ -30,7 +30,7 @@ import org.apache.pdfbox.pdmodel.common.
  * This class represents a type 0 function in a PDF document.
  *
  * @author <a href="mailto:[email protected]";>Ben Litchfield</a>
- * @version $Revision: 1.2 $
+ * 
  */
 public class PDFunctionType0 extends PDFunction
 {
@@ -41,14 +41,14 @@ public class PDFunctionType0 extends PDF
     private static final Log log = LogFactory.getLog(PDFunctionType0.class);
 
     /**
-     * An array of 2 × m numbers specifying the linear mapping of input 
values 
-     * into the domain of the function’s sample table. 
-     * Default value: [ 0 (Size0 − 1) 0 (Size1 − 1) … ].
+     * An array of 2 x m numbers specifying the linear mapping of input values 
+     * into the domain of the function's sample table. 
+     * Default value: [ 0 (Size0 - 1) 0 (Size1 - 1) ...].
      */
     private COSArray encode = null;
     /**
-     * An array of 2 × n numbers specifying the linear mapping of sample 
values 
-     * into the range appropriate for the function’s output values. 
+     * An array of 2 x n numbers specifying the linear mapping of sample 
values 
+     * into the range appropriate for the function's output values. 
      * Default value: same as the value of Range
      */
     private COSArray decode = null;
@@ -298,16 +298,16 @@ public class PDFunctionType0 extends PDF
         int bitsPerSample = getBitsPerSample();
         int numberOfInputValues = input.length;
         int numberOfOutputValues = getNumberOfOutputParameters();
-        int[] intInputValuesPrevious = new int[numberOfInputValues];
-        int[] intInputValuesNext = new int[numberOfInputValues];
+        int intInputValuesPrevious = 0;
+        int intInputValuesNext = 0;
         for (int i=0; i<numberOfInputValues; i++) {
             PDRange domain = getDomainForInput(i);
             PDRange encode = getEncodeForParameter(i);
             input[i] = clipToRange(input[i], domain.getMin(), domain.getMax());
             input[i] = interpolate(input[i], domain.getMin(), domain.getMax(), 
encode.getMin(), encode.getMax());
             input[i] = clipToRange(input[i], 0, sizeValues[i]-1);
-            intInputValuesPrevious[i] = (int)Math.floor(input[i]);
-            intInputValuesNext[i] = (int)Math.ceil(input[i]);
+            intInputValuesPrevious += (int)Math.floor(input[i]);
+            intInputValuesNext += (int)Math.ceil(input[i]);
         }
         float[] outputValuesPrevious = null;
         float[] outputValuesNext = null;
@@ -331,26 +331,17 @@ public class PDFunctionType0 extends PDF
     /**
      * Get the samples for the given input values.
      * 
-     * @param inputValues an array containing the input values
+     * @param indexValue the index into the sample values array
      * @return an array with the corresponding samples
      */
-    private float[] getSample(int[] inputValues)
+    private float[] getSample(int indexValue)
     {
-        int[][] sampleValues = getSamples();
-        COSArray sizes = getSize();
-        int numberOfInputValues = getNumberOfInputParameters();
-        int index = 0;
-        int previousSize = 1;
-        for (int i=0;i<numberOfInputValues;i++)
+        int[] sampleValues = getSamples()[indexValue];
+        int numberOfValues = sampleValues.length;
+        float[] result = new float[numberOfValues];
+        for (int i=0;i<numberOfValues;i++)
         {
-            index += inputValues[i];
-            previousSize *= sizes.getInt(i);
-        }
-        int numberOfOutputValues = getNumberOfOutputParameters();
-        float[] result = new float[numberOfOutputValues];
-        for (int i=0;i<numberOfOutputValues;i++)
-        {
-            result[i] = sampleValues[index][i];
+            result[i] = sampleValues[i];
         }
         return result;
     }

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java?rev=1538191&r1=1538190&r2=1538191&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/AxialShadingContext.java
 Sat Nov  2 13:43:59 2013
@@ -39,7 +39,6 @@ import org.apache.pdfbox.util.Matrix;
  * This class represents the PaintContext of an axial shading.
  * 
  * @author lehmi
- * @version $Revision: $
  * 
  */
 public class AxialShadingContext implements PaintContext 
@@ -52,6 +51,8 @@ public class AxialShadingContext impleme
 
     private float[] coords;
     private float[] domain;
+    private int[] extend0Values;
+    private int[] extend1Values;
     private boolean[] extend;
     private double x1x0; 
     private double y1y0;
@@ -196,10 +197,13 @@ public class AxialShadingContext impleme
         // create writable raster
         WritableRaster raster = 
getColorModel().createCompatibleWritableRaster(w, h);
         int[] data = new int[w * h * 3];
+        boolean saveExtend0 = false;
+        boolean saveExtend1 = false;
         for (int j = 0; j < h; j++) 
         {
             for (int i = 0; i < w; i++) 
             {
+                int index = (j * w + i) * 3;
                 double inputValue = x1x0 * (x + i - coords[0]); 
                 inputValue += y1y0 * (y + j - coords[1]);
                 inputValue /= denom;
@@ -209,7 +213,17 @@ public class AxialShadingContext impleme
                     // the shading has to be extended if extend[0] == true
                     if (extend[0])
                     {
-                        inputValue = domain[0];
+                        if (extend0Values == null)
+                        {
+                            inputValue = domain[0];
+                            saveExtend0 = true;
+                        }
+                        else
+                        {
+                            // use the chached values
+                            System.arraycopy(extend0Values, 0, data, index, 3);
+                            continue;
+                        }
                     }
                     else 
                     {
@@ -222,7 +236,17 @@ public class AxialShadingContext impleme
                     // the shading has to be extended if extend[1] == true
                     if (extend[1])
                     {
-                        inputValue = domain[1];
+                        if (extend1Values == null)
+                        {
+                            inputValue = domain[1];
+                            saveExtend1 = true;
+                        }
+                        else
+                        {
+                            // use the chached values
+                            System.arraycopy(extend1Values, 0, data, index, 3);
+                            continue;
+                        }
                     }
                     else 
                     {
@@ -231,7 +255,6 @@ public class AxialShadingContext impleme
                 }
                 float input = (float)(domain[0] + (d1d0*inputValue));
                 float[] values = null;
-                int index = (j * w + i) * 3;
                 try 
                 {
                     values = shadingType.evalFunction(input);
@@ -252,6 +275,18 @@ public class AxialShadingContext impleme
                 data[index] = (int)(values[0]*255);
                 data[index+1] = (int)(values[1]*255);
                 data[index+2] = (int)(values[2]*255);
+                if (saveExtend0)
+                {
+                    // chache values
+                    extend0Values = new int[3];
+                    System.arraycopy(data, index, extend0Values, 0, 3);
+                }
+                if (saveExtend1)
+                {
+                    // chache values
+                    extend1Values = new int[3];
+                    System.arraycopy(data, index, extend1Values, 0, 3);
+                }
             }
         }
         raster.setPixels(0, 0, w, h, data);

Modified: 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java
URL: 
http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java?rev=1538191&r1=1538190&r2=1538191&view=diff
==============================================================================
--- 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java
 (original)
+++ 
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java
 Sat Nov  2 13:43:59 2013
@@ -39,7 +39,6 @@ import org.apache.pdfbox.util.Matrix;
  * This class represents the PaintContext of an radial shading.
  * 
  * @author lehmi
- * @version $Revision: $
  * 
  */
 public class RadialShadingContext implements PaintContext 
@@ -52,6 +51,8 @@ public class RadialShadingContext implem
 
     private float[] coords;
     private float[] domain;
+    private int[] extend0Values;
+    private int[] extend1Values;
     private boolean[] extend;
     private double x1x0; 
     private double y1y0;
@@ -207,11 +208,14 @@ public class RadialShadingContext implem
         // create writable raster
         WritableRaster raster = 
getColorModel().createCompatibleWritableRaster(w, h);
         float inputValue;
+        boolean saveExtend0 = false;
+        boolean saveExtend1 = false;
         int[] data = new int[w * h * 3];
         for (int j = 0; j < h; j++) 
         {
             for (int i = 0; i < w; i++) 
             {
+                int index = (j * w + i) * 3;
                 float[] inputValues = calculateInputValues(x + i, y + j);
                 // choose 1 of the 2 values
                 if (inputValues[0] >= domain[0] && inputValues[0] <= domain[1])
@@ -247,7 +251,17 @@ public class RadialShadingContext implem
                     // the shading has to be extended if extend[0] == true
                     if (extend[0])
                     {
-                        inputValue = domain[0];
+                        if (extend0Values == null)
+                        {
+                            inputValue = domain[0];
+                            saveExtend0 = true;
+                        }
+                        else
+                        {
+                            // use the chached values
+                            System.arraycopy(extend0Values, 0, data, index, 3);
+                            continue;
+                        }
                     }
                     else 
                     {
@@ -260,7 +274,17 @@ public class RadialShadingContext implem
                     // the shading has to be extended if extend[1] == true
                     if (extend[1])
                     {
-                        inputValue = domain[1];
+                        if (extend1Values == null)
+                        {
+                            inputValue = domain[1];
+                            saveExtend1 = true;
+                        }
+                        else
+                        {
+                            // use the chached values 
+                            System.arraycopy(extend1Values, 0, data, index, 3);
+                            continue;
+                        }
                     }
                     else 
                     {
@@ -269,7 +293,6 @@ public class RadialShadingContext implem
                 }
                 float input = (float)(domain[0] + (d1d0*inputValue));
                 float[] values = null;
-                int index = (j * w + i) * 3;
                 try 
                 {
                     values = shadingType.evalFunction(input);
@@ -290,6 +313,18 @@ public class RadialShadingContext implem
                 data[index] = (int)(values[0]*255);
                 data[index+1] = (int)(values[1]*255);
                 data[index+2] = (int)(values[2]*255);
+                if (saveExtend0)
+                {
+                    // chache values
+                    extend0Values = new int[3];
+                    System.arraycopy(data, index, extend0Values, 0, 3);
+                }
+                if (saveExtend1)
+                {
+                    // chache values
+                    extend1Values = new int[3];
+                    System.arraycopy(data, index, extend1Values, 0, 3);
+                }
             }
         }
         raster.setPixels(0, 0, w, h, data);


Reply via email to