You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2014/06/17 02:20:18 UTC

svn commit: r1603033 - in /pdfbox/trunk: examples/src/main/java/org/apache/pdfbox/examples/util/ pdfbox/src/main/java/org/apache/pdfbox/cos/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/g...

Author: jahewson
Date: Tue Jun 17 00:20:17 2014
New Revision: 1603033

URL: http://svn.apache.org/r1603033
Log:
PDFBOX-2104: Implement transparency groups, as proposed by Petr Slaby

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java
Modified:
    pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamEngine.java
    pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamWrapper.java

Modified: pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java (original)
+++ pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/util/PrintImageLocations.java Tue Jun 17 00:20:17 2014
@@ -164,7 +164,7 @@ public class PrintImageLocations extends
             else if(xobject instanceof PDFormXObject)
             {
                 // save the graphics state
-                getGraphicsStack().push( (PDGraphicsState)getGraphicsState().clone() );
+                saveGraphicsState();
                 
                 PDFormXObject form = (PDFormXObject)xobject;
                 COSStream invoke = (COSStream)form.getCOSObject();
@@ -179,7 +179,7 @@ public class PrintImageLocations extends
                 processSubStream( pdResources, invoke );
                 
                 // restore the graphics state
-                setGraphicsState( (PDGraphicsState)getGraphicsStack().pop() );
+                restoreGraphicsState();
             }
             
         }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Tue Jun 17 00:20:17 2014
@@ -59,6 +59,7 @@ public final class COSName extends COSBa
     public static final COSName AESV3 = new COSName("AESV3");
     public static final COSName AIS = new COSName("AIS");
     public static final COSName ALT = new COSName("Alt");
+    public static final COSName ALPHA = new COSName("Alpha");
     public static final COSName ALTERNATE = new COSName("Alternate");
     public static final COSName ANNOT = new COSName("Annot");
     public static final COSName ANNOTS = new COSName("Annots");
@@ -84,6 +85,7 @@ public final class COSName extends COSBa
     public static final COSName BASE_FONT = new COSName("BaseFont");
     public static final COSName BASE_STATE = new COSName("BaseState");
     public static final COSName BBOX = new COSName("BBox");
+    public static final COSName BC = new COSName("BC");
     public static final COSName BITS_PER_COMPONENT = new COSName("BitsPerComponent");
     public static final COSName BITS_PER_COORDINATE = new COSName("BitsPerCoordinate");
     public static final COSName BITS_PER_FLAG = new COSName("BitsPerFlag");
@@ -91,6 +93,7 @@ public final class COSName extends COSBa
     public static final COSName BLACK_IS_1 = new COSName("BlackIs1");
     public static final COSName BLACK_POINT = new COSName("BlackPoint");
     public static final COSName BLEED_BOX = new COSName("BleedBox");
+    public static final COSName BM = new COSName("BM");
     public static final COSName BOUNDS = new COSName("Bounds");
     public static final COSName BPC = new COSName("BPC");
     public static final COSName BYTERANGE = new COSName("ByteRange");
@@ -119,10 +122,13 @@ public final class COSName extends COSBa
     public static final COSName CLR_F = new COSName("ClrF");
     public static final COSName CLR_FF = new COSName("ClrFf");
     public static final COSName CMYK = new COSName("CMYK");
+    public static final COSName COLOR_BURN = new COSName("ColorBurn");
+    public static final COSName COLOR_DODGE = new COSName("ColorDodge");
     public static final COSName COLORANTS = new COSName("Colorants");
     public static final COSName COLORS = new COSName("Colors");
     public static final COSName COLORSPACE = new COSName("ColorSpace");
     public static final COSName COLUMNS = new COSName("Columns");
+    public static final COSName COMPATIBLE = new COSName("Compatible");
     public static final COSName COMPONENTS = new COSName("Components");
     public static final COSName CONTACT_INFO = new COSName("ContactInfo");
     public static final COSName CONTENTS = new COSName("Contents");
@@ -136,6 +142,7 @@ public final class COSName extends COSBa
     // D
     public static final COSName D = new COSName("D");
     public static final COSName DA = new COSName("DA");
+    public static final COSName DARKEN = new COSName("Darken");
     public static final COSName DATE = new COSName("Date");
     public static final COSName DCT_DECODE = new COSName("DCTDecode");
     public static final COSName DCT_DECODE_ABBREVIATION = new COSName("DCT");
@@ -152,6 +159,7 @@ public final class COSName extends COSBa
     public static final COSName DEVICEGRAY = new COSName("DeviceGray");
     public static final COSName DEVICEN = new COSName("DeviceN");
     public static final COSName DEVICERGB = new COSName("DeviceRGB");
+    public static final COSName DIFFERENCE = new COSName("Difference");
     public static final COSName DIFFERENCES = new COSName("Differences");
     public static final COSName DIGEST_METHOD = new COSName("DigestMethod");
     public static final COSName DIGEST_RIPEMD160 = new COSName("RIPEMD160");
@@ -188,6 +196,7 @@ public final class COSName extends COSBa
     public static final COSName ENCRYPT_META_DATA = new COSName("EncryptMetadata");
     public static final COSName END_OF_LINE = new COSName("EndOfLine");
     public static final COSName ENTRUST_PPKEF = new COSName("Entrust.PPKEF");
+    public static final COSName EXCLUSION = new COSName("Exclusion");
     public static final COSName EXT_G_STATE = new COSName("ExtGState");
     public static final COSName EXTEND = new COSName("Extend");
     public static final COSName EXTENDS = new COSName("Extends");
@@ -227,9 +236,11 @@ public final class COSName extends COSBa
     // G
     public static final COSName G = new COSName("G");
     public static final COSName GAMMA = new COSName("Gamma");
+    public static final COSName GROUP = new COSName("Group");
     public static final COSName GTS_PDFA1 = new COSName("GTS_PDFA1");
     // H
     public static final COSName H = new COSName("H");
+    public static final COSName HARD_LIGHT = new COSName("HardLight");
     public static final COSName HEIGHT = new COSName("Height");
     public static final COSName HIDE_MENUBAR = new COSName("HideMenubar");
     public static final COSName HIDE_TOOLBAR = new COSName("HideToolbar");
@@ -269,9 +280,11 @@ public final class COSName extends COSBa
     public static final COSName LENGTH = new COSName("Length");
     public static final COSName LENGTH1 = new COSName("Length1");
     public static final COSName LENGTH2 = new COSName("Length2");
+    public static final COSName LIGHTEN = new COSName("Lighten");
     public static final COSName LIMITS = new COSName("Limits");
     public static final COSName LJ = new COSName("LJ");
     public static final COSName LOCATION = new COSName("Location");
+    public static final COSName LUMINOSITY = new COSName("Luminosity");
     public static final COSName LW = new COSName("LW");
     public static final COSName LZW_DECODE = new COSName("LZWDecode");
     public static final COSName LZW_DECODE_ABBREVIATION = new COSName("LZW");
@@ -292,6 +305,7 @@ public final class COSName extends COSBa
     public static final COSName ML = new COSName("ML");
     public static final COSName MM_TYPE1 = new COSName("MMType1");
     public static final COSName MOD_DATE = new COSName("ModDate");
+    public static final COSName MULTIPLY = new COSName("Multiply");
     // N
     public static final COSName N = new COSName("N");
     public static final COSName NAME = new COSName("Name");
@@ -300,6 +314,8 @@ public final class COSName extends COSBa
     public static final COSName NM = new COSName("NM");
     public static final COSName NON_EFONT_NO_WARN = new COSName("NonEFontNoWarn");
     public static final COSName NON_FULL_SCREEN_PAGE_MODE = new COSName("NonFullScreenPageMode");
+    public static final COSName NONE = new COSName("None");
+    public static final COSName NORMAL = new COSName("Normal");
     public static final COSName NUMS = new COSName("Nums");
     // O
     public static final COSName O = new COSName("O");
@@ -325,6 +341,7 @@ public final class COSName extends COSBa
     public static final COSName OUTPUT_CONDITION_IDENTIFIER = new COSName("OutputConditionIdentifier");
     public static final COSName OUTPUT_INTENT = new COSName("OutputIntent");
     public static final COSName OUTPUT_INTENTS = new COSName("OutputIntents");
+    public static final COSName OVERLAY = new COSName("Overlay");
     // P
     public static final COSName P = new COSName("P");
     public static final COSName PAGE = new COSName("Page");
@@ -378,6 +395,7 @@ public final class COSName extends COSBa
     // S
     public static final COSName S = new COSName("S");
     public static final COSName SA = new COSName("SA");
+    public static final COSName SCREEN = new COSName("Screen");
     public static final COSName SE = new COSName("SE");
     public static final COSName SEPARATION = new COSName("Separation");
     public static final COSName SET_F = new COSName("SetF");
@@ -389,6 +407,7 @@ public final class COSName extends COSBa
     public static final COSName SIZE = new COSName("Size");
     public static final COSName SM = new COSName("SM");
     public static final COSName SMASK = new COSName("SMask");
+    public static final COSName SOFT_LIGHT = new COSName("SoftLight");
     public static final COSName STANDARD_ENCODING = new COSName("StandardEncoding");
     public static final COSName STATUS = new COSName("Status");
     public static final COSName STD_CF = new COSName("StdCF");
@@ -415,7 +434,9 @@ public final class COSName extends COSBa
     public static final COSName TITLE = new COSName("Title");
     public static final COSName TK = new COSName("TK");
     public static final COSName TO_UNICODE = new COSName("ToUnicode");
+    public static final COSName TR = new COSName("TR");
     public static final COSName TRAPPED = new COSName("Trapped");
+    public static final COSName TRANSPARENCY = new COSName("Transparency");
     public static final COSName TRIM_BOX = new COSName("TrimBox");
     public static final COSName TRUE_TYPE = new COSName("TrueType");
     public static final COSName TRUSTED_MODE = new COSName("TrustedMode");

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,204 @@
+/*
+ * 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.blend;
+
+import java.awt.AlphaComposite;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.color.ColorSpace;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * AWT composite for blend modes.
+ * 
+ * @author Kühn & Weyh Software, GmbH
+ */
+public final class BlendComposite implements Composite
+{
+    /**
+     * Creates a blend composite
+     *
+     * @param blendMode Desired blend mode
+     * @param constantAlpha Constant alpha
+     */
+    public static Composite getInstance(BlendMode blendMode, float constantAlpha)
+    {
+        if (blendMode == BlendMode.NORMAL)
+        {
+            return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, constantAlpha);
+        }
+        else
+        {
+            return new BlendComposite(blendMode, constantAlpha);
+        }
+    }
+
+    // TODO - non-separable blending modes
+
+    private final BlendMode blendMode;
+    private final float constantAlpha;
+
+    private BlendComposite(BlendMode blendMode, float constantAlpha)
+    {
+        super();
+        this.blendMode = blendMode;
+        this.constantAlpha = constantAlpha;
+    }
+
+    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
+            RenderingHints hints)
+    {
+        return new BlendCompositeContext(srcColorModel, dstColorModel, hints);
+    }
+
+    class BlendCompositeContext implements CompositeContext
+    {
+        private ColorModel srcColorModel;
+        private ColorModel dstColorModel;
+        private RenderingHints hints;
+
+        public BlendCompositeContext(ColorModel srcColorModel, ColorModel dstColorModel,
+                RenderingHints hints)
+        {
+            this.srcColorModel = srcColorModel;
+            this.dstColorModel = dstColorModel;
+            this.hints = hints;
+        }
+
+        public void dispose()
+        {
+            // nothing needed
+        }
+
+        public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
+        {
+            int x0 = src.getMinX();
+            int y0 = src.getMinY();
+            int width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()), dstOut.getWidth());
+            int height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()), dstOut.getHeight());
+            int x1 = x0 + width;
+            int y1 = y0 + height;
+            int dstInXShift = dstIn.getMinX() - x0;
+            int dstInYShift = dstIn.getMinY() - y0;
+            int dstOutXShift = dstOut.getMinX() - x0;
+            int dstOutYShift = dstOut.getMinY() - y0;
+
+            ColorSpace srcColorSpace = srcColorModel.getColorSpace();
+            int numSrcColorComponents = srcColorModel.getNumColorComponents();
+            int numSrcComponents = src.getNumBands();
+            boolean srcHasAlpha = (numSrcComponents > numSrcColorComponents);
+            ColorSpace dstColorSpace = dstColorModel.getColorSpace();
+            int numDstColorComponents = dstColorModel.getNumColorComponents();
+            int numDstComponents = dstIn.getNumBands();
+            boolean dstHasAlpha = (numDstComponents > numDstColorComponents);
+
+            int colorSpaceType = dstColorSpace.getType();
+            boolean subtractive = (colorSpaceType != ColorSpace.TYPE_RGB)
+                    && (colorSpaceType != ColorSpace.TYPE_GRAY);
+
+            boolean blendModeIsSeparable = blendMode instanceof SeparableBlendMode;
+            SeparableBlendMode separableBlendMode = blendModeIsSeparable ?
+                    (SeparableBlendMode) blendMode : null;
+
+            boolean needsColorConversion = !srcColorSpace.equals(dstColorSpace);
+
+            Object srcPixel = null;
+            Object dstPixel = null;
+            float[] srcComponents = new float[numSrcComponents];
+            float[] dstComponents = new float[numDstComponents];
+
+            float[] srcColor = new float[numSrcColorComponents];
+            float[] srcConverted;
+
+            for (int y = y0; y < y1; y++)
+            {
+                for (int x = x0; x < x1; x++)
+                {
+                    srcPixel = src.getDataElements(x, y, srcPixel);
+                    dstPixel = dstIn.getDataElements(dstInXShift + x, dstInYShift + y, dstPixel);
+
+                    srcComponents = srcColorModel.getNormalizedComponents(srcPixel, srcComponents,
+                            0);
+                    dstComponents = dstColorModel.getNormalizedComponents(dstPixel, dstComponents,
+                            0);
+
+                    float srcAlpha = srcHasAlpha ? srcComponents[numSrcColorComponents] : 1.0f;
+                    float dstAlpha = dstHasAlpha ? dstComponents[numDstColorComponents] : 1.0f;
+
+                    srcAlpha = srcAlpha * constantAlpha;
+
+                    float resultAlpha = dstAlpha + srcAlpha - srcAlpha * dstAlpha;
+                    float srcAlphaRatio = (resultAlpha > 0) ? srcAlpha / resultAlpha : 0;
+
+                    // convert color
+                    System.arraycopy(srcComponents, 0, srcColor, 0, numSrcColorComponents);
+                    if (needsColorConversion)
+                    {
+                        // TODO - very very slow - Hash results???
+                        float[] cieXYZ = srcColorSpace.toCIEXYZ(srcColor);
+                        srcConverted = dstColorSpace.fromCIEXYZ(cieXYZ);
+                    }
+                    else
+                    {
+                        srcConverted = srcColor;
+                    }
+
+                    if (separableBlendMode != null)
+                    {
+                        for (int k = 0; k < numDstColorComponents; k++)
+                        {
+                            float srcValue = srcConverted[k];
+                            float dstValue = dstComponents[k];
+
+                            if (subtractive)
+                            {
+                                srcValue = 1 - srcValue;
+                                dstValue = 1 - dstValue;
+                            }
+
+                            float value = separableBlendMode.blendChannel(srcValue, dstValue);
+                            value = srcValue + dstAlpha * (value - srcValue);
+                            value = dstValue + srcAlphaRatio * (value - dstValue);
+
+                            if (subtractive)
+                            {
+                                value = 1 - value;
+                            }
+
+                            dstComponents[k] = value;
+                        }
+                    }
+                    else
+                    {
+                        // TODO - nonseparable modes
+                    }
+
+                    if (dstHasAlpha)
+                    {
+                        dstComponents[numDstColorComponents] = resultAlpha;
+                    }
+
+                    dstPixel = dstColorModel.getDataElements(dstComponents, 0, dstPixel);
+                    dstOut.setDataElements(dstOutXShift + x, dstOutYShift + y, dstPixel);
+                }
+            }
+        }
+    }
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendMode.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,183 @@
+package org.apache.pdfbox.pdmodel.graphics.blend;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSName;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Blend mode.
+ *
+ * @author Kühn & Weyh Software, GmbH
+ */
+public abstract class BlendMode
+{
+    private static final Map<COSName, BlendMode> BLEND_MODES = createBlendModeMap();
+
+    private static Map<COSName, BlendMode> createBlendModeMap()
+    {
+        Map<COSName, BlendMode> map = new HashMap<COSName, BlendMode>();
+        map.put(COSName.NORMAL, BlendMode.NORMAL);
+        map.put(COSName.COMPATIBLE, BlendMode.COMPATIBLE);
+        map.put(COSName.MULTIPLY, BlendMode.MULTIPLY);
+        map.put(COSName.SCREEN, BlendMode.SCREEN);
+        map.put(COSName.OVERLAY, BlendMode.OVERLAY);
+        map.put(COSName.DARKEN, BlendMode.DARKEN);
+        map.put(COSName.LIGHTEN, BlendMode.LIGHTEN);
+        map.put(COSName.COLOR_DODGE, BlendMode.COLOR_DODGE);
+        map.put(COSName.COLOR_BURN, BlendMode.COLOR_BURN);
+        map.put(COSName.HARD_LIGHT, BlendMode.HARD_LIGHT);
+        map.put(COSName.SOFT_LIGHT, BlendMode.SOFT_LIGHT);
+        map.put(COSName.DIFFERENCE, BlendMode.DIFFERENCE);
+        map.put(COSName.EXCLUSION, BlendMode.EXCLUSION);
+        // TODO - non-separable blending modes
+        return map;
+    }
+
+    /**
+     * Determines the blend mode from the BM entry in the COS ExtGState.
+     *
+     * @param cosBlendMode name or array
+     * @return blending mode
+     */
+    public static BlendMode getInstance(COSBase cosBlendMode)
+    {
+        BlendMode result = null;
+        if (cosBlendMode instanceof COSName)
+        {
+            result = BLEND_MODES.get(cosBlendMode);
+        }
+        else if (cosBlendMode instanceof COSArray)
+        {
+            COSArray cosBlendModeArray = (COSArray) cosBlendMode;
+            for (int i = 0; i < cosBlendModeArray.size(); i++)
+            {
+                result = BLEND_MODES.get(cosBlendModeArray.get(i));
+                if (result != null)
+                {
+                    break;
+                }
+            }
+        }
+        if (result != null)
+        {
+            return result;
+        }
+        return BlendMode.COMPATIBLE;
+    }
+
+    public static SeparableBlendMode NORMAL = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return srcValue;
+        }
+    };
+
+    public static SeparableBlendMode COMPATIBLE = NORMAL;
+
+    public static SeparableBlendMode MULTIPLY = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return srcValue * dstValue;
+        }
+    };
+
+    public static SeparableBlendMode SCREEN = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return srcValue + dstValue - srcValue * dstValue;
+        }
+    };
+
+    public static SeparableBlendMode OVERLAY = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return (dstValue <= 0.5) ? 2 * dstValue * srcValue : 2 * (srcValue + dstValue - srcValue
+                    * dstValue) - 1;
+        }
+    };
+
+    public static SeparableBlendMode DARKEN = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return Math.min(srcValue, dstValue);
+        }
+    };
+
+    public static SeparableBlendMode LIGHTEN = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return Math.max(srcValue, dstValue);
+        }
+    };
+
+    public static SeparableBlendMode COLOR_DODGE = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return (srcValue < 1) ? Math.min(1, dstValue / (1 - srcValue)) : 1;
+        }
+    };
+
+    public static SeparableBlendMode COLOR_BURN = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return (srcValue > 0) ? 1 - Math.min(1, (1 - dstValue) / srcValue) : 0;
+        }
+    };
+
+    public static SeparableBlendMode HARD_LIGHT = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return (srcValue <= 0.5) ? 2 * dstValue * srcValue :
+                    2 * (srcValue + dstValue - srcValue * dstValue) - 1;
+        }
+    };
+
+    public static SeparableBlendMode SOFT_LIGHT = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            if (srcValue <= 0.5)
+            {
+                return dstValue - (1 - 2 * srcValue) * dstValue * (1 - dstValue);
+            }
+            else
+            {
+                float D = (dstValue <= 0.25) ? ((16 * dstValue - 12) * dstValue + 4) * dstValue
+                        : (float) Math .sqrt(dstValue);
+                return dstValue + (2 * srcValue - 1) * (D - dstValue);
+            }
+        }
+    };
+
+    public static SeparableBlendMode DIFFERENCE = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return Math.abs(dstValue - srcValue);
+        }
+    };
+
+    public static SeparableBlendMode EXCLUSION = new SeparableBlendMode()
+    {
+        public float blendChannel(float srcValue, float dstValue)
+        {
+            return dstValue + srcValue - 2 * dstValue * srcValue;
+        }
+    };
+
+    BlendMode()
+    {
+    }
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/NonSeparableBlendMode.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,15 @@
+package org.apache.pdfbox.pdmodel.graphics.blend;
+
+/**
+ * Non-separable blend mode (supports blend function).
+ *
+ * @author Kühn & Weyh Software, GmbH
+ */
+public abstract class NonSeparableBlendMode extends BlendMode
+{
+    NonSeparableBlendMode()
+    {
+    }
+
+    public abstract void blend(float[] srcValues, float[] dstValues, float[] result);
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SeparableBlendMode.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,15 @@
+package org.apache.pdfbox.pdmodel.graphics.blend;
+
+/**
+ * Separable blend mode (support blendChannel)
+ *
+ * @author Kühn & Weyh Software, GmbH
+ */
+public abstract class SeparableBlendMode extends BlendMode
+{
+    SeparableBlendMode()
+    {
+    }
+
+    public abstract float blendChannel(float srcValue, float dstValue);
+}

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,175 @@
+/*
+ * 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.blend;
+
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorConvertOp;
+import java.awt.image.ColorModel;
+import java.awt.image.ComponentColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.io.IOException;
+
+/**
+ * AWT Paint that adds a soft mask to the alpha channel of the existing parent paint. If the parent
+ * paint does not have an alpha channel, a new raster is created.
+ * 
+ * @author Kühn & Weyh Software, GmbH
+ */
+public final class SoftMaskPaint implements Paint
+{
+    private final Paint parentPaint;
+    private final Raster softMaskRaster;
+
+    /**
+     * Applies the soft mask to the parent.
+     */
+    public SoftMaskPaint(Paint parentPaint, Raster softMaskRaster)
+    {
+        this.parentPaint = parentPaint;
+        this.softMaskRaster = softMaskRaster;
+    }
+
+    public int getTransparency()
+    {
+        return Transparency.TRANSLUCENT;
+    }
+
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform at, RenderingHints hints)
+    {
+        try
+        {
+            PaintContext parentContext = parentPaint.createContext(null, deviceBounds, userBounds,
+                    at, hints);
+            return new Context(parentContext);
+        }
+        catch (IOException e)
+        {
+            return null; // context cannot be created
+        }
+    }
+
+    private class Context implements PaintContext
+    {
+        private PaintContext parentContext;
+        private final ColorModel colorModel;
+        private final int numColorComponents;
+        private final ColorModel parentColorModel;
+
+        public Context(PaintContext parentContext) throws IOException
+        {
+            this.parentContext = parentContext;
+            parentColorModel = parentContext.getColorModel();
+            if (parentContext.getColorModel().hasAlpha())
+            {
+                colorModel = parentColorModel;
+            }
+            else
+            {
+                colorModel = new ComponentColorModel(parentContext.getColorModel()
+                        .getColorSpace(), true, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+            }
+            numColorComponents = colorModel.getNumColorComponents();
+        }
+
+        public ColorModel getColorModel()
+        {
+            return colorModel;
+        }
+
+        public Raster getRaster(int x, int y, int w, int h)
+        {
+            Raster parentRaster = parentContext.getRaster(x, y, w, h);
+
+            // getRaster can return the raster with origin (0,0) even if we applied for (x,y)
+            int parentMinX = parentRaster.getMinX();
+            int parentMinY = parentRaster.getMinY();
+
+            WritableRaster result;
+            if (parentRaster instanceof WritableRaster)
+            {
+                if (parentColorModel.equals(colorModel))
+                {
+                    result = parentRaster.createCompatibleWritableRaster();
+                    result.setDataElements(-parentMinX, -parentMinY, parentRaster);
+                }
+                else
+                {
+                    BufferedImage parentImage = new BufferedImage(parentColorModel,
+                            (WritableRaster) parentRaster,
+                            parentColorModel.isAlphaPremultiplied(), null);
+                    result = Raster.createWritableRaster(
+                            colorModel.createCompatibleSampleModel(w, h), new Point(0, 0));
+                    BufferedImage resultImage = new BufferedImage(colorModel, result, false, null);
+                    resultImage.getGraphics().drawImage(parentImage, 0, 0, null);
+                }
+            }
+            else
+            {
+                result = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, getColorModel()
+                        .getNumComponents(), new Point(0, 0));
+                ColorConvertOp colorConvertOp = new ColorConvertOp(
+                        parentColorModel.getColorSpace(), colorModel.getColorSpace(), null);
+                colorConvertOp.filter(parentRaster, result);
+            }
+
+            int softMaskMinX = softMaskRaster.getMinX();
+            int softMaskMinY = softMaskRaster.getMinY();
+            int softMaskMaxX = softMaskMinX + softMaskRaster.getWidth();
+            int softMaskMaxY = softMaskMinY + softMaskRaster.getHeight();
+
+            for (int j = 0; j < h; j++)
+            {
+                for (int i = 0; i < w; i++)
+                {
+                    int rx = x + i;
+                    int ry = y + j;
+
+                    int alpha;
+                    if ((rx >= softMaskMinX) && (rx < softMaskMaxX) && (ry >= softMaskMinY)
+                            && (ry < softMaskMaxY))
+                    {
+                        alpha = softMaskRaster.getSample(Math.round(rx), Math.round(ry), 0);
+                    }
+                    else
+                    {
+                        alpha = 0;
+                    }
+                    alpha = alpha * result.getSample(i, j, numColorComponents) / 255;
+                    result.setSample(i, j, numColorComponents, alpha);
+                }
+            }
+
+            return result;
+        }
+
+        public void dispose()
+        {
+            // do nothing
+        }
+    }
+}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java Tue Jun 17 00:20:17 2014
@@ -22,12 +22,10 @@ import java.util.Map;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSFloat;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNumber;
-import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.pdfbox.pdmodel.PDResources;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
@@ -61,6 +59,8 @@ public final class PDFormXObject extends
     // name of XObject in resources, to prevent recursion
     private String name;
 
+    private PDGroup group;
+
     /**
      * Creates a Form XObject for reading.
      * @param stream The XObject stream
@@ -109,6 +109,23 @@ public final class PDFormXObject extends
     }
 
     /**
+     * Returns group descriptor...
+     *
+     * @return
+     */
+    public PDGroup getGroup() {
+        if( group == null ) 
+        {
+            COSDictionary dic = (COSDictionary) getCOSStream().getDictionaryObject(COSName.GROUP);
+            if( dic != null ) 
+            {
+                group = new PDGroup(dic);
+            }
+        }
+        return group;
+    }
+
+    /**
      * This will get the resources at this page and not look up the hierarchy.
      * This attribute is inheritable, and findResources() should probably used.
      * This will return null if no resources are available at this level.

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,101 @@
+/*
+ * 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.form;
+
+import java.io.IOException;
+
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+
+/**
+ * Transparency group.
+ * 
+ * @author Kühn & Weyh Software, GmbH
+ */
+public final class PDGroup implements COSObjectable
+{
+    private COSDictionary dictionary;
+    private COSName subType;
+    private PDColorSpace colorSpace;
+
+    /**
+     * Creates a group object from a given dictionary
+     * @param dic {@link COSDictionary} object
+     */
+    public PDGroup(COSDictionary dic)
+    {
+        dictionary = dic;
+    }
+
+    public COSBase getCOSObject()
+    {
+        return dictionary;
+    }
+
+    public COSDictionary getCOSDictionary()
+    {
+        return dictionary;
+    }
+
+    /**
+     * Returns the groups's subtype, should be "Transparency".
+     */
+    public COSName getSubType()
+    {
+        if (subType == null)
+        {
+            subType = (COSName) getCOSDictionary().getDictionaryObject(COSName.S);
+        }
+        return subType;
+    }
+
+    /**
+     * Returns the blending color space
+     * @return color space
+     * @throws IOException
+     */
+    public PDColorSpace getColorSpace() throws IOException
+    {
+        if (colorSpace == null)
+        {
+            colorSpace = PDColorSpace.create(getCOSDictionary().getDictionaryObject(
+                    COSName.COLORSPACE));
+        }
+        return colorSpace;
+    }
+
+    /**
+     * Returns true if this group is isolated. Isolated groups begin with the fully transparent
+     * image, non-isolated begin with the current backdrop.
+     */
+    public boolean isIsolated()
+    {
+        return getCOSDictionary().getBoolean(COSName.I, false);
+    }
+
+    /**
+     * Returns true if this group is a knockout. A knockout group blends with original backdrop,
+     * a non-knockout group blends with the current backdrop.
+     */
+    public boolean isKnockout()
+    {
+        return getCOSDictionary().getBoolean(COSName.K, false);
+    }
+}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java Tue Jun 17 00:20:17 2014
@@ -16,19 +16,18 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.state;
 
+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.COSFloat;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNumber;
-
 import org.apache.pdfbox.pdmodel.common.COSObjectable;
 import org.apache.pdfbox.pdmodel.graphics.PDFontSetting;
 import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
-
-import java.io.IOException;
-
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
 
 /**
  * This class represents the graphics state dictionary that is stored in the PDF document.
@@ -151,6 +150,14 @@ public class PDExtendedGraphicsState imp
             {
                 gs.getTextState().setKnockoutFlag( getTextKnockoutFlag() );
             }
+            else if( key.equals( COSName.SMASK ) ) 
+            {
+                gs.setSoftMask(getSoftMask());
+            }
+            else if( key.equals( COSName.BM ) ) 
+            {
+                gs.setBlendMode( getBlendMode() );
+            }
         }
     }
 
@@ -283,7 +290,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setLineDashPattern( PDLineDashPattern dashPattern )
     {
-        graphicsState.setItem( COSName.D, dashPattern.getCOSObject() );
+        graphicsState.setItem(COSName.D, dashPattern.getCOSObject());
     }
 
     /**
@@ -303,7 +310,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setRenderingIntent( String ri )
     {
-        graphicsState.setName( "RI", ri );
+        graphicsState.setName("RI", ri);
     }
 
     /**
@@ -313,7 +320,7 @@ public class PDExtendedGraphicsState imp
      */
     public boolean getStrokingOverprintControl()
     {
-        return graphicsState.getBoolean( COSName.OP, false );
+        return graphicsState.getBoolean(COSName.OP, false);
     }
 
     /**
@@ -323,7 +330,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setStrokingOverprintControl( boolean op )
     {
-        graphicsState.setBoolean( COSName.OP, op );
+        graphicsState.setBoolean(COSName.OP, op);
     }
 
     /**
@@ -354,7 +361,7 @@ public class PDExtendedGraphicsState imp
      */
     public Float getOverprintMode()
     {
-        return getFloatItem( COSName.OPM );
+        return getFloatItem(COSName.OPM);
     }
 
     /**
@@ -364,7 +371,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setOverprintMode( Float overprintMode )
     {
-        setFloatItem( COSName.OPM, overprintMode );
+        setFloatItem(COSName.OPM, overprintMode);
     }
 
     /**
@@ -390,7 +397,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setFontSetting( PDFontSetting fs )
     {
-        graphicsState.setItem( COSName.FONT, fs );
+        graphicsState.setItem(COSName.FONT, fs);
     }
 
     /**
@@ -410,7 +417,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setFlatnessTolerance( Float flatness )
     {
-        setFloatItem( COSName.FL, flatness );
+        setFloatItem(COSName.FL, flatness);
     }
 
     /**
@@ -440,7 +447,7 @@ public class PDExtendedGraphicsState imp
      */
     public boolean getAutomaticStrokeAdjustment()
     {
-        return graphicsState.getBoolean( COSName.SA,false );
+        return graphicsState.getBoolean(COSName.SA, false);
     }
 
     /**
@@ -450,7 +457,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setAutomaticStrokeAdjustment( boolean sa )
     {
-        graphicsState.setBoolean( COSName.SA, sa );
+        graphicsState.setBoolean(COSName.SA, sa);
     }
 
     /**
@@ -460,7 +467,7 @@ public class PDExtendedGraphicsState imp
      */
     public Float getStrokingAlpaConstant()
     {
-        return getFloatItem( COSName.CA );
+        return getFloatItem(COSName.CA);
     }
 
     /**
@@ -470,7 +477,7 @@ public class PDExtendedGraphicsState imp
      */
     public void setStrokingAlphaConstant( Float alpha )
     {
-        setFloatItem( COSName.CA, alpha );
+        setFloatItem(COSName.CA, alpha);
     }
 
     /**
@@ -500,7 +507,7 @@ public class PDExtendedGraphicsState imp
      */
     public boolean getAlphaSourceFlag()
     {
-        return graphicsState.getBoolean( COSName.AIS, false );
+        return graphicsState.getBoolean(COSName.AIS, false);
     }
 
     /**
@@ -510,10 +517,25 @@ public class PDExtendedGraphicsState imp
      */
     public void setAlphaSourceFlag( boolean alpha )
     {
-        graphicsState.setBoolean( COSName.AIS, alpha );
+        graphicsState.setBoolean(COSName.AIS, alpha);
     }
 
     /**
+     * Returns the blending mode stored in the COS dictionary
+     *
+     * @return
+     */
+    public BlendMode getBlendMode() {
+        return BlendMode.getInstance(graphicsState.getDictionaryObject(COSName.BM));
+    }
+
+    public PDSoftMask getSoftMask() {
+        return PDSoftMask.create(graphicsState.getDictionaryObject(COSName.SMASK));
+    }
+
+    /**
+
+    /**
      * This will get the text knockout flag.
      *
      * @return The text knockout flag.

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java Tue Jun 17 00:20:17 2014
@@ -16,13 +16,18 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.state;
 
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Composite;
+import java.awt.Rectangle;
+import java.awt.Shape;
 import java.awt.geom.GeneralPath;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
 import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendComposite;
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
 import org.apache.pdfbox.pdmodel.graphics.color.PDDeviceGray;
@@ -78,6 +83,9 @@ public class PDGraphicsState implements 
 
     private GeneralPath currentClippingPath;
 
+    private BlendMode blendMode = BlendMode.COMPATIBLE;
+    private PDSoftMask softMask;
+
     /**
      * Default constructor.
      */
@@ -281,6 +289,49 @@ public class PDGraphicsState implements 
     }
 
     /**
+     * returns the current softmask
+     *
+     * @return softMask
+     */
+    public PDSoftMask getSoftMask() 
+    {
+        return softMask;
+    }
+
+
+    /**
+     * Sets the current soft mask
+     *
+     * @param softMask
+     */
+    public void setSoftMask(PDSoftMask softMask)
+    {
+        this.softMask = softMask;
+    }
+
+    /**
+     * Returns the current blend mode
+     *
+     * @return
+     */
+    public BlendMode getBlendMode()
+    {
+        return blendMode;
+    }
+
+    /**
+     * Sets the blend mode in the current graphics state
+     *
+     * @param blendMode
+     */
+    public void setBlendMode(BlendMode blendMode)
+    {
+        this.blendMode = blendMode;
+    }
+
+    /**
+
+    /**
      * get the value of the overprint property.
      *
      * @return The value of the overprint parameter.
@@ -567,13 +618,13 @@ public class PDGraphicsState implements 
         return currentClippingPath;
     }
 
-    public Composite getStrokeJavaComposite() {
-
-        return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alphaConstants);
+    public Composite getStrokeJavaComposite() 
+    {
+        return BlendComposite.getInstance(blendMode, (float) alphaConstants);
     }
 
-    public Composite getNonStrokeJavaComposite() {
-
-        return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) nonStrokingAlphaConstants);
+    public Composite getNonStrokeJavaComposite() 
+    {
+        return BlendComposite.getInstance(blendMode, (float) nonStrokingAlphaConstants);
     }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java?rev=1603033&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDSoftMask.java Tue Jun 17 00:20:17 2014
@@ -0,0 +1,155 @@
+/*
+ * 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.state;
+
+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.COSBase;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.common.COSObjectable;
+import org.apache.pdfbox.pdmodel.common.function.PDFunction;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
+
+/**
+ * Soft mask.
+ *
+ * @author Kühn & Weyh Software, GmbH
+ */
+public final class PDSoftMask implements COSObjectable
+{
+    /**
+     * Creates a new soft mask.
+     *
+     * @param dictionary SMask
+     */
+    public static PDSoftMask create(COSBase dictionary)
+    {
+        if (dictionary instanceof COSName)
+        {
+            if (COSName.NONE.equals(dictionary))
+            {
+                return null;
+            }
+            else
+            {
+                LOG.warn("Invalid SMask " + dictionary);
+                return null;
+            }
+        }
+        else if (dictionary instanceof COSDictionary)
+        {
+            return new PDSoftMask((COSDictionary) dictionary);
+        }
+        else
+        {
+            LOG.warn("Invalid SMask " + dictionary);
+            return null;
+        }
+    }
+
+    private static final Log LOG = LogFactory.getLog(PDSoftMask.class);
+
+    private COSDictionary dictionary;
+    private COSName subType = null;
+    private PDFormXObject group = null;
+    private COSArray backdropColor = null;
+    private PDFunction transferFunction = null;
+
+    /**
+     * Creates a new soft mask.
+     */
+    public PDSoftMask(COSDictionary dictionary)
+    {
+        super();
+        this.dictionary = dictionary;
+    }
+
+    public COSBase getCOSObject()
+    {
+        return dictionary;
+    }
+
+    public COSDictionary getCOSDictionary()
+    {
+        return dictionary;
+    }
+
+    /**
+     * Returns the subtype of the soft mask (Alpha, Luminosity) - S entry
+     */
+    public COSName getSubType()
+    {
+        if (subType == null)
+        {
+            subType = (COSName) getCOSDictionary().getDictionaryObject(COSName.S);
+        }
+        return subType;
+    }
+
+    /**
+     * Returns the G entry of the soft mask object
+     * 
+     * @return form containing the transparency group
+     * @throws IOException
+     */
+    public PDFormXObject getGroup() throws IOException
+    {
+        if (group == null)
+        {
+            COSBase cosGroup = getCOSDictionary().getDictionaryObject(COSName.G);
+            if (cosGroup != null)
+            {
+                group = (PDFormXObject) PDXObject
+                        .createXObject(cosGroup, COSName.G.getName(), null);
+            }
+        }
+        return group;
+    }
+
+    /**
+     * Returns the backdrop color.
+     */
+    public COSArray getBackdropColor()
+    {
+        if (backdropColor == null)
+        {
+            backdropColor = (COSArray) getCOSDictionary().getDictionaryObject(COSName.BC);
+        }
+        return backdropColor;
+    }
+
+    /**
+     * Returns the transfer function.
+     */
+    public PDFunction getTransferFunction() throws IOException
+    {
+        if (transferFunction == null)
+        {
+            COSBase cosTF = getCOSDictionary().getDictionaryObject(COSName.TR);
+            if (cosTF != null)
+            {
+                transferFunction = PDFunction.create(cosTF);
+            }
+        }
+        return transferFunction;
+    }
+}

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java Tue Jun 17 00:20:17 2014
@@ -25,6 +25,8 @@ import java.awt.Graphics2D;
 import java.awt.Image;
 import java.awt.Paint;
 import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.TexturePaint;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
@@ -32,6 +34,10 @@ import java.awt.geom.Area;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.NoninvertibleTransformException;
 import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -64,20 +70,24 @@ import org.apache.pdfbox.pdmodel.font.PD
 import org.apache.pdfbox.pdmodel.font.PDType1CFont;
 import org.apache.pdfbox.pdmodel.font.PDType1Font;
 import org.apache.pdfbox.pdmodel.font.PDType3Font;
-import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
 import org.apache.pdfbox.pdmodel.graphics.PDLineDashPattern;
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendMode;
+import org.apache.pdfbox.pdmodel.graphics.state.PDSoftMask;
+import org.apache.pdfbox.pdmodel.graphics.blend.SoftMaskPaint;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
 import org.apache.pdfbox.pdmodel.graphics.pattern.PDTilingPattern;
 import org.apache.pdfbox.pdmodel.graphics.shading.PDShading;
+import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
-import org.apache.pdfbox.pdmodel.graphics.state.PDTextState;
+import org.apache.pdfbox.text.TextPosition;
 import org.apache.pdfbox.util.Matrix;
 import org.apache.pdfbox.util.PDFStreamEngine;
 import org.apache.pdfbox.util.ResourceLoader;
-import org.apache.pdfbox.text.TextPosition;
 
 /**
  * This will paint a page in a PDF document to a graphics context.
@@ -397,7 +407,7 @@ public class PageDrawer extends PDFStrea
             if (stream != null)
             {
                 // save the current graphics state and matrices
-                getGraphicsStack().push((PDGraphicsState) getGraphicsState().clone());
+                saveGraphicsState();
                 Matrix textMatrix = getTextMatrix();
                 Matrix textLineMatrix = getTextLineMatrix();
                 
@@ -407,7 +417,7 @@ public class PageDrawer extends PDFStrea
                 processSubStream(font.getType3Resources(), stream);
 
                 // restore the saved graphics state and matrices
-                setGraphicsState(getGraphicsStack().pop());
+                restoreGraphicsState();
                 setTextLineMatrix(textLineMatrix);
                 setTextMatrix(textMatrix);
                  
@@ -623,11 +633,49 @@ public class PageDrawer extends PDFStrea
         return linePath;
     }
 
+    /**
+     * Generates awt raster for a soft mask
+     * 
+     * @param context
+     * @return
+     * @throws IOException
+     */
+    private Raster createSoftMaskRaster(PDSoftMask softMask) throws IOException
+    {
+        PageDrawer.Group result = createPageDrawerGroup(softMask.getGroup());
+        COSName sMaskSubType = softMask.getSubType();
+        if (COSName.ALPHA.equals(sMaskSubType))
+        {
+            return result.getAlphaRaster();
+        }
+        else if (COSName.LUMINOSITY.equals(sMaskSubType))
+        {
+            return result.getLuminosityRaster();
+        }
+        else
+        {
+            throw new IOException("Invalid soft mask subtype.");
+        }
+    }
+
+    private Paint applySoftMaskToPaint(Paint parentPaint, PDSoftMask softMask) throws IOException  
+    {
+        if (softMask != null) 
+        {
+            return new SoftMaskPaint(parentPaint, createSoftMaskRaster(softMask));
+        }
+        else 
+        {
+            return parentPaint;
+        }
+    }
+
     // returns the stroking AWT Paint
     private Paint getStrokingPaint() throws IOException
     {
-        return getGraphicsState().getStrokingColorSpace()
-                .toPaint(renderer, getGraphicsState().getStrokingColor(), pageHeight);
+        PDGraphicsState graphicsState = getGraphicsState();
+        return applySoftMaskToPaint(graphicsState.getStrokingColorSpace()
+                .toPaint(renderer, graphicsState.getStrokingColor(), pageHeight), graphicsState.getSoftMask());
     }
 
     // returns the non-stroking AWT Paint
@@ -816,16 +864,34 @@ public class PageDrawer extends PDFStrea
      * @param at The transformation to use when drawing.
      * 
      */
-    public void drawImage(Image awtImage, AffineTransform at)
+    public void drawImage(Image awtImage, AffineTransform at) throws IOException
     {
         graphics.setComposite(getGraphicsState().getNonStrokeJavaComposite());
         graphics.setClip(getGraphicsState().getCurrentClippingPath());
-        int width = awtImage.getWidth(null);
-        int height = awtImage.getHeight(null);
-        AffineTransform imageTransform = new AffineTransform(at);
-        imageTransform.scale(1.0 / width, -1.0 / height);
-        imageTransform.translate(0, -height);
-        graphics.drawImage(awtImage, imageTransform, null);
+        PDSoftMask softMask = getGraphicsState().getSoftMask();
+        if( softMask != null ) 
+        {
+            AffineTransform imageTransform = new AffineTransform(at);
+            imageTransform.scale(1, -1);
+            imageTransform.translate(0, -1);
+            Paint awtPaint = new TexturePaint((BufferedImage)awtImage, 
+                    new Rectangle2D.Double(imageTransform.getTranslateX(), imageTransform.getTranslateY(),
+                            imageTransform.getScaleX(), imageTransform.getScaleY())); 
+            awtPaint = applySoftMaskToPaint(awtPaint, softMask);
+            graphics.setPaint(awtPaint);
+            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+            Rectangle2D unitRect = new Rectangle2D.Float(0, 0, 1, 1);
+            graphics.fill(at.createTransformedShape(unitRect));
+        }
+        else 
+        {
+            int width = awtImage.getWidth(null);
+            int height = awtImage.getHeight(null);
+            AffineTransform imageTransform = new AffineTransform(at);
+            imageTransform.scale(1.0 / width, -1.0 / height);
+            imageTransform.translate(0, -height);
+            graphics.drawImage(awtImage, imageTransform, null);
+        }
     }
 
     /**
@@ -846,4 +912,191 @@ public class PageDrawer extends PDFStrea
         graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
         graphics.fill(getGraphicsState().getCurrentClippingPath());
     }
+
+    /**
+     * Creates a buffered image for a transparency group result.
+     *
+     * @param clippingPath clipping path (in current graphics2D coordinates)
+     * @param resources Global resources
+     * @param content Content of the transparency group to create
+     * @return {@link Group} object
+     */
+    private Group createGroup(GeneralPath clippingPath, PDResources resources, COSStream content) throws IOException {
+        return new Group(clippingPath, resources, content);
+    }
+
+
+    /**
+     * Draws the transparency group into a {@link BufferedImage} object and returns it together with the transformation matrix
+     *
+     * @param context {@link PageDrawer} object
+     * @return PageDrawer.Group
+     * @throws IOException
+     */
+    public PageDrawer.Group createPageDrawerGroup(PDFormXObject form) throws IOException {
+        // save the graphics state
+        saveGraphicsState();
+
+        try {
+            PDResources pdResources = form.getResources();
+            if (pdResources == null) {
+                pdResources = getResources();
+            }
+
+            // if there is an optional form matrix, we have to
+            // map the form space to the user space
+            Matrix matrix = form.getMatrix();
+            if(matrix != null)
+            {
+                Matrix xobjectCTM = matrix.multiply(getGraphicsState().getCurrentTransformationMatrix());
+                getGraphicsState().setCurrentTransformationMatrix(xobjectCTM);
+            }
+
+            PDRectangle bBox = form.getBBox();
+
+            float x1 = bBox.getLowerLeftX();
+            float y1 = bBox.getLowerLeftY();
+            float x2 = bBox.getUpperRightX();
+            float y2 = bBox.getUpperRightY();
+
+            Point2D p0 = transformedPoint(x1, y1);
+            Point2D p1 = transformedPoint(x2, y1);
+            Point2D p2 = transformedPoint(x2, y2);
+            Point2D p3 = transformedPoint(x1, y2);
+
+            GeneralPath path = new GeneralPath();
+            path.moveTo((float) p0.getX(), (float) p0.getY());
+            path.lineTo((float) p1.getX(), (float) p1.getY());
+            path.lineTo((float) p2.getX(), (float) p2.getY());
+            path.lineTo((float) p3.getX(), (float) p3.getY());
+            path.closePath();
+
+            return createGroup(path, pdResources, form.getCOSStream());
+        }
+        finally {
+            // restore the graphics state
+            restoreGraphicsState();
+        }
+
+    }
+
+    /**
+     * Create for rendering transparency groups...
+     *
+     **/
+    public class Group {
+        /**
+         * {@link BufferedImage} object to draw into...
+         */
+        private final BufferedImage mImage;
+        /**
+         * Matrix for drawing the result
+         */
+        private final Matrix mResultMatrix;
+
+
+        private final int minX;
+        private final int minY;
+        private final int width;
+        private final int height;
+
+        /**
+         * Creates a group object. The group can now be created only if the underlying {@link Graphics2D} implementation
+         * is SunGraphics2D (i.e. rendering to bitmap). For all other implementations, this throws
+         * an {@link UnsupportedOperationException}.
+         *
+         * @param image
+         * @param g2d
+         */
+        private Group(GeneralPath clippingPath, PDResources resources, COSStream content) throws IOException {
+            Graphics2D g2dOriginal = graphics;
+
+            // Check underlying g2d
+            double unitSize = 1.0;
+
+            Area resultClippingArea = new Area(getGraphicsState().getCurrentClippingPath());
+            if(clippingPath != null) {
+                Area newArea = new Area(clippingPath);            
+                resultClippingArea.intersect(newArea);
+            }
+
+            AffineTransform at = g2dOriginal.getTransform();
+            at.scale(unitSize, unitSize);
+            Shape clippingPathInPixels = at.createTransformedShape(resultClippingArea);
+            Rectangle2D bounds2D = clippingPathInPixels.getBounds2D();
+
+            minX = (int) Math.floor(bounds2D.getMinX());
+            minY = (int) Math.floor(bounds2D.getMinY());
+            int maxX = (int) Math.floor(bounds2D.getMaxX()) + 1;
+            int maxY = (int) Math.floor(bounds2D.getMaxY()) + 1;
+
+            width = maxX - minX;
+            height = maxY - minY;
+            mImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);     // FIXME - color space
+            Graphics2D groupG2D = mImage.createGraphics();
+            groupG2D.translate(-minX, -minY);
+            groupG2D.transform(at);
+            groupG2D.setClip(resultClippingArea);
+
+            AffineTransform atInv = null;
+            Matrix tmpResultMatrix = null;
+            try {
+                atInv = groupG2D.getTransform().createInverse();
+                atInv.scale(width, -height);
+                atInv.translate(0, -1);
+                tmpResultMatrix = new Matrix();
+                tmpResultMatrix.setFromAffineTransform(atInv);
+            }
+            catch (NoninvertibleTransformException e) {
+                LOG.warn("Non-invertible transform when rendering a transparency group.", e);
+            }
+            mResultMatrix = tmpResultMatrix;
+
+            PDGraphicsState gs = getGraphicsState();
+            gs.setBlendMode(BlendMode.NORMAL);
+            gs.setAlphaConstants(1.0);
+            gs.setNonStrokeAlphaConstants(1.0);
+            gs.setSoftMask(null);
+            graphics = groupG2D;
+            try {
+                processSubStream(resources, content);
+            }
+            finally 
+            {
+                graphics = g2dOriginal;
+            }
+        }
+
+        public BufferedImage getImage() {
+            return mImage;
+        }
+
+        /**
+         * @return the resultMatrix
+         */
+        public Matrix getResultMatrix() {
+            return mResultMatrix;
+        }
+
+        public void drawResult() throws IOException {
+            if (mResultMatrix != null) {
+                saveGraphicsState();
+                drawImage(mImage, mResultMatrix.createAffineTransform());
+                restoreGraphicsState();
+            }
+        }
+
+        public Raster getAlphaRaster() {
+            return mImage.getAlphaRaster().createTranslatedChild(minX, minY);
+        }
+
+        public Raster getLuminosityRaster() {
+            BufferedImage tmpImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
+            Graphics g = tmpImage.getGraphics();
+            g.drawImage(mImage, 0, 0, null);
+
+            WritableRaster result = tmpImage.getRaster();
+            return result.createTranslatedChild(minX, minY);
+        }
+    }
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java Tue Jun 17 00:20:17 2014
@@ -610,19 +610,27 @@ public class PDFStreamEngine
     }
 
     /**
-     * @return Returns the graphicsStack.
+     * Pushes the current graphics state to the stack.
      */
-    public Stack<PDGraphicsState> getGraphicsStack()
+    public void saveGraphicsState()
     {
-        return graphicsStack;
+        graphicsStack.push((PDGraphicsState) getGraphicsState().clone());
     }
 
     /**
-     * @param value The graphicsStack to set.
+     * Pops the current graphics state from the stack.
      */
-    public void setGraphicsStack(Stack<PDGraphicsState> value)
+    public void restoreGraphicsState()
     {
-        graphicsStack = value;
+        graphicsState = graphicsStack.pop();
+    }
+
+    /**
+     * @return Returns the size of the graphicsStack.
+     */
+    public int getGraphicsStackSize()
+    {
+        return graphicsStack.size();
     }
 
     /**
@@ -747,5 +755,4 @@ public class PDFStreamEngine
             unsupportedOperators.clear();
         }
     }
-
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GRestore.java Tue Jun 17 00:20:17 2014
@@ -42,9 +42,9 @@ public class GRestore extends OperatorPr
      */
     public void process(PDFOperator operator, List<COSBase> arguments)
     {
-    	if (context.getGraphicsStack().size() > 0)
+    	if (context.getGraphicsStackSize() > 0)
     	{
-    		context.setGraphicsState( (PDGraphicsState)context.getGraphicsStack().pop() );
+    		context.restoreGraphicsState();
     	}
     	else
     	{

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/GSave.java Tue Jun 17 00:20:17 2014
@@ -36,7 +36,7 @@ public class GSave extends OperatorProce
      */
     public void process(PDFOperator operator, List<COSBase> arguments)
     {
-        context.getGraphicsStack().push( (PDGraphicsState)context.getGraphicsState().clone() );
+        context.saveGraphicsState();
     }
 
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java Tue Jun 17 00:20:17 2014
@@ -94,27 +94,36 @@ public final class Invoke extends Operat
         }
         else if (xobject instanceof PDFormXObject)
         {
-            // save the graphics state
-            context.getGraphicsStack().push((PDGraphicsState) context.getGraphicsState().clone());
+            PDFormXObject form = (PDFormXObject) xobject;         
+            if ((form.getGroup() != null) && (COSName.TRANSPARENCY.equals(form.getGroup().getSubType()))) {
+                PageDrawer.Group group = drawer.createPageDrawerGroup(form);
 
-            PDFormXObject form = (PDFormXObject) xobject;
-            COSStream formContentStream = form.getCOSStream();
+                // Draw the result of the group to the page...
+                group.drawResult();
+            }
+            else 
+            {
+                // save the graphics state
+                context.saveGraphicsState();
 
-            // find some optional resources, instead of using the current resources
-            PDResources pdResources = form.getResources();
+                COSStream formContentStream = form.getCOSStream();
 
-            // if there is an optional form matrix, we have to map the form space to the user space
-            Matrix matrix = form.getMatrix();
-            if (matrix != null)
-            {
-                Matrix xobjectCTM = matrix.multiply(
-                    context.getGraphicsState().getCurrentTransformationMatrix());
+                // find some optional resources, instead of using the current resources
+                PDResources pdResources = form.getResources();
+
+                // if there is an optional form matrix, we have to map the form space to the user space
+                Matrix matrix = form.getMatrix();
+                if (matrix != null)
+                {
+                    Matrix xobjectCTM = matrix.multiply(
+                                    context.getGraphicsState().getCurrentTransformationMatrix());
                     context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM);
-            }
-            getContext().processSubStream(pdResources, formContentStream);
+                }
+                getContext().processSubStream(pdResources, formContentStream);
 
-            // restore the graphics state
-            context.setGraphicsState(context.getGraphicsStack().pop());
+                // restore the graphics state
+                context.restoreGraphicsState();
+            }
         }
     }
 }

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamEngine.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamEngine.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamEngine.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamEngine.java Tue Jun 17 00:20:17 2014
@@ -264,7 +264,7 @@ public abstract class ContentStreamEngin
     {
         if ("q".equals(operator.getOperation()))
         {
-            int numberOfGraphicStates = this.getGraphicsStack().size();
+            int numberOfGraphicStates = this.getGraphicsStackSize();
             if (numberOfGraphicStates > MAX_GRAPHIC_STATES)
             {
                 registerError("Too many graphic states", ERROR_GRAPHIC_TOO_MANY_GRAPHIC_STATES);

Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamWrapper.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamWrapper.java?rev=1603033&r1=1603032&r2=1603033&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamWrapper.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/content/ContentStreamWrapper.java Tue Jun 17 00:20:17 2014
@@ -141,7 +141,7 @@ public class ContentStreamWrapper extend
         this.setGraphicsState(new PDGraphicsState());
         this.setTextMatrix(null);
         this.setTextLineMatrix(null);
-        this.getGraphicsStack().clear();
+        //this.getGraphicsStack().clear();
         // this.streamResourcesStack.clear();
     }