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/04/02 07:08:09 UTC

svn commit: r1888288 - in /pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox: pdmodel/graphics/shading/ rendering/

Author: tilman
Date: Fri Apr  2 07:08:09 2021
New Revision: 1888288

URL: http://svn.apache.org/viewvc?rev=1888288&view=rev
Log:
PDFBOX-5134: calculating the bounding boxes of the triangles reduces shading rendering times if no bounding box is preset, as suggested by Oliver Schmidtmer; Closes #109

Added:
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java   (with props)
Modified:
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType4.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType5.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType6.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType7.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDTriangleBasedShadingType.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PatchMeshesShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/TriangleBasedShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type4ShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type5ShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type6ShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type7ShadingContext.java
    pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java Fri Apr  2 07:08:09 2021
@@ -19,17 +19,13 @@ package org.apache.pdfbox.pdmodel.graphi
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import javax.imageio.stream.ImageInputStream;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.pdmodel.common.PDRange;
+
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -40,8 +36,6 @@ import org.apache.pdfbox.util.Matrix;
  */
 abstract class GouraudShadingContext extends TriangleBasedShadingContext
 {
-    private static final Log LOG = LogFactory.getLog(GouraudShadingContext.class);
-
     /**
      * triangle list.
      */
@@ -62,53 +56,6 @@ abstract class GouraudShadingContext ext
         super(shading, colorModel, xform, matrix);
     }
 
-    /**
-     * Read a vertex from the bit input stream performs interpolations.
-     *
-     * @param input bit input stream
-     * @param maxSrcCoord max value for source coordinate (2^bits-1)
-     * @param maxSrcColor max value for source color (2^bits-1)
-     * @param rangeX dest range for X
-     * @param rangeY dest range for Y
-     * @param colRangeTab dest range array for colors
-     * @param matrix the pattern matrix concatenated with that of the parent content stream
-     * @return a new vertex with the flag and the interpolated values
-     * @throws IOException if something went wrong
-     */
-    protected Vertex readVertex(ImageInputStream input, long maxSrcCoord, long maxSrcColor,
-                                PDRange rangeX, PDRange rangeY, PDRange[] colRangeTab,
-                                Matrix matrix, AffineTransform xform) throws IOException
-    {
-        float[] colorComponentTab = new float[numberOfColorComponents];
-        long x = input.readBits(bitsPerCoordinate);
-        long y = input.readBits(bitsPerCoordinate);
-        float dstX = interpolate(x, maxSrcCoord, rangeX.getMin(), rangeX.getMax());
-        float dstY = interpolate(y, maxSrcCoord, rangeY.getMin(), rangeY.getMax());
-        LOG.debug("coord: " + String.format("[%06X,%06X] -> [%f,%f]", x, y, dstX, dstY));
-        Point2D p = matrix.transformPoint(dstX, dstY);
-        xform.transform(p, p);
-
-        for (int n = 0; n < numberOfColorComponents; ++n)
-        {
-            int color = (int) input.readBits(bitsPerColorComponent);
-            colorComponentTab[n] = interpolate(color, maxSrcColor, colRangeTab[n].getMin(),
-                    colRangeTab[n].getMax());
-            LOG.debug("color[" + n + "]: " + color + "/" + String.format("%02x", color)
-                    + "-> color[" + n + "]: " + colorComponentTab[n]);
-        }
-
-        // "Each set of vertex data shall occupy a whole number of bytes.
-        // If the total number of bits required is not divisible by 8, the last data byte
-        // for each vertex is padded at the end with extra bits, which shall be ignored."
-        int bitOffset = input.getBitOffset();
-        if (bitOffset != 0)
-        {
-            input.readBits(8 - bitOffset);
-        }
-
-        return new Vertex(p, colorComponentTab);
-    }
-
     final void setTriangleList(List<ShadedTriangle> triangleList)
     {
         this.triangleList = triangleList;
@@ -129,20 +76,6 @@ abstract class GouraudShadingContext ext
         super.dispose();
     }
 
-    /**
-     * Calculate the interpolation, see p.345 pdf spec 1.7.
-     *
-     * @param src src value
-     * @param srcMax max src value (2^bits-1)
-     * @param dstMin min dst value
-     * @param dstMax max dst value
-     * @return interpolated value
-     */
-    private float interpolate(float src, long srcMax, float dstMin, float dstMax)
-    {
-        return dstMin + (src * (dstMax - dstMin) / srcMax);
-    }
-
     @Override
     protected boolean isDataEmpty()
     {

Added: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java?rev=1888288&view=auto
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java (added)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java Fri Apr  2 07:08:09 2021
@@ -0,0 +1,265 @@
+/*
+ * 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.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.MemoryCacheImageInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDRange;
+import org.apache.pdfbox.util.Matrix;
+
+/**
+ * Common resources for shading types 6 and 7
+ */
+abstract class PDMeshBasedShadingType extends PDShadingType4
+{
+
+    private static final Log LOG = LogFactory.getLog(PDMeshBasedShadingType.class);
+
+    PDMeshBasedShadingType(COSDictionary shadingDictionary)
+    {
+        super(shadingDictionary);
+    }
+
+    /**
+     * Create a patch list from a data stream, the returned list contains all the patches contained in the data stream.
+     *
+     * @param shadingType the shading type
+     * @param xform transformation for user to device space
+     * @param matrix the pattern matrix concatenated with that of the parent content stream
+     * @param controlPoints number of control points, 12 for type 6 shading and 16 for type 7 shading
+     * @return the obtained patch list
+     * @throws IOException when something went wrong
+     */
+    @SuppressWarnings({ "squid:S2583", "squid:S1166" })
+    final List<Patch> collectPatches(AffineTransform xform, Matrix matrix, int controlPoints)
+            throws IOException
+    {
+        COSDictionary dict = getCOSObject();
+        if (!(dict instanceof COSStream))
+        {
+            return Collections.emptyList();
+        }
+        PDRange rangeX = getDecodeForParameter(0);
+        PDRange rangeY = getDecodeForParameter(1);
+        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0
+                || Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
+        {
+            return Collections.emptyList();
+        }
+        int bitsPerFlag = getBitsPerFlag();
+        PDRange[] colRange = new PDRange[getNumberOfColorComponents()];
+        for (int i = 0; i < getNumberOfColorComponents(); ++i)
+        {
+            colRange[i] = getDecodeForParameter(2 + i);
+            if (colRange[i] == null)
+            {
+                throw new IOException("Range missing in shading /Decode entry");
+            }
+        }
+        List<Patch> list = new ArrayList<Patch>();
+        long maxSrcCoord = (long) Math.pow(2, getBitsPerCoordinate()) - 1;
+        long maxSrcColor = (long) Math.pow(2, getBitsPerComponent()) - 1;
+        COSStream cosStream = (COSStream) dict;
+
+        ImageInputStream mciis = new MemoryCacheImageInputStream(cosStream.createInputStream());
+        try
+        {
+            Point2D[] implicitEdge = new Point2D[4];
+            float[][] implicitCornerColor = new float[2][getNumberOfColorComponents()];
+            byte flag = 0;
+
+            try
+            {
+                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+            }
+            catch (EOFException ex)
+            {
+                LOG.error(ex);
+            }
+
+            boolean eof = false;
+            while (!eof)
+            {
+                try
+                {
+                    boolean isFree = (flag == 0);
+                    Patch current = readPatch(mciis, isFree, implicitEdge, implicitCornerColor,
+                            maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange, matrix, xform,
+                            controlPoints);
+                    if (current == null)
+                    {
+                        break;
+                    }
+                    list.add(current);
+                    flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+                    switch (flag)
+                    {
+                    case 0:
+                        break;
+                    case 1:
+                        implicitEdge = current.getFlag1Edge();
+                        implicitCornerColor = current.getFlag1Color();
+                        break;
+                    case 2:
+                        implicitEdge = current.getFlag2Edge();
+                        implicitCornerColor = current.getFlag2Color();
+                        break;
+                    case 3:
+                        implicitEdge = current.getFlag3Edge();
+                        implicitCornerColor = current.getFlag3Color();
+                        break;
+                    default:
+                        LOG.warn("bad flag: " + flag);
+                        break;
+                    }
+                }
+                catch (EOFException ex)
+                {
+                    eof = true;
+                }
+            }
+        }
+        finally
+        {
+            mciis.close();
+        }
+        return list;
+    }
+
+    /**
+     * Read a single patch from a data stream, a patch contains information of its coordinates and color parameters.
+     *
+     * @param input the image source data stream
+     * @param isFree whether this is a free patch
+     * @param implicitEdge implicit edge when a patch is not free, otherwise it's not used
+     * @param implicitCornerColor implicit colors when a patch is not free, otherwise it's not used
+     * @param maxSrcCoord the maximum coordinate value calculated from source data
+     * @param maxSrcColor the maximum color value calculated from source data
+     * @param rangeX range for coordinate x
+     * @param rangeY range for coordinate y
+     * @param colRange range for color
+     * @param matrix the pattern matrix concatenated with that of the parent content stream
+     * @param xform transformation for user to device space
+     * @param controlPoints number of control points, 12 for type 6 shading and 16 for type 7 shading
+     * @return a single patch
+     * @throws IOException when something went wrong
+     */
+    protected Patch readPatch(ImageInputStream input, boolean isFree, Point2D[] implicitEdge,
+            float[][] implicitCornerColor, long maxSrcCoord, long maxSrcColor, PDRange rangeX,
+            PDRange rangeY, PDRange[] colRange, Matrix matrix, AffineTransform xform,
+            int controlPoints) throws IOException
+    {
+        float[][] color = new float[4][getNumberOfColorComponents()];
+        Point2D[] points = new Point2D[controlPoints];
+        int pStart = 4, cStart = 2;
+        if (isFree)
+        {
+            pStart = 0;
+            cStart = 0;
+        }
+        else
+        {
+            points[0] = implicitEdge[0];
+            points[1] = implicitEdge[1];
+            points[2] = implicitEdge[2];
+            points[3] = implicitEdge[3];
+
+            for (int i = 0; i < getNumberOfColorComponents(); i++)
+            {
+                color[0][i] = implicitCornerColor[0][i];
+                color[1][i] = implicitCornerColor[1][i];
+            }
+        }
+
+        try
+        {
+            for (int i = pStart; i < controlPoints; i++)
+            {
+                long x = input.readBits(getBitsPerCoordinate());
+                long y = input.readBits(getBitsPerCoordinate());
+                float px = interpolate(x, maxSrcCoord, rangeX.getMin(), rangeX.getMax());
+                float py = interpolate(y, maxSrcCoord, rangeY.getMin(), rangeY.getMax());
+                Point2D p = matrix.transformPoint(px, py);
+                xform.transform(p, p);
+                points[i] = p;
+            }
+            for (int i = cStart; i < 4; i++)
+            {
+                for (int j = 0; j < getNumberOfColorComponents(); j++)
+                {
+                    long c = input.readBits(getBitsPerComponent());
+                    color[i][j] = interpolate(c, maxSrcColor, colRange[j].getMin(),
+                            colRange[j].getMax());
+                }
+            }
+        }
+        catch (EOFException ex)
+        {
+            LOG.debug("EOF", ex);
+            return null;
+        }
+        return generatePatch(points, color);
+    }
+
+    /**
+     * Create a patch using control points and 4 corner color values, in Type6ShadingContext, a CoonsPatch is returned;
+     * in Type6ShadingContext, a TensorPatch is returned.
+     *
+     * @param points 12 or 16 control points
+     * @param color 4 corner colors
+     * @return a patch instance
+     */
+    abstract Patch generatePatch(Point2D[] points, float[][] color);
+
+    @Override
+    abstract public Rectangle2D getBounds(AffineTransform xform, Matrix matrix) throws IOException;
+
+    Rectangle2D getBounds(AffineTransform xform, Matrix matrix, int controlPoints)
+            throws IOException
+    {
+        Rectangle2D bounds = null;
+        for (Patch patch : collectPatches(xform, matrix, controlPoints))
+        {
+            for (ShadedTriangle shadedTriangle : patch.listOfTriangles)
+            {
+                if (bounds == null)
+                {
+                    bounds = new Rectangle2D.Double(shadedTriangle.corner[0].getX(),
+                            shadedTriangle.corner[0].getY(), 0, 0);
+                }
+                bounds.add(shadedTriangle.corner[0]);
+                bounds.add(shadedTriangle.corner[1]);
+                bounds.add(shadedTriangle.corner[2]);
+            }
+        }
+        return bounds;
+    }
+}

Propchange: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDMeshBasedShadingType.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShading.java Fri Apr  2 07:08:09 2021
@@ -17,6 +17,8 @@
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
 import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
 import java.io.IOException;
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
@@ -196,6 +198,19 @@ public abstract class PDShading implemen
     }
 
     /**
+     * Calculate a bounding rectangle around the areas of this shading context.
+     * 
+     * @param xform
+     * @param matrix
+     * @return Bounding rectangle or null, if not supported by this shading type.
+     * @throws java.io.IOException
+     */
+    public Rectangle2D getBounds(AffineTransform xform, Matrix matrix) throws IOException
+    {
+        return null;
+    }
+
+    /**
      * This will set the AntiAlias value.
      *
      * @param antiAlias the new AntiAlias value

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType4.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType4.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType4.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType4.java Fri Apr  2 07:08:09 2021
@@ -17,9 +17,23 @@
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
 import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.MemoryCacheImageInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDRange;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -27,6 +41,8 @@ import org.apache.pdfbox.util.Matrix;
  */
 public class PDShadingType4 extends PDTriangleBasedShadingType
 {
+    private static final Log LOG = LogFactory.getLog(PDShadingType4.class);
+	
     /**
      * Constructor using the given shading dictionary.
      *
@@ -69,4 +85,118 @@ public class PDShadingType4 extends PDTr
     {
         return new Type4ShadingPaint(this, matrix);
     }
+    
+    @SuppressWarnings("squid:S1166")
+    @Override
+    List<ShadedTriangle> collectTriangles(AffineTransform xform, Matrix matrix)
+            throws IOException
+    {
+		int bitsPerFlag = getBitsPerFlag();
+        COSDictionary dict = getCOSObject();
+        if (!(dict instanceof COSStream))
+        {
+            return Collections.emptyList();
+        }
+        PDRange rangeX = getDecodeForParameter(0);
+        PDRange rangeY = getDecodeForParameter(1);
+        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0 ||
+            Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
+        {
+            return Collections.emptyList();
+        }
+        PDRange[] colRange = new PDRange[getNumberOfColorComponents()];
+        for (int i = 0; i < getNumberOfColorComponents(); ++i)
+        {
+            colRange[i] = getDecodeForParameter(2 + i);
+        }
+        List<ShadedTriangle> list = new ArrayList<ShadedTriangle>();
+        long maxSrcCoord = (long) Math.pow(2, getBitsPerCoordinate()) - 1;
+        long maxSrcColor = (long) Math.pow(2, getBitsPerComponent()) - 1;
+        COSStream stream = (COSStream) dict;
+
+        ImageInputStream mciis = new MemoryCacheImageInputStream(stream.createInputStream());
+        try
+        {
+            byte flag = (byte) 0;
+            try
+            {
+                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+            }
+            catch (EOFException ex)
+            {
+                LOG.error(ex);
+            }
+
+            boolean eof = false;
+            while (!eof)
+            {
+                Vertex p0, p1, p2;
+                Point2D[] ps;
+                float[][] cs;
+                int lastIndex;
+                try
+                {
+                    switch (flag)
+                    {
+                        case 0:
+                            p0 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
+                                            matrix, xform);
+                            flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+                            if (flag != 0)
+                            {
+                                LOG.error("bad triangle: " + flag);
+                            }
+                            p1 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
+                                            matrix, xform);
+                            mciis.readBits(bitsPerFlag);
+                            if (flag != 0)
+                            {
+                                LOG.error("bad triangle: " + flag);
+                            }
+                            p2 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
+                                            matrix, xform);
+                            ps = new Point2D[] { p0.point, p1.point, p2.point };
+                            cs = new float[][] { p0.color, p1.color, p2.color };
+                            list.add(new ShadedTriangle(ps, cs));
+                            flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+                            break;
+                        case 1:
+                        case 2:
+                            lastIndex = list.size() - 1;
+                            if (lastIndex < 0)
+                            {
+                                LOG.error("broken data stream: " + list.size());
+                            }
+                            else
+                            {
+                                ShadedTriangle preTri = list.get(lastIndex);
+                                p2 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY,
+                                                colRange, matrix, xform);
+                                ps = new Point2D[] { flag == 1 ? preTri.corner[1] : preTri.corner[0],
+                                                     preTri.corner[2],
+                                                     p2.point };
+                                cs = new float[][] { flag == 1 ? preTri.color[1] : preTri.color[0],
+                                                     preTri.color[2],
+                                                     p2.color };
+                                list.add(new ShadedTriangle(ps, cs));
+                                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
+                            }
+                            break;
+                        default:
+                            LOG.warn("bad flag: " + flag);
+                            break;
+                    }
+                }
+                catch (EOFException ex)
+                {
+                    eof = true;
+                }
+            }
+        }
+        finally
+        {
+            mciis.close();
+        }
+        return list;
+    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType5.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType5.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType5.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType5.java Fri Apr  2 07:08:09 2021
@@ -17,9 +17,21 @@
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
 import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.io.EOFException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.MemoryCacheImageInputStream;
 
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.pdmodel.common.PDRange;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -69,4 +81,101 @@ public class PDShadingType5 extends PDTr
     {
         return new Type5ShadingPaint(this, matrix);
     }
+    
+    @SuppressWarnings("squid:S1166")
+    @Override
+    List<ShadedTriangle> collectTriangles(AffineTransform xform, Matrix matrix) throws IOException
+    {
+        COSDictionary dict = getCOSObject();
+        if (!(dict instanceof COSStream))
+        {
+            return Collections.emptyList();
+        }
+        PDRange rangeX = getDecodeForParameter(0);
+        PDRange rangeY = getDecodeForParameter(1);
+        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0 ||
+            Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
+        {
+            return Collections.emptyList();
+        }
+        int numPerRow = getVerticesPerRow();
+        PDRange[] colRange = new PDRange[getNumberOfColorComponents()];
+        for (int i = 0; i < getNumberOfColorComponents(); ++i)
+        {
+            colRange[i] = getDecodeForParameter(2 + i);
+        }
+        List<Vertex> vlist = new ArrayList<Vertex>();
+        long maxSrcCoord = (long) Math.pow(2, getBitsPerCoordinate()) - 1;
+        long maxSrcColor = (long) Math.pow(2, getBitsPerComponent()) - 1;
+        COSStream cosStream = (COSStream) dict;
+
+        ImageInputStream mciis = new MemoryCacheImageInputStream(cosStream.createInputStream());
+        try
+        {
+            boolean eof = false;
+            while (!eof)
+            {
+                Vertex p;
+                try
+                {
+                    p = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange, matrix, xform);
+                    vlist.add(p);
+                }
+                catch (EOFException ex)
+                {
+                    eof = true;
+                }
+            }
+        }
+        finally
+        {
+            mciis.close();
+        }
+        int rowNum = vlist.size() / numPerRow;
+        Vertex[][] latticeArray = new Vertex[rowNum][numPerRow];
+        List<ShadedTriangle> list = new ArrayList<ShadedTriangle>();
+        if (rowNum < 2)
+        {
+            // must have at least two rows; if not, return empty list
+            return list;
+        }
+        for (int i = 0; i < rowNum; i++)
+        {
+            for (int j = 0; j < numPerRow; j++)
+            {
+                latticeArray[i][j] = vlist.get(i * numPerRow + j);
+            }
+        }
+
+        for (int i = 0; i < rowNum - 1; i++)
+        {
+            for (int j = 0; j < numPerRow - 1; j++)
+            {
+                Point2D[] ps = new Point2D[] {
+                    latticeArray[i][j].point,
+                    latticeArray[i][j + 1].point,
+                    latticeArray[i + 1][j].point  };
+
+                float[][] cs = new float[][] {
+                    latticeArray[i][j].color,
+                    latticeArray[i][j + 1].color,
+                    latticeArray[i + 1][j].color };
+
+                list.add(new ShadedTriangle(ps, cs));
+
+                ps = new Point2D[] {
+                    latticeArray[i][j + 1].point,
+                    latticeArray[i + 1][j].point,
+                    latticeArray[i + 1][j + 1].point };
+
+                cs = new float[][]{
+                    latticeArray[i][j + 1].color,
+                    latticeArray[i + 1][j].color,
+                    latticeArray[i + 1][j + 1].color };
+
+                list.add(new ShadedTriangle(ps, cs));
+            }
+        }
+        return list;
+    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType6.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType6.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType6.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType6.java Fri Apr  2 07:08:09 2021
@@ -17,6 +17,10 @@
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
 import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
 
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.util.Matrix;
@@ -24,7 +28,7 @@ import org.apache.pdfbox.util.Matrix;
 /**
  * Resources for a shading type 6 (Coons Patch Mesh).
  */
-public class PDShadingType6 extends PDShadingType4
+public class PDShadingType6 extends PDMeshBasedShadingType
 {
     /**
      * Constructor using the given shading dictionary.
@@ -47,4 +51,16 @@ public class PDShadingType6 extends PDSh
     {
         return new Type6ShadingPaint(this, matrix);
     }
+    
+    @Override
+    protected Patch generatePatch(Point2D[] points, float[][] color)
+    {
+        return new CoonsPatch(points, color);
+    }
+
+    @Override
+    public Rectangle2D getBounds(AffineTransform xform, Matrix matrix) throws IOException
+    {
+        return getBounds(xform, matrix, 12);
+    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType7.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType7.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType7.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDShadingType7.java Fri Apr  2 07:08:09 2021
@@ -17,6 +17,10 @@
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
 import java.awt.Paint;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
 
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.util.Matrix;
@@ -24,7 +28,7 @@ import org.apache.pdfbox.util.Matrix;
 /**
  * Resources for a shading type 7 (Tensor-Product Patch Mesh).
  */
-public class PDShadingType7 extends PDShadingType6
+public class PDShadingType7 extends PDMeshBasedShadingType
 {
     /**
      * Constructor using the given shading dictionary.
@@ -47,4 +51,16 @@ public class PDShadingType7 extends PDSh
     {
         return new Type7ShadingPaint(this, matrix);
     }
+    
+    @Override
+    protected Patch generatePatch(Point2D[] points, float[][] color)
+    {
+        return new TensorPatch(points, color);
+    }
+
+    @Override
+    public Rectangle2D getBounds(AffineTransform xform, Matrix matrix) throws IOException
+    {
+        return getBounds(xform, matrix, 16);
+    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDTriangleBasedShadingType.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDTriangleBasedShadingType.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDTriangleBasedShadingType.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PDTriangleBasedShadingType.java Fri Apr  2 07:08:09 2021
@@ -15,10 +15,21 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.shading;
 
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.List;
+
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.common.PDRange;
+import org.apache.pdfbox.util.Matrix;
 
 /**
  * Common resources for shading types 4,5,6 and 7
@@ -30,20 +41,30 @@ abstract class PDTriangleBasedShadingTyp
     // value: same as the value of Range
     private COSArray decode = null;
 
+    private static final Log LOG = LogFactory.getLog(TriangleBasedShadingContext.class);
+
+    private int bitsPerCoordinate = -1;
+    private int bitsPerColorComponent = -1;
+    private int numberOfColorComponents = -1;
+
     PDTriangleBasedShadingType(COSDictionary shadingDictionary)
     {
         super(shadingDictionary);
     }
 
     /**
-     * The bits per component of this shading. This will return -1 if one has
-     * not been set.
+     * The bits per component of this shading. This will return -1 if one has not been set.
      *
      * @return the number of bits per component
      */
     public int getBitsPerComponent()
     {
-        return getCOSObject().getInt(COSName.BITS_PER_COMPONENT, -1);
+        if (bitsPerColorComponent == -1)
+        {
+            bitsPerColorComponent = getCOSObject().getInt(COSName.BITS_PER_COMPONENT, -1);
+            LOG.debug("bitsPerColorComponent: " + bitsPerColorComponent);
+        }
+        return bitsPerColorComponent;
     }
 
     /**
@@ -54,6 +75,7 @@ abstract class PDTriangleBasedShadingTyp
     public void setBitsPerComponent(int bitsPerComponent)
     {
         getCOSObject().setInt(COSName.BITS_PER_COMPONENT, bitsPerComponent);
+        bitsPerColorComponent = bitsPerComponent;
     }
 
     /**
@@ -64,17 +86,39 @@ abstract class PDTriangleBasedShadingTyp
      */
     public int getBitsPerCoordinate()
     {
-        return getCOSObject().getInt(COSName.BITS_PER_COORDINATE, -1);
+        if (bitsPerCoordinate == -1)
+        {
+            bitsPerCoordinate = getCOSObject().getInt(COSName.BITS_PER_COORDINATE, -1);
+            LOG.debug("bitsPerCoordinate: " + (Math.pow(2, bitsPerCoordinate) - 1));
+        }
+        return bitsPerCoordinate;
     }
 
     /**
      * Set the number of bits per coordinate.
      *
-     * @param bitsPerComponent the number of bits per coordinate
+     * @param bitsPerCoordinate the number of bits per coordinate
      */
-    public void setBitsPerCoordinate(int bitsPerComponent)
+    public void setBitsPerCoordinate(int bitsPerCoordinate)
     {
-        getCOSObject().setInt(COSName.BITS_PER_COORDINATE, bitsPerComponent);
+        getCOSObject().setInt(COSName.BITS_PER_COORDINATE, bitsPerCoordinate);
+        this.bitsPerCoordinate = bitsPerCoordinate;
+    }
+    
+    /**
+     * The number of color components of this shading.
+     *
+     * @return number of color components of this shading
+     */
+    public int getNumberOfColorComponents() throws IOException
+    {
+        if (numberOfColorComponents == -1)
+        {
+            numberOfColorComponents = getFunction() != null ? 1
+                    : getColorSpace().getNumberOfComponents();
+            LOG.debug("numberOfColorComponents: " + numberOfColorComponents);
+        }
+        return numberOfColorComponents;
     }
 
     /**
@@ -118,5 +162,85 @@ abstract class PDTriangleBasedShadingTyp
         }
         return retval;
     }
+    
+    /**
+     * Calculate the interpolation, see p.345 pdf spec 1.7.
+     *
+     * @param src src value
+     * @param srcMax max src value (2^bits-1)
+     * @param dstMin min dst value
+     * @param dstMax max dst value
+     * @return interpolated value
+     */
+    protected float interpolate(float src, long srcMax, float dstMin, float dstMax)
+    {
+        return dstMin + (src * (dstMax - dstMin) / srcMax);
+    }
+    
+    /**
+     * Read a vertex from the bit input stream performs interpolations.
+     *
+     * @param input bit input stream
+     * @param maxSrcCoord max value for source coordinate (2^bits-1)
+     * @param maxSrcColor max value for source color (2^bits-1)
+     * @param rangeX dest range for X
+     * @param rangeY dest range for Y
+     * @param colRangeTab dest range array for colors
+     * @param matrix the pattern matrix concatenated with that of the parent content stream
+     * @return a new vertex with the flag and the interpolated values
+     * @throws IOException if something went wrong
+     */
+    protected Vertex readVertex(ImageInputStream input, long maxSrcCoord, long maxSrcColor,
+                                PDRange rangeX, PDRange rangeY, PDRange[] colRangeTab,
+                                Matrix matrix, AffineTransform xform) throws IOException
+    {
+        float[] colorComponentTab = new float[numberOfColorComponents];
+        long x = input.readBits(bitsPerCoordinate);
+        long y = input.readBits(bitsPerCoordinate);
+        float dstX = interpolate(x, maxSrcCoord, rangeX.getMin(), rangeX.getMax());
+        float dstY = interpolate(y, maxSrcCoord, rangeY.getMin(), rangeY.getMax());
+        LOG.debug("coord: " + String.format("[%06X,%06X] -> [%f,%f]", x, y, dstX, dstY));
+        Point2D p = matrix.transformPoint(dstX, dstY);
+        xform.transform(p, p);
+
+        for (int n = 0; n < numberOfColorComponents; ++n)
+        {
+            int color = (int) input.readBits(bitsPerColorComponent);
+            colorComponentTab[n] = interpolate(color, maxSrcColor, colRangeTab[n].getMin(),
+                    colRangeTab[n].getMax());
+            LOG.debug("color[" + n + "]: " + color + "/" + String.format("%02x", color)
+                    + "-> color[" + n + "]: " + colorComponentTab[n]);
+        }
 
+        // "Each set of vertex data shall occupy a whole number of bytes.
+        // If the total number of bits required is not divisible by 8, the last data byte
+        // for each vertex is padded at the end with extra bits, which shall be ignored."
+        int bitOffset = input.getBitOffset();
+        if (bitOffset != 0)
+        {
+            input.readBits(8 - bitOffset);
+        }
+
+        return new Vertex(p, colorComponentTab);
+    }
+
+    abstract List<ShadedTriangle> collectTriangles(AffineTransform xform, Matrix matrix) throws IOException;
+    
+    @Override
+    public Rectangle2D getBounds(AffineTransform xform, Matrix matrix) throws IOException
+    {
+        Rectangle2D bounds = null;
+        for (ShadedTriangle shadedTriangle : collectTriangles(xform, matrix))
+        {
+            if (bounds == null)
+            {
+                bounds = new Rectangle2D.Double(shadedTriangle.corner[0].getX(),
+                        shadedTriangle.corner[0].getY(), 0, 0);
+            }
+            bounds.add(shadedTriangle.corner[0]);
+            bounds.add(shadedTriangle.corner[1]);
+            bounds.add(shadedTriangle.corner[2]);
+        }
+        return bounds;
+    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PatchMeshesShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PatchMeshesShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PatchMeshesShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/PatchMeshesShadingContext.java Fri Apr  2 07:08:09 2021
@@ -18,22 +18,13 @@ package org.apache.pdfbox.pdmodel.graphi
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
-import java.io.EOFException;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import javax.imageio.stream.ImageInputStream;
-import javax.imageio.stream.MemoryCacheImageInputStream;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdmodel.common.PDRange;
+
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -44,7 +35,6 @@ import org.apache.pdfbox.util.Matrix;
  */
 abstract class PatchMeshesShadingContext extends TriangleBasedShadingContext
 {
-    private static final Log LOG = LogFactory.getLog(PatchMeshesShadingContext.class);
 
     /**
      * patch list
@@ -62,215 +52,15 @@ abstract class PatchMeshesShadingContext
      * @param controlPoints number of control points, 12 for type 6 shading and 16 for type 7 shading
      * @throws IOException if something went wrong
      */
-    protected PatchMeshesShadingContext(PDShadingType6 shading, ColorModel colorModel,
+    protected PatchMeshesShadingContext(PDMeshBasedShadingType shading, ColorModel colorModel,
             AffineTransform xform, Matrix matrix, Rectangle deviceBounds,
             int controlPoints) throws IOException
     {
         super(shading, colorModel, xform, matrix);
-        patchList = collectPatches(shading, xform, matrix, controlPoints);
+        patchList = shading.collectPatches(xform, matrix, controlPoints);
         createPixelTable(deviceBounds);
     }
 
-    /**
-     * Create a patch list from a data stream, the returned list contains all the patches contained
-     * in the data stream.
-     *
-     * @param shadingType the shading type
-     * @param xform transformation for user to device space
-     * @param matrix the pattern matrix concatenated with that of the parent content stream
-     * @param controlPoints number of control points, 12 for type 6 shading and 16 for type 7 shading
-     * @return the obtained patch list
-     * @throws IOException when something went wrong
-     */
-    final List<Patch> collectPatches(PDShadingType6 shadingType, AffineTransform xform,
-            Matrix matrix, int controlPoints) throws IOException
-    {
-        COSDictionary dict = shadingType.getCOSObject();
-        if (!(dict instanceof COSStream))
-        {
-            return Collections.emptyList();
-        }
-        PDRange rangeX = shadingType.getDecodeForParameter(0);
-        PDRange rangeY = shadingType.getDecodeForParameter(1);
-        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0 ||
-            Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
-        {
-            return Collections.emptyList();
-        }
-        int bitsPerFlag = shadingType.getBitsPerFlag();
-        PDRange[] colRange = new PDRange[numberOfColorComponents];
-        for (int i = 0; i < numberOfColorComponents; ++i)
-        {
-            colRange[i] = shadingType.getDecodeForParameter(2 + i);
-            if (colRange[i] == null)
-            {
-                throw new IOException("Range missing in shading /Decode entry");
-            }
-        }
-        List<Patch> list = new ArrayList<Patch>();
-        long maxSrcCoord = (long) Math.pow(2, bitsPerCoordinate) - 1;
-        long maxSrcColor = (long) Math.pow(2, bitsPerColorComponent) - 1;
-        COSStream cosStream = (COSStream) dict;
-
-        ImageInputStream mciis = new MemoryCacheImageInputStream(cosStream.createInputStream());
-        try
-        {
-            Point2D[] implicitEdge = new Point2D[4];
-            float[][] implicitCornerColor = new float[2][numberOfColorComponents];
-            byte flag = 0;
-
-            try
-            {
-                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-            }
-            catch (EOFException ex)
-            {
-                LOG.error(ex);
-            }
-
-            boolean eof = false;
-            while (!eof)
-            {
-                try
-                {
-                    boolean isFree = (flag == 0);
-                    Patch current = readPatch(mciis, isFree, implicitEdge, implicitCornerColor,
-                            maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange, matrix, xform, controlPoints);
-                    if (current == null)
-                    {
-                        break;
-                    }
-                    list.add(current);
-                    flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-                    switch (flag)
-                    {
-                        case 0:
-                            break;
-                        case 1:
-                            implicitEdge = current.getFlag1Edge();
-                            implicitCornerColor = current.getFlag1Color();
-                            break;
-                        case 2:
-                            implicitEdge = current.getFlag2Edge();
-                            implicitCornerColor = current.getFlag2Color();
-                            break;
-                        case 3:
-                            implicitEdge = current.getFlag3Edge();
-                            implicitCornerColor = current.getFlag3Color();
-                            break;
-                        default:
-                            LOG.warn("bad flag: " + flag);
-                            break;
-                    }
-                }
-                catch (EOFException ex)
-                {
-                    eof = true;
-                }
-            }
-        }
-        finally
-        {
-            mciis.close();
-        }
-        return list;
-    }
-
-    /**
-     * Read a single patch from a data stream, a patch contains information of its coordinates and
-     * color parameters.
-     *
-     * @param input the image source data stream
-     * @param isFree whether this is a free patch
-     * @param implicitEdge implicit edge when a patch is not free, otherwise it's not used
-     * @param implicitCornerColor implicit colors when a patch is not free, otherwise it's not used
-     * @param maxSrcCoord the maximum coordinate value calculated from source data
-     * @param maxSrcColor the maximum color value calculated from source data
-     * @param rangeX range for coordinate x
-     * @param rangeY range for coordinate y
-     * @param colRange range for color
-     * @param matrix the pattern matrix concatenated with that of the parent content stream
-     * @param xform transformation for user to device space
-     * @param controlPoints number of control points, 12 for type 6 shading and 16 for type 7 shading
-     * @return a single patch
-     * @throws IOException when something went wrong
-     */
-    protected Patch readPatch(ImageInputStream input, boolean isFree, Point2D[] implicitEdge,
-                              float[][] implicitCornerColor, long maxSrcCoord, long maxSrcColor,
-                              PDRange rangeX, PDRange rangeY, PDRange[] colRange, Matrix matrix,
-                              AffineTransform xform, int controlPoints) throws IOException
-    {
-        float[][] color = new float[4][numberOfColorComponents];
-        Point2D[] points = new Point2D[controlPoints];
-        int pStart = 4, cStart = 2;
-        if (isFree)
-        {
-            pStart = 0;
-            cStart = 0;
-        }
-        else
-        {
-            points[0] = implicitEdge[0];
-            points[1] = implicitEdge[1];
-            points[2] = implicitEdge[2];
-            points[3] = implicitEdge[3];
-
-            for (int i = 0; i < numberOfColorComponents; i++)
-            {
-                color[0][i] = implicitCornerColor[0][i];
-                color[1][i] = implicitCornerColor[1][i];
-            }
-        }
-
-        try
-        {
-            for (int i = pStart; i < controlPoints; i++)
-            {
-                long x = input.readBits(bitsPerCoordinate);
-                long y = input.readBits(bitsPerCoordinate);
-                float px = interpolate(x, maxSrcCoord, rangeX.getMin(), rangeX.getMax());
-                float py = interpolate(y, maxSrcCoord, rangeY.getMin(), rangeY.getMax());
-                Point2D p = matrix.transformPoint(px, py);
-                xform.transform(p, p);
-                points[i] = p;
-            }
-            for (int i = cStart; i < 4; i++)
-            {
-                for (int j = 0; j < numberOfColorComponents; j++)
-                {
-                    long c = input.readBits(bitsPerColorComponent);
-                    color[i][j] = interpolate(c, maxSrcColor, colRange[j].getMin(),
-                            colRange[j].getMax());
-                }
-            }
-        }
-        catch (EOFException ex)
-        {
-            LOG.debug("EOF");
-            return null;
-        }
-        return generatePatch(points, color);
-    }
-
-    /**
-     * Create a patch using control points and 4 corner color values, in
-     * Type6ShadingContext, a CoonsPatch is returned; in Type6ShadingContext, a
-     * TensorPatch is returned.
-     *
-     * @param points 12 or 16 control points
-     * @param color 4 corner colors
-     * @return a patch instance
-     */
-    abstract Patch generatePatch(Point2D[] points, float[][] color);
-
-    /**
-     * Get a point coordinate on a line by linear interpolation.
-     */
-    private float interpolate(float x, long maxValue, float rangeMin, float rangeMax)
-    {
-        return rangeMin + (x / maxValue) * (rangeMax - rangeMin);
-    }
-
     @Override
     protected Map<Point, Integer> calcPixelTable(Rectangle deviceBounds)  throws IOException
     {

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/TriangleBasedShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/TriangleBasedShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/TriangleBasedShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/TriangleBasedShadingContext.java Fri Apr  2 07:08:09 2021
@@ -38,14 +38,6 @@ import org.apache.pdfbox.util.Matrix;
  */
 abstract class TriangleBasedShadingContext extends ShadingContext implements PaintContext
 {
-    private static final Log LOG = LogFactory.getLog(TriangleBasedShadingContext.class);
-
-    protected int bitsPerCoordinate;
-    protected int bitsPerColorComponent;
-    protected int numberOfColorComponents;
-    
-    private final boolean hasFunction;
-
     // map of pixels within triangles to their RGB color
     private Map<Point, Integer> pixelTable;
 
@@ -62,14 +54,6 @@ abstract class TriangleBasedShadingConte
                                        Matrix matrix) throws IOException
     {
         super(shading, cm, xform, matrix);
-        PDTriangleBasedShadingType triangleBasedShadingType = (PDTriangleBasedShadingType) shading;
-        hasFunction = shading.getFunction() != null;
-        bitsPerCoordinate = triangleBasedShadingType.getBitsPerCoordinate();
-        LOG.debug("bitsPerCoordinate: " + (Math.pow(2, bitsPerCoordinate) - 1));
-        bitsPerColorComponent = triangleBasedShadingType.getBitsPerComponent();
-        LOG.debug("bitsPerColorComponent: " + bitsPerColorComponent);
-        numberOfColorComponents = hasFunction ? 1 : getShadingColorSpace().getNumberOfComponents();
-        LOG.debug("numberOfColorComponents: " + numberOfColorComponents);
     }
 
     /**
@@ -156,7 +140,7 @@ abstract class TriangleBasedShadingConte
      */
     private int evalFunctionAndConvertToRGB(float[] values) throws IOException
     {
-        if (hasFunction)
+        if (getShading().getFunction() != null)
         {
             values = getShading().evalFunction(values);
         }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type4ShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type4ShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type4ShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type4ShadingContext.java Fri Apr  2 07:08:09 2021
@@ -18,20 +18,11 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
-import java.io.EOFException;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import javax.imageio.stream.ImageInputStream;
-import javax.imageio.stream.MemoryCacheImageInputStream;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdmodel.common.PDRange;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -62,118 +53,7 @@ class Type4ShadingContext extends Gourau
         bitsPerFlag = shading.getBitsPerFlag();
         //TODO handle cases where bitperflag isn't 8
         LOG.debug("bitsPerFlag: " + bitsPerFlag);
-        setTriangleList(collectTriangles(shading, xform, matrix));
+        setTriangleList(shading.collectTriangles(xform, matrix));
         createPixelTable(deviceBounds);
     }
-
-    private List<ShadedTriangle> collectTriangles(PDShadingType4 freeTriangleShadingType, AffineTransform xform, Matrix matrix)
-            throws IOException
-    {
-        COSDictionary dict = freeTriangleShadingType.getCOSObject();
-        if (!(dict instanceof COSStream))
-        {
-            return Collections.emptyList();
-        }
-        PDRange rangeX = freeTriangleShadingType.getDecodeForParameter(0);
-        PDRange rangeY = freeTriangleShadingType.getDecodeForParameter(1);
-        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0 ||
-            Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
-        {
-            return Collections.emptyList();
-        }
-        PDRange[] colRange = new PDRange[numberOfColorComponents];
-        for (int i = 0; i < numberOfColorComponents; ++i)
-        {
-            colRange[i] = freeTriangleShadingType.getDecodeForParameter(2 + i);
-        }
-        List<ShadedTriangle> list = new ArrayList<ShadedTriangle>();
-        long maxSrcCoord = (long) Math.pow(2, bitsPerCoordinate) - 1;
-        long maxSrcColor = (long) Math.pow(2, bitsPerColorComponent) - 1;
-        COSStream stream = (COSStream) dict;
-
-        ImageInputStream mciis = new MemoryCacheImageInputStream(stream.createInputStream());
-        try
-        {
-            byte flag = (byte) 0;
-            try
-            {
-                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-            }
-            catch (EOFException ex)
-            {
-                LOG.error(ex);
-            }
-
-            boolean eof = false;
-            while (!eof)
-            {
-                Vertex p0, p1, p2;
-                Point2D[] ps;
-                float[][] cs;
-                int lastIndex;
-                try
-                {
-                    switch (flag)
-                    {
-                        case 0:
-                            p0 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
-                                            matrix, xform);
-                            flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-                            if (flag != 0)
-                            {
-                                LOG.error("bad triangle: " + flag);
-                            }
-                            p1 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
-                                            matrix, xform);
-                            mciis.readBits(bitsPerFlag);
-                            if (flag != 0)
-                            {
-                                LOG.error("bad triangle: " + flag);
-                            }
-                            p2 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange,
-                                            matrix, xform);
-                            ps = new Point2D[] { p0.point, p1.point, p2.point };
-                            cs = new float[][] { p0.color, p1.color, p2.color };
-                            list.add(new ShadedTriangle(ps, cs));
-                            flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-                            break;
-                        case 1:
-                        case 2:
-                            lastIndex = list.size() - 1;
-                            if (lastIndex < 0)
-                            {
-                                LOG.error("broken data stream: " + list.size());
-                            }
-                            else
-                            {
-                                ShadedTriangle preTri = list.get(lastIndex);
-                                p2 = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY,
-                                                colRange, matrix, xform);
-                                ps = new Point2D[] { flag == 1 ? preTri.corner[1] : preTri.corner[0],
-                                                     preTri.corner[2],
-                                                     p2.point };
-                                cs = new float[][] { flag == 1 ? preTri.color[1] : preTri.color[0],
-                                                     preTri.color[2],
-                                                     p2.color };
-                                list.add(new ShadedTriangle(ps, cs));
-                                flag = (byte) (mciis.readBits(bitsPerFlag) & 3);
-                            }
-                            break;
-                        default:
-                            LOG.warn("bad flag: " + flag);
-                            break;
-                    }
-                }
-                catch (EOFException ex)
-                {
-                    eof = true;
-                }
-            }
-        }
-        finally
-        {
-            mciis.close();
-        }
-        return list;
-    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type5ShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type5ShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type5ShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type5ShadingContext.java Fri Apr  2 07:08:09 2021
@@ -18,20 +18,11 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
-import java.io.EOFException;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import javax.imageio.stream.ImageInputStream;
-import javax.imageio.stream.MemoryCacheImageInputStream;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.pdfbox.cos.COSDictionary;
-import org.apache.pdfbox.cos.COSStream;
-import org.apache.pdfbox.pdmodel.common.PDRange;
 import org.apache.pdfbox.util.Matrix;
 
 /**
@@ -60,104 +51,7 @@ class Type5ShadingContext extends Gourau
 
         LOG.debug("Type5ShadingContext");
 
-        setTriangleList(collectTriangles(shading, xform, matrix));
+        setTriangleList(shading.collectTriangles(xform, matrix));
         createPixelTable(deviceBounds);
     }
-
-    private List<ShadedTriangle> collectTriangles(PDShadingType5 latticeTriangleShadingType,
-            AffineTransform xform, Matrix matrix) throws IOException
-    {
-        COSDictionary dict = latticeTriangleShadingType.getCOSObject();
-        if (!(dict instanceof COSStream))
-        {
-            return Collections.emptyList();
-        }
-        PDRange rangeX = latticeTriangleShadingType.getDecodeForParameter(0);
-        PDRange rangeY = latticeTriangleShadingType.getDecodeForParameter(1);
-        if (Float.compare(rangeX.getMin(), rangeX.getMax()) == 0 ||
-            Float.compare(rangeY.getMin(), rangeY.getMax()) == 0)
-        {
-            return Collections.emptyList();
-        }
-        int numPerRow = latticeTriangleShadingType.getVerticesPerRow();
-        PDRange[] colRange = new PDRange[numberOfColorComponents];
-        for (int i = 0; i < numberOfColorComponents; ++i)
-        {
-            colRange[i] = latticeTriangleShadingType.getDecodeForParameter(2 + i);
-        }
-        List<Vertex> vlist = new ArrayList<Vertex>();
-        long maxSrcCoord = (long) Math.pow(2, bitsPerCoordinate) - 1;
-        long maxSrcColor = (long) Math.pow(2, bitsPerColorComponent) - 1;
-        COSStream cosStream = (COSStream) dict;
-
-        ImageInputStream mciis = new MemoryCacheImageInputStream(cosStream.createInputStream());
-        try
-        {
-            boolean eof = false;
-            while (!eof)
-            {
-                Vertex p;
-                try
-                {
-                    p = readVertex(mciis, maxSrcCoord, maxSrcColor, rangeX, rangeY, colRange, matrix, xform);
-                    vlist.add(p);
-                }
-                catch (EOFException ex)
-                {
-                    eof = true;
-                }
-            }
-        }
-        finally
-        {
-            mciis.close();
-        }
-        int rowNum = vlist.size() / numPerRow;
-        Vertex[][] latticeArray = new Vertex[rowNum][numPerRow];
-        List<ShadedTriangle> list = new ArrayList<ShadedTriangle>();
-        if (rowNum < 2)
-        {
-            // must have at least two rows; if not, return empty list
-            return list;
-        }
-        for (int i = 0; i < rowNum; i++)
-        {
-            for (int j = 0; j < numPerRow; j++)
-            {
-                latticeArray[i][j] = vlist.get(i * numPerRow + j);
-            }
-        }
-
-        for (int i = 0; i < rowNum - 1; i++)
-        {
-            for (int j = 0; j < numPerRow - 1; j++)
-            {
-                Point2D[] ps = new Point2D[] {
-                    latticeArray[i][j].point,
-                    latticeArray[i][j + 1].point,
-                    latticeArray[i + 1][j].point  };
-
-                float[][] cs = new float[][] {
-                    latticeArray[i][j].color,
-                    latticeArray[i][j + 1].color,
-                    latticeArray[i + 1][j].color };
-
-                list.add(new ShadedTriangle(ps, cs));
-
-                ps = new Point2D[] {
-                    latticeArray[i][j + 1].point,
-                    latticeArray[i + 1][j].point,
-                    latticeArray[i + 1][j + 1].point };
-
-                cs = new float[][]{
-                    latticeArray[i][j + 1].color,
-                    latticeArray[i + 1][j].color,
-                    latticeArray[i + 1][j + 1].color };
-
-                list.add(new ShadedTriangle(ps, cs));
-            }
-        }
-        return list;
-    }
-
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type6ShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type6ShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type6ShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type6ShadingContext.java Fri Apr  2 07:08:09 2021
@@ -17,7 +17,6 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
 import java.io.IOException;
 import org.apache.pdfbox.util.Matrix;
@@ -45,10 +44,4 @@ class Type6ShadingContext extends PatchM
     {
         super(shading, colorModel, xform, matrix, deviceBounds, 12);
     }
-
-    @Override
-    protected Patch generatePatch(Point2D[] points, float[][] color)
-    {
-        return new CoonsPatch(points, color);
-    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type7ShadingContext.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type7ShadingContext.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type7ShadingContext.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/Type7ShadingContext.java Fri Apr  2 07:08:09 2021
@@ -17,7 +17,6 @@ package org.apache.pdfbox.pdmodel.graphi
 
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
-import java.awt.geom.Point2D;
 import java.awt.image.ColorModel;
 import java.io.IOException;
 import org.apache.pdfbox.util.Matrix;
@@ -45,10 +44,4 @@ class Type7ShadingContext extends PatchM
     {
         super(shading, colorModel, xform, matrix, deviceBounds, 16);
     }
-
-    @Override
-    protected Patch generatePatch(Point2D[] points, float[][] color)
-    {
-        return new TensorPatch(points, color);
-    }
 }

Modified: pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1888288&r1=1888287&r2=1888288&view=diff
==============================================================================
--- pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original)
+++ pdfbox/branches/2.0/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Fri Apr  2 07:08:09 2021
@@ -1413,7 +1413,20 @@ public class PageDrawer extends PDFGraph
         }
         else
         {
-            area = getGraphicsState().getCurrentClippingPath();
+            Rectangle2D bounds = shading.getBounds(new AffineTransform(), ctm);
+            if (bounds != null)
+            {
+                bounds.add(new Point2D.Double(Math.floor(bounds.getMinX() - 1),
+                        Math.floor(bounds.getMinY() - 1)));
+                bounds.add(new Point2D.Double(Math.ceil(bounds.getMaxX() + 1),
+                        Math.ceil(bounds.getMaxY() + 1)));
+                area = new Area(bounds);
+                area.intersect(getGraphicsState().getCurrentClippingPath());
+            }
+            else
+            {
+                area = getGraphicsState().getCurrentClippingPath();
+            }
         }
         if (isContentRendered())
         {