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 2012/02/01 21:37:40 UTC

svn commit: r1239309 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics: pattern/PDShadingPatternResources.java shading/RadialShadingContext.java shading/RadialShadingPaint.java xobject/PDJpeg.java

Author: lehmi
Date: Wed Feb  1 20:37:39 2012
New Revision: 1239309

URL: http://svn.apache.org/viewvc?rev=1239309&view=rev
Log:
PDFBOX-615, PDFBOX-1094: added the implementation of a radial shading

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/xobject/PDJpeg.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java?rev=1239309&r1=1239308&r2=1239309&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/pattern/PDShadingPatternResources.java Wed Feb  1 20:37:39 2012
@@ -33,6 +33,8 @@ import org.apache.pdfbox.pdmodel.graphic
 import org.apache.pdfbox.pdmodel.graphics.shading.AxialShadingPaint;
 import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingResources;
 import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType2;
+import org.apache.pdfbox.pdmodel.graphics.shading.PDShadingType3;
+import org.apache.pdfbox.pdmodel.graphics.shading.RadialShadingPaint;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -206,8 +208,10 @@ public class PDShadingPatternResources e
             case PDShadingResources.SHADING_TYPE2:
                 paint = new AxialShadingPaint((PDShadingType2)getShading(), null, pageHeight);
                 break;
-            case PDShadingResources.SHADING_TYPE1: 
             case PDShadingResources.SHADING_TYPE3:
+                paint = new RadialShadingPaint((PDShadingType3)getShading(), null, pageHeight);
+                break;
+            case PDShadingResources.SHADING_TYPE1: 
             case PDShadingResources.SHADING_TYPE4:
             case PDShadingResources.SHADING_TYPE5:
             case PDShadingResources.SHADING_TYPE6:

Added: 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=1239309&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingContext.java Wed Feb  1 20:37:39 2012
@@ -0,0 +1,325 @@
+/*
+ * 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.shading;
+
+import java.awt.PaintContext;
+import java.awt.color.ColorSpace;
+import java.awt.geom.AffineTransform;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBoolean;
+import org.apache.pdfbox.pdmodel.common.function.PDFunction;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceRGB;
+import org.apache.pdfbox.util.Matrix;
+
+/**
+ * This class represents the PaintContext of an radial shading.
+ * 
+ * @author lehmi
+ * @version $Revision: $
+ * 
+ */
+public class RadialShadingContext implements PaintContext 
+{
+
+    private ColorModel colorModel;
+    private PDFunction function;
+    private ColorSpace shadingColorSpace;
+
+    private float[] coords;
+    private float[] domain;
+    private boolean[] extend;
+    private double x1x0; 
+    private double y1y0;
+    private double r1r0;
+    private double x1x0pow2;
+    private double y1y0pow2;
+    private double r0pow2;
+
+    private float d1d0;
+    private double denom;
+    
+    /**
+     * Log instance.
+     */
+    private static final Log LOG = LogFactory.getLog(AxialShadingContext.class);
+
+    /**
+     * Constructor creates an instance to be used for fill operations.
+     * 
+     * @param shadingType3 the shading type to be used
+     * @param colorModelValue the color model to be used
+     * @param xform transformation for user to device space
+     * @param ctm current transformation matrix
+     * @param pageHeight height of the current page
+     * 
+     */
+    public RadialShadingContext(PDShadingType3 shadingType3, ColorModel colorModelValue, 
+            AffineTransform xform, Matrix ctm, int pageHeight) 
+    {
+        coords = shadingType3.getCoords().toFloatArray();
+        if (ctm != null)
+        {
+            // the shading is used in combination with the sh-operator
+            float[] coordsTemp = new float[coords.length]; 
+            // transform the coords from shading to user space
+            ctm.createAffineTransform().transform(coords, 0, coordsTemp, 0, 1);
+            ctm.createAffineTransform().transform(coords, 3, coordsTemp, 3, 1);
+            // move the 0,0-reference
+            coordsTemp[1] = pageHeight - coordsTemp[1];
+            coordsTemp[4] = pageHeight - coordsTemp[4];
+            // transform the coords from user to device space
+            xform.transform(coordsTemp, 0, coords, 0, 1);
+            xform.transform(coordsTemp, 3, coords, 3, 1);
+        }
+        else
+        {
+            // the shading is used as pattern colorspace in combination
+            // with a fill-, stroke- or showText-operator
+            float translateY = (float)xform.getTranslateY();
+            // move the 0,0-reference including the y-translation from user to device space
+            coords[1] = pageHeight + translateY - coords[1];
+            coords[4] = pageHeight + translateY - coords[4];
+        }
+        // colorSpace 
+        try 
+        {
+            PDColorSpace cs = shadingType3.getColorSpace();
+            if (!(cs instanceof PDDeviceRGB))
+            {
+                // we have to create an instance of the shading colorspace if it isn't RGB
+                shadingColorSpace = cs.getJavaColorSpace();
+            }
+        } 
+        catch (IOException exception) 
+        {
+            LOG.error("error while creating colorSpace", exception);
+        }
+        // colorModel
+        if (colorModelValue != null)
+        {
+            colorModel = colorModelValue;
+        }
+        else
+        {
+            try
+            {
+                // TODO bpc != 8 ??  
+                colorModel = shadingType3.getColorSpace().createColorModel(8);
+            }
+            catch(IOException exception)
+            {
+                LOG.error("error while creating colorModel", exception);
+            }
+        }
+        // shading function
+        try
+        {
+            function = shadingType3.getFunction();
+        }
+        catch(IOException exception)
+        {
+            LOG.error("error while creating a function", exception);
+        }
+        // domain values
+        if (shadingType3.getDomain() != null)
+        {
+            domain = shadingType3.getDomain().toFloatArray();
+        }
+        else 
+        {
+            // set default values
+            domain = new float[]{0,1};
+        }
+        // extend values
+        COSArray extendValues = shadingType3.getExtend();
+        if (shadingType3.getExtend() != null)
+        {
+            extend = new boolean[2];
+            extend[0] = ((COSBoolean)extendValues.get(0)).getValue();
+            extend[1] = ((COSBoolean)extendValues.get(1)).getValue();
+        }
+        else
+        {
+            // set default values
+            extend = new boolean[]{false,false};
+        }
+        // calculate some constants to be used in getRaster
+        x1x0 = coords[3] - coords[0]; 
+        y1y0 = coords[4] - coords[1];
+        r1r0 = coords[5] - coords[2];
+        x1x0pow2 = Math.pow(x1x0,2);
+        y1y0pow2 = Math.pow(y1y0,2);
+        r0pow2 = Math.pow(coords[2],2);
+        denom = x1x0pow2 + y1y0pow2 - Math.pow(r1r0, 2);
+        d1d0 = domain[1]-domain[0];
+        // TODO take a possible Background value into account
+        
+    }
+    /**
+     * {@inheritDoc}
+     */
+    public void dispose() 
+    {
+        colorModel = null;
+        function = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ColorModel getColorModel() 
+    {
+        return colorModel;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Raster getRaster(int x, int y, int w, int h) 
+    {
+        // create writable raster
+        WritableRaster raster = getColorModel().createCompatibleWritableRaster(w, h);
+        float[] input = new float[1];
+        float inputValue;
+        int[] data = new int[w * h * 3];
+        for (int j = 0; j < h; j++) 
+        {
+            for (int i = 0; i < w; i++) 
+            {
+                float[] inputValues = calculateInputValues(x + i, y + j);
+                // choose 1 of the 2 values
+                if (inputValues[0] >= domain[0] && inputValues[0] <= domain[1])
+                {
+                    // both values are in the domain -> choose the larger one 
+                    if(inputValues[1] >= domain[0] && inputValues[1] <= domain[1])
+                    {
+                        inputValue = Math.max(inputValues[0], inputValues[1]);
+                    } 
+                    // first value is in the domain, the second not -> choose first value
+                    else
+                    {
+                        inputValue = inputValues[0];
+                    }
+                }
+                else
+                {
+                    // first value is not in the domain, but the second -> choose second value
+                    if(inputValues[1] >= domain[0] && inputValues[1] <= domain[1])
+                    {
+                        inputValue = inputValues[1];
+                    }
+                    // TODO
+                    // both are not in the domain -> choose the first as I don't know it better
+                    else
+                    {
+                        inputValue = inputValues[0];
+                    }
+                }
+                // input value is out of range
+                if (inputValue < domain[0])
+                {
+                    // the shading has to be extended if extend[0] == true
+                    if (extend[0])
+                    {
+                        inputValue = domain[0];
+                    }
+                    else 
+                    {
+                        continue;
+                    }
+                }
+                // input value is out of range
+                else if (inputValue > domain[1])
+                {
+                    // the shading has to be extended if extend[1] == true
+                    if (extend[1])
+                    {
+                        inputValue = domain[1];
+                    }
+                    else 
+                    {
+                        continue;
+                    }
+                }
+                input[0] = (float)(domain[0] + (d1d0*inputValue));
+                float[] values = null;
+                try 
+                {
+                    values = function.eval(input);
+                } 
+                catch (IOException exception) 
+                {
+                    LOG.error("error while processing a function", exception);
+                }
+                int index = (j * w + i) * 3;
+                // convert color values from shading colorspace to RGB 
+                if (shadingColorSpace != null)
+                {
+                    values = shadingColorSpace.toRGB(values);
+                }
+                data[index] = (int)(values[0]*255);
+                data[index+1] = (int)(values[1]*255);
+                data[index+2] = (int)(values[2]*255);
+            }
+        }
+        raster.setPixels(0, 0, w, h, data);
+        return raster;
+    }
+
+    private float[] calculateInputValues(int x, int y) 
+    {
+        
+        /** 
+         *  According to Adobes Technical Note #5600 we have to do the following 
+         *  
+         *  x0, y0, r0 defines the start circle
+         *  x1, y1, r1 defines the end circle
+         *  
+         *  The parametric equations for the center and radius of the gradient fill
+         *  circle moving between the start circle and the end circle as a function 
+         *  of s are as follows:
+         *  
+         *  xc(s) = x0 + s * (x1 - x0)
+         *  yc(s) = y0 + s * (y1 - y0)
+         *  r(s)  = r0 + s * (r1 - r0)
+         * 
+         *  Given a geometric coordinate position (x, y) in or along the gradient fill, 
+         *  the corresponding value of s can be determined by solving the quadratic 
+         *  constraint equation:
+         *  
+         *  [x - xc(s)]2 + [y - yc(s)]2 = [r(s)]2
+         *  
+         *  The following code calculates the 2 possible values of s
+         */
+        
+        float[] values = new float[2];
+        double p = (-0.25)*((x - coords[0])*x1x0 + (y - coords[1])*y1y0 - r1r0) / denom;
+        double q = (Math.pow(x - coords[0],2) + Math.pow(y - coords[1],2) - r0pow2) / denom;
+        double root = Math.sqrt(Math.pow(p , 2) - q);
+        values[0] = (float)((-1)*p + root);
+        values[1] = (float)((-1)*p - root);
+        return values;
+    }
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java?rev=1239309&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/RadialShadingPaint.java Wed Feb  1 20:37:39 2012
@@ -0,0 +1,73 @@
+/*
+ * 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.shading;
+
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ColorModel;
+
+import org.apache.pdfbox.util.Matrix;
+
+/**
+ * This represents the Paint of an radial shading.
+ * 
+ * @author lehmi
+ * @version $Revision: $
+ * 
+ */
+public class RadialShadingPaint implements Paint 
+{
+
+    private PDShadingType3 shading;
+    private Matrix currentTransformationMatrix;
+    private int pageHeight;
+    
+    /**
+     * Constructor.
+     * 
+     * @param shadingType3 the shading resources
+     * @param ctm current transformation matrix
+     * @param pageSizeValue size of the current page
+     */
+    public RadialShadingPaint(PDShadingType3 shadingType3, Matrix ctm, int pageHeightValue) 
+    {
+        shading = shadingType3;
+        currentTransformationMatrix = ctm;
+        pageHeight = pageHeightValue;
+    }
+    /**
+     * {@inheritDoc}
+     */
+    public int getTransparency() 
+    {
+        return 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform xform, RenderingHints hints) 
+    {
+        return new RadialShadingContext(shading, cm, xform, currentTransformationMatrix, pageHeight);
+    }
+
+}

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=1239309&r1=1239308&r2=1239309&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 Wed Feb  1 20:37:39 2012
@@ -167,8 +167,11 @@ public class PDJpeg extends PDXObjectIma
             {
                 for(int x = 0; x < alphaWidth; x++)
                 {
-                    Color color = new Color(alpha.getRGB(x, y));
-                    if(color.getRed() != 0 && color.getGreen() != 0 && color.getBlue() != 0)
+                    int colorValues = alpha.getRGB(x, y);
+                    // TODO check condition PDFBOX-626
+                    if( ((colorValues >> 16) & 0xFF) != 0 
+                            && ((colorValues >> 8) & 0xFF) != 0 
+                            && ((colorValues >> 0) & 0xFF) != 0 )
                     {
                         alpha.setRGB(x, y, whiteRGB);
                     }