Index: pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java	(working copy)
@@ -59,6 +59,7 @@
     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 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 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 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 @@
     // 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 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 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 @@
     // 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 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 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 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 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 @@
     // 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 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 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");
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java	(working copy)
@@ -0,0 +1,362 @@
+/*
+ * 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.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;
+
+/**
+ * Implementation of the Blend composite according to the PDF specification.
+ * 
+ * @author kühn &amp; weyh Software, GmbH
+ */
+public class BlendComposite implements Composite
+{
+
+    /**
+     * Interface for identifying blend modes
+     * 
+     */
+    public interface BlendMode
+    {
+        // Empty
+    }
+
+    /**
+     * Interface for separable blend modes (support blendChannel)
+     * 
+     */
+    public interface SeparableBlendMode extends BlendMode
+    {
+        public float blendChannel(float srcValue, float dstValue);
+    }
+
+    /**
+     * Interface for non-separable blend modes (supports blend function)
+     * 
+     */
+    public interface NonseparableBlendMode extends BlendMode
+    {
+        public void blend(float[] srcValues, float[] dstValues, float[] result);
+    }
+
+    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;
+        }
+    };
+
+    // TODO - non-separable blending modes
+
+    private final BlendMode mBlendMode;
+    private final float mConstantAlpha;
+
+    /**
+     * @param blendMode
+     * @param alpha
+     */
+    public BlendComposite(BlendMode blendMode, float constantAlpha)
+    {
+        super();
+        mBlendMode = blendMode;
+        mConstantAlpha = constantAlpha;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.Composite#createContext(java.awt.image.ColorModel, java.awt.image.ColorModel,
+     * java.awt.RenderingHints)
+     */
+    public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
+            RenderingHints hints)
+    {
+        return new BlendCompositeContext(srcColorModel, dstColorModel, hints);
+    }
+
+    /**
+     * BlendCompositeContext implements CompositeContext interface for the BlendComposite class...
+     * 
+     */
+    class BlendCompositeContext implements CompositeContext
+    {
+        /**
+         * Source color model
+         */
+        private ColorModel mSrcColorModel;
+        /**
+         * Destination color model
+         */
+        private ColorModel mDstColorModel;
+        @SuppressWarnings("unused")
+        private RenderingHints mHints;
+
+        /**
+         * @param srcColorModel
+         * @param dstColorModel
+         */
+        public BlendCompositeContext(ColorModel srcColorModel, ColorModel dstColorModel,
+                RenderingHints hints)
+        {
+            mSrcColorModel = srcColorModel;
+            mDstColorModel = dstColorModel;
+            mHints = hints;
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.CompositeContext#dispose()
+         */
+        public void dispose()
+        {
+            // Nothing needed
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.CompositeContext#compose(java.awt.image.Raster, java.awt.image.Raster,
+         * java.awt.image.WritableRaster)
+         */
+        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 = mSrcColorModel.getColorSpace();
+            int numSrcColorComponents = mSrcColorModel.getNumColorComponents();
+            int numSrcComponents = src.getNumBands();
+            boolean srcHasAlpha = (numSrcComponents > numSrcColorComponents);
+            ColorSpace dstColorSpace = mDstColorModel.getColorSpace();
+            int numDstColorComponents = mDstColorModel.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 = mBlendMode instanceof SeparableBlendMode;
+            SeparableBlendMode separableBlendMode = blendModeIsSeparable ? (SeparableBlendMode) mBlendMode : 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 = null;
+
+            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 = mSrcColorModel.getNormalizedComponents(srcPixel, srcComponents,
+                            0);
+                    dstComponents = mDstColorModel.getNormalizedComponents(dstPixel, dstComponents,
+                            0);
+
+                    float srcAlpha = srcHasAlpha ? srcComponents[numSrcColorComponents] : 1.0f;
+                    float dstAlpha = dstHasAlpha ? dstComponents[numDstColorComponents] : 1.0f;
+
+                    srcAlpha = srcAlpha * mConstantAlpha;
+
+                    float resultAlpha = dstAlpha + srcAlpha - srcAlpha * dstAlpha;
+                    float srcAlphaRatio = (resultAlpha > 0) ? srcAlpha / resultAlpha : 0;
+
+                    // Convert color
+                    for (int k = 0; k < numSrcColorComponents; k++)
+                    {
+                        srcColor[k] = srcComponents[k];
+                    }
+                    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 = mDstColorModel.getDataElements(dstComponents, 0, dstPixel);
+                    dstOut.setDataElements(dstOutXShift + x, dstOutYShift + y, dstPixel);
+
+                }
+            }
+        }
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/PDFCompositeFactory.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/PDFCompositeFactory.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/PDFCompositeFactory.java	(working copy)
@@ -0,0 +1,104 @@
+/*
+ * 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.util.HashMap;
+import java.util.Map;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.cos.COSName;
+
+public class PDFCompositeFactory
+{
+    private static Map<COSName, BlendComposite.BlendMode> blendModeMap = createBlendModeMap();
+
+    private static Map<COSName, BlendComposite.BlendMode> createBlendModeMap()
+    {
+        Map<COSName, BlendComposite.BlendMode> result = new HashMap<COSName, BlendComposite.BlendMode>();
+        result.put(COSName.NORMAL, BlendComposite.NORMAL);
+        result.put(COSName.COMPATIBLE, BlendComposite.COMPATIBLE);
+        result.put(COSName.MULTIPLY, BlendComposite.MULTIPLY);
+        result.put(COSName.SCREEN, BlendComposite.SCREEN);
+        result.put(COSName.OVERLAY, BlendComposite.OVERLAY);
+        result.put(COSName.DARKEN, BlendComposite.DARKEN);
+        result.put(COSName.LIGHTEN, BlendComposite.LIGHTEN);
+        result.put(COSName.COLOR_DODGE, BlendComposite.COLOR_DODGE);
+        result.put(COSName.COLOR_BURN, BlendComposite.COLOR_BURN);
+        result.put(COSName.HARD_LIGHT, BlendComposite.HARD_LIGHT);
+        result.put(COSName.SOFT_LIGHT, BlendComposite.SOFT_LIGHT);
+        result.put(COSName.DIFFERENCE, BlendComposite.DIFFERENCE);
+        result.put(COSName.EXCLUSION, BlendComposite.EXCLUSION);
+
+        // TODO - non-separable blending modes
+
+        return result;
+    }
+
+    /**
+     * Creates a blend composite
+     * 
+     * @param cosBlendMode Desired blend mode
+     * @param constantAlpha Constant alpha
+     * @return
+     */
+    public static Composite createComposite(BlendComposite.BlendMode blendMode, float constantAlpha)
+    {
+        if (blendMode == BlendComposite.NORMAL)
+        {
+            return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, constantAlpha);
+        }
+        else
+        {
+            return new BlendComposite(blendMode, constantAlpha);
+        }
+    }
+
+    /**
+     * Determines the blend mode from the BM entry in the COS ExtGState...
+     * 
+     * @param cosBlendMode {@link COSName} or {@link COSArray} object
+     * @return blending mode
+     */
+    public static BlendComposite.BlendMode createBlendMode(COSBase cosBlendMode)
+    {
+        BlendComposite.BlendMode result = null;
+        if (cosBlendMode instanceof COSName)
+        {
+            result = blendModeMap.get(cosBlendMode);
+        }
+        else if (cosBlendMode instanceof COSArray)
+        {
+            COSArray cosBlendModeArray = (COSArray) cosBlendMode;
+            for (int i = 0; i < cosBlendModeArray.size(); i++)
+            {
+                result = blendModeMap.get(cosBlendModeArray.get(i));
+                if (result != null)
+                {
+                    break;
+                }
+            }
+        }
+        if (result != null)
+        {
+            return result;
+        }
+        return BlendComposite.COMPATIBLE;
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/SoftMaskPaint.java	(working copy)
@@ -0,0 +1,185 @@
+/*
+ * 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;
+
+/**
+ * Descendant of java.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 &amp; weyh Software, GmbH
+ */
+public class SoftMaskPaint implements Paint
+{
+
+    private final Paint mParentPaint;
+    private final Raster mSoftMaskRaster;
+
+    /**
+     * Applies the soft mask to the parent.
+     */
+    public SoftMaskPaint(Paint parentPaint, Raster softMaskRaster)
+    {
+        mParentPaint = parentPaint;
+        mSoftMaskRaster = softMaskRaster;
+    }
+
+    public int getTransparency()
+    {
+        return Transparency.TRANSLUCENT;
+    }
+
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform at, RenderingHints hints)
+    {
+        try
+        {
+            PaintContext parentContext = mParentPaint.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 mParentContext;
+        private final ColorModel mColorModel;
+        private final int mNumColorComponents;
+        private final ColorModel mParentColorModel;
+
+        /**
+         * @param at
+         * @throws IOException
+         */
+        public Context(PaintContext parentContext) throws IOException
+        {
+            mParentContext = parentContext;
+            mParentColorModel = mParentContext.getColorModel();
+            if (parentContext.getColorModel().hasAlpha())
+            {
+                mColorModel = mParentColorModel;
+            }
+            else
+            {
+                mColorModel = new ComponentColorModel(mParentContext.getColorModel()
+                        .getColorSpace(), true, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+            }
+            mNumColorComponents = mColorModel.getNumColorComponents();
+        }
+
+        public ColorModel getColorModel()
+        {
+            return mColorModel;
+        }
+
+        public Raster getRaster(int x, int y, int w, int h)
+        {
+
+            Raster parentRaster = mParentContext.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 (mParentColorModel.equals(mColorModel))
+                {
+                    result = parentRaster.createCompatibleWritableRaster();
+                    result.setDataElements(-parentMinX, -parentMinY, parentRaster);
+                }
+                else
+                {
+                    BufferedImage parentImage = new BufferedImage(mParentColorModel,
+                            (WritableRaster) parentRaster,
+                            mParentColorModel.isAlphaPremultiplied(), null);
+                    result = Raster.createWritableRaster(
+                            mColorModel.createCompatibleSampleModel(w, h), new Point(0, 0));
+                    BufferedImage resultImage = new BufferedImage(mColorModel,
+                            (WritableRaster) 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(
+                        mParentColorModel.getColorSpace(), mColorModel.getColorSpace(), null);
+                colorConvertOp.filter(parentRaster, result);
+            }
+
+            int softMaskMinX = mSoftMaskRaster.getMinX();
+            int softMaskMinY = mSoftMaskRaster.getMinY();
+            int softMaskMaxX = softMaskMinX + mSoftMaskRaster.getWidth();
+            int softMaskMaxY = softMaskMinY + mSoftMaskRaster.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 = mSoftMaskRaster.getSample(Math.round(rx), Math.round(ry), 0);
+                    }
+                    else
+                    {
+                        alpha = 0;
+                    }
+                    alpha = alpha * result.getSample(i, j, mNumColorComponents) / 255;
+                    result.setSample(i, j, mNumColorComponents, alpha);
+                }
+            }
+
+            return result;
+        }
+
+        public void dispose()
+        {
+            // Do nothing
+        }
+
+    }
+
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/ColorSpaceDeviceGray.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/ColorSpaceDeviceGray.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/ColorSpaceDeviceGray.java	(working copy)
@@ -0,0 +1,165 @@
+/*
+ * 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.color;
+
+import java.awt.color.ColorSpace;
+
+/**
+ * Singleton implementation of pdf's DEVICEGRAY color space. The gray level {x} in this space corresponds to the sRGB
+ * color {x,x,x}.
+ * 
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public class ColorSpaceDeviceGray extends ColorSpace
+{
+    /**
+     * Instance
+     */
+    private static final ColorSpaceDeviceGray INSTANCE = new ColorSpaceDeviceGray();
+
+    /**
+     * CIE-XYZ color space
+     */
+    private static final ColorSpace mCIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
+
+    private static final int LUT_STEPS = 256;
+    private static final int LUT_MAX = LUT_STEPS - 1;
+
+    /**
+     * Conversion lookup table to sRGB
+     */
+    private static final float[][] TO_RGB_LUT = makeToRGBLUT();
+
+    private static float[][] makeToRGBLUT()
+    {
+        float[][] result = new float[LUT_STEPS][];
+        float[] colorvalue = { 0 };
+        for (int i = 0; i < LUT_STEPS; i++)
+        {
+            colorvalue[0] = (float) i / (LUT_STEPS - 1);
+            float[] rgb = internalToRGB(colorvalue);
+            result[i] = rgb;
+        }
+        return result;
+    }
+
+    /**
+     * Conversion lookup table to CIE-XYZ
+     */
+    private static final float[][] TO_CIEXYZ_LUT = makeToCIEXYZLUT();
+
+    private static float[][] makeToCIEXYZLUT()
+    {
+        float[][] result = new float[LUT_STEPS][];
+        float[] colorvalue = { 0 };
+        for (int i = 0; i < LUT_STEPS; i++)
+        {
+            colorvalue[0] = (float) i / (LUT_STEPS - 1);
+            float[] ciexyz = internalToCIEXYZ(colorvalue);
+            result[i] = ciexyz;
+        }
+        return result;
+    }
+
+    private static float[] internalToRGB(float[] colorvalue)
+    {
+        float v = Math.min(1f, colorvalue[0]);
+        return new float[] { v, v, v };
+    }
+
+    private static float[] internalToCIEXYZ(float[] colorvalue)
+    {
+        return mCIEXYZ.fromRGB(internalToRGB(colorvalue));
+    }
+
+    /**
+     * @return the instance
+     */
+    public static final ColorSpaceDeviceGray getInstance()
+    {
+        return INSTANCE;
+    }
+
+    /**
+     * Private constructor to prevent instance construction.
+     */
+    private ColorSpaceDeviceGray()
+    {
+        super(ColorSpace.TYPE_GRAY, 1);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.color.ColorSpace#toRGB(float[])
+     */
+    @Override
+    public float[] toRGB(float[] colorvalue)
+    {
+        float f = colorvalue[0];
+        int index = f >= 1.0 ? LUT_MAX : Math.round(f * LUT_MAX);
+        return TO_RGB_LUT[index];
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.color.ColorSpace#fromRGB(float[])
+     */
+    @Override
+    public float[] fromRGB(float[] rgbvalue)
+    {
+        return new float[] { 0.299f * rgbvalue[0] + 0.587f * rgbvalue[1] + 0.114f * rgbvalue[2] };
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.color.ColorSpace#toCIEXYZ(float[])
+     */
+    @Override
+    public float[] toCIEXYZ(float[] colorvalue)
+    {
+        float f = colorvalue[0];
+        int index = f >= 1.0 ? LUT_MAX : Math.round(f * LUT_MAX);
+        return TO_CIEXYZ_LUT[index];
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.color.ColorSpace#fromCIEXYZ(float[])
+     */
+    @Override
+    public float[] fromCIEXYZ(float[] colorvalue)
+    {
+        float rl = 3.2406f * colorvalue[0] - 1.5372f * colorvalue[1] - 0.4986f * colorvalue[2];
+        float gl = -0.9689f * colorvalue[0] + 1.8758f * colorvalue[1] + 0.0415f * colorvalue[2];
+        float bl = 0.0557f * colorvalue[0] - 0.2040f * colorvalue[1] + 1.0570f * colorvalue[2];
+        float rs = internalGammaOnRGB(rl);
+        float gs = internalGammaOnRGB(gl);
+        float bs = internalGammaOnRGB(bl);
+        return new float[] { 0.299f * rs + 0.587f * gs + 0.114f * bs };
+    }
+
+    private static float internalGammaOnRGB(float value)
+    {
+        return (value <= 0.0031308) ? (12.92f * value) : (1.055f * (float) Math.pow(value, 1 / 2.4) - 0.055f);
+    }
+
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDFormXObject.java	(working copy)
@@ -17,22 +17,25 @@
 package org.apache.pdfbox.pdmodel.graphics.form;
 
 import java.awt.geom.AffineTransform;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
 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;
 import org.apache.pdfbox.pdmodel.common.PDStream;
 import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.Matrix;
 
 /*
@@ -61,6 +64,8 @@
     // 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 +114,23 @@
     }
 
     /**
+     * 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.
@@ -244,4 +266,55 @@
     {
         getCOSStream().setInt(COSName.STRUCT_PARENTS, structParent);
     }
+
+    /**
+     * 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(PageDrawer context) throws IOException {
+        // save the graphics state
+        context.pushGraphicsState();
+
+        try {
+            PDResources pdResources = getResources();
+            if (pdResources == null) {
+                pdResources = context.getResources();
+            }
+
+            // if there is an optional form matrix, we have to
+            // map the form space to the user space
+            Matrix matrix = getMatrix();
+            Matrix xobjectCTM = matrix.multiply(context.getGraphicsState().getCurrentTransformationMatrix());
+            context.getGraphicsState().setCurrentTransformationMatrix(xobjectCTM);
+
+            PDRectangle bBox = getBBox();
+
+            float x1 = bBox.getLowerLeftX();
+            float y1 = bBox.getLowerLeftY();
+            float x2 = bBox.getUpperRightX();
+            float y2 = bBox.getUpperRightY();
+
+            Point2D p0 = context.transformedPoint(x1, y1);
+            Point2D p1 = context.transformedPoint(x2, y1);
+            Point2D p2 = context.transformedPoint(x2, y2);
+            Point2D p3 = context.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 context.createGroup(path, pdResources, getCOSStream());
+        }
+        finally {
+            // restore the graphics state
+            context.popGraphicsState();
+        }
+
+    }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/form/PDGroup.java	(working copy)
@@ -0,0 +1,119 @@
+/*
+ * 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;
+
+/**
+ * Group definition in XObjectForm
+ * 
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public class PDGroup implements COSObjectable
+{
+    /**
+     * {@link COSDictionary} object
+     */
+    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;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.kwsoft.pdfbox.pdmodel.common.COSObjectable#getCOSObject()
+     */
+    public COSBase getCOSObject()
+    {
+        return dictionary;
+    }
+
+    public COSDictionary getCOSDictionary()
+    {
+        return dictionary;
+    }
+
+    /**
+     * Subtype of the group (should be: "Transparency")
+     * 
+     * @return
+     */
+    public COSName getSubType()
+    {
+        if (subType == null)
+        {
+            subType = (COSName) getCOSDictionary().getDictionaryObject(COSName.S);
+        }
+        return subType;
+    }
+
+    /**
+     * Returns the blending color space
+     * 
+     * @return {@link PDColorSpace} object
+     * @throws IOException
+     */
+    public PDColorSpace getColorSpace() throws IOException
+    {
+        if (colorSpace == null)
+        {
+            colorSpace = PDColorSpace.create(getCOSDictionary().getDictionaryObject(
+                    COSName.COLORSPACE));
+        }
+        return colorSpace;
+    }
+
+    /**
+     * Isolated group begins with the fully transparent image, non-isolated begins with the current backdrop.
+     * 
+     * @return
+     */
+    public boolean isIsolated()
+    {
+        return getCOSDictionary().getBoolean(COSName.I, false);
+    }
+
+    /**
+     * A knockout group blends with original backdrop, a non-knockout group blends with the current backdrop.
+     * 
+     * @return
+     */
+    public boolean isKnockout()
+    {
+        return getCOSDictionary().getBoolean(COSName.K, false);
+    }
+
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/AbstractImagePaint.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/AbstractImagePaint.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/AbstractImagePaint.java	(working copy)
@@ -0,0 +1,165 @@
+/*
+ * 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.paint;
+
+import java.awt.Paint;
+import java.awt.PaintContext;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+
+/**
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public abstract class AbstractImagePaint implements Paint
+{
+
+    private final BufferedImage texture;
+    private final AffineTransform textureAt;
+
+    /**
+     *
+     */
+    public AbstractImagePaint(BufferedImage texture, AffineTransform textureAt)
+    {
+        this.texture = texture;
+        this.textureAt = (AffineTransform) textureAt.clone();
+        this.textureAt.scale(1.0f / this.texture.getWidth(), 1.0f / this.texture.getHeight());
+    }
+
+    public int getTransparency()
+    {
+        return texture.getTransparency();
+    }
+
+    /**
+     * @return Returns the texture.
+     */
+    protected BufferedImage getTexture()
+    {
+        return texture;
+    }
+
+    /**
+     * @return Returns the textureAt.
+     */
+    public AffineTransform getTextureAt()
+    {
+        return textureAt;
+    }
+
+    protected abstract class AbstractContext implements PaintContext
+    {
+        /**
+         * Color model used for image paint
+         */
+        private final ColorModel mColorModel;
+        /**
+         * Affine transform
+         */
+        private final AffineTransform mAt;
+        /**
+         * InverseAffineTransform
+         */
+        private final AffineTransform mAtInv;
+        /**
+         * Rendering hints
+         */
+        private final RenderingHints mHints;
+        /**
+         * Rendering hints interpolation value
+         */
+        private final Object mInterpolation;
+        /**
+         * Texture converted to the color model
+         */
+        private final BufferedImage mConvertedTexture;
+
+        /**
+         * @param cm Color model
+         * @param at Affine transform
+         */
+        public AbstractContext(ColorModel cm, AffineTransform contextAt, RenderingHints hints)
+        {
+            mHints = hints;
+            mInterpolation = mHints.get(RenderingHints.KEY_INTERPOLATION);
+
+            // TODO - Color conversion is very slow, think about pre-converting the images...
+            mColorModel = texture.getColorModel();
+            mConvertedTexture = texture;
+
+            mAt = (AffineTransform) contextAt.clone();
+            mAt.concatenate(textureAt);
+            AffineTransform tmpAtInv = null;
+            try
+            {
+                tmpAtInv = mAt.createInverse();
+            }
+            catch (NoninvertibleTransformException e)
+            {
+                tmpAtInv = new AffineTransform(); // Identity
+            }
+            mAtInv = tmpAtInv;
+        }
+
+        public AffineTransform getAtInv()
+        {
+            return mAtInv;
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.PaintContext#getColorModel()
+         */
+        public ColorModel getColorModel()
+        {
+            return mColorModel;
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.PaintContext#getRaster(int, int, int, int)
+         */
+        public abstract Raster getRaster(int x, int y, int w, int h);
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.PaintContext#dispose()
+         */
+        public void dispose()
+        {
+            // Nothing needed
+        }
+
+        public Object getInterpolation()
+        {
+            return mInterpolation;
+        }
+
+        public BufferedImage getConvertedTexture()
+        {
+            return mConvertedTexture;
+        }
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaint.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaint.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaint.java	(working copy)
@@ -0,0 +1,154 @@
+/*
+ * 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.paint;
+
+import java.awt.PaintContext;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/**
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public class ImagePaint extends AbstractImagePaint
+{
+    /**
+     * @param texture
+     * @param textureAt
+     */
+    public ImagePaint(BufferedImage texture, AffineTransform textureAt)
+    {
+        super(texture, textureAt);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.Paint#createContext(java.awt.image.ColorModel, java.awt.Rectangle, java.awt.geom.Rectangle2D,
+     * java.awt.geom.AffineTransform, java.awt.RenderingHints)
+     */
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform at, RenderingHints hints)
+    {
+        return new Context(cm, at, hints);
+    }
+
+    private class Context extends AbstractImagePaint.AbstractContext
+    {
+        /**
+         * @param cm Color model
+         * @param at Affine transform
+         */
+        public Context(ColorModel cm, AffineTransform contextAt, RenderingHints hints)
+        {
+            super(cm, contextAt, hints);
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.PaintContext#getRaster(int, int, int, int)
+         */
+        public Raster getRaster(int x, int y, int w, int h)
+        {
+            ColorModel colorModel = getColorModel();
+            WritableRaster result = colorModel.createCompatibleWritableRaster(w, h);
+            Point2D.Float pt = new Point2D.Float(0, 0);
+
+            int textureWidth = getConvertedTexture().getWidth();
+            int textureHeight = getConvertedTexture().getHeight();
+            Raster textureRaster = getConvertedTexture().getRaster();
+
+            if ((getInterpolation() == null)
+                    || (getInterpolation() == RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
+            {
+                int[] components = new int[textureRaster.getNumBands()];
+
+                for (int j = 0; j < h; j++)
+                {
+                    for (int i = 0; i < w; i++)
+                    {
+                        pt.setLocation(i + x, j + y);
+                        getAtInv().transform(pt, pt);
+
+                        int rx = (int) pt.x;
+                        rx = (rx < 0) ? 0 : (rx >= textureWidth) ? textureWidth - 1 : rx;
+                        int ry = (int) pt.y;
+                        ry = (ry < 0) ? 0 : (ry >= textureHeight) ? textureHeight - 1 : ry;
+
+                        textureRaster.getPixel(rx, ry, components);
+                        result.setPixel(i, j, components);
+                    }
+                }
+            }
+            else
+            {
+                int numBands = textureRaster.getNumBands();
+
+                int[] c00 = new int[numBands];
+                int[] c01 = new int[numBands];
+                int[] c10 = new int[numBands];
+                int[] c11 = new int[numBands];
+
+                for (int j = 0; j < h; j++)
+                {
+                    for (int i = 0; i < w; i++)
+                    {
+                        pt.setLocation(i + x, j + y);
+                        getAtInv().transform(pt, pt);
+
+                        float rx = pt.x - 0.5f;
+                        rx = (rx < 0) ? 0 : (rx > textureWidth - 1) ? textureWidth - 1 : rx;
+                        float ry = pt.y - 0.5f;
+                        ry = (ry < 0) ? 0 : (ry > textureHeight - 1) ? textureHeight - 1 : ry;
+
+                        int ix = (int) rx;
+                        int ixNext = (ix >= textureWidth - 1) ? textureWidth - 1 : ix + 1;
+                        int iy = (int) ry;
+                        int iyNext = (iy >= textureHeight - 1) ? textureHeight - 1 : iy + 1;
+
+                        rx = rx - ix;
+                        ry = ry - iy;
+
+                        textureRaster.getPixel(ix, iy, c00);
+                        textureRaster.getPixel(ixNext, iy, c10);
+                        textureRaster.getPixel(ix, iyNext, c01);
+                        textureRaster.getPixel(ixNext, iyNext, c11);
+
+                        for (int k = 0; k < numBands; k++)
+                        {
+                            c00[k] = Math.round(c00[k] + rx * (c10[k] - c00[k]));
+                            c01[k] = Math.round(c01[k] + rx * (c11[k] - c01[k]));
+                            c00[k] = Math.round(c00[k] + ry * (c01[k] - c00[k]));
+                        }
+
+                        result.setPixel(i, j, c00);
+                    }
+                }
+            }
+
+            return result;
+        }
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaintTiling.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaintTiling.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/paint/ImagePaintTiling.java	(working copy)
@@ -0,0 +1,207 @@
+/*
+ * 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.paint;
+
+import java.awt.PaintContext;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.util.Arrays;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public class ImagePaintTiling extends AbstractImagePaint
+{
+    /**
+     * Log instance.
+     */
+    private static final Log LOG = LogFactory.getLog(ImagePaintTiling.class);
+
+    private final Point2D mRepeatX;
+    private final Point2D mRepeatY;
+    /**
+     * Transforms texture space into the repeat space.
+     */
+    private final AffineTransform textureToRepeatAt;
+    private final Rectangle2D textureRepeatBounds;
+
+    /**
+     * Constructor
+     * 
+     * @param texture BufferedImage object
+     * @param textureAt Maps the texture space (0,1)x(0,1) into the user space
+     * @param repeatXVector x-repeat vector in a user space
+     * @param repeatYVector y-repeat vector in a user space
+     */
+    public ImagePaintTiling(BufferedImage texture, AffineTransform textureAt,
+            Point2D repeatXVector, Point2D repeatYVector)
+    {
+        super(texture, textureAt);
+
+        AffineTransform textureAtInv = null;
+        try
+        {
+            textureAtInv = getTextureAt().createInverse();
+        }
+        catch (NoninvertibleTransformException e)
+        {
+            textureAtInv = new AffineTransform(); // Identity
+        }
+
+        // Transform repeat vectors to texture space
+        mRepeatX = new Point2D.Float();
+        textureAtInv.deltaTransform(repeatXVector, mRepeatX);
+        mRepeatY = new Point2D.Float();
+        textureAtInv.deltaTransform(repeatYVector, mRepeatY);
+
+        AffineTransform repeatAt = new AffineTransform(new float[] { (float) mRepeatX.getX(),
+                (float) mRepeatX.getY(), (float) mRepeatY.getX(), (float) mRepeatY.getY() });
+        AffineTransform tmpRepeatInverseAt = null;
+        try
+        {
+            tmpRepeatInverseAt = repeatAt.createInverse();
+        }
+        catch (NoninvertibleTransformException e)
+        {
+            LOG.warn("Non-invertible transform when rendering a tiling pattern.", e);
+            tmpRepeatInverseAt = new AffineTransform();
+        }
+        textureToRepeatAt = tmpRepeatInverseAt;
+
+        Rectangle2D unitRect = new Rectangle2D.Float(0.0f, 0.0f, texture.getWidth(),
+                texture.getHeight());
+        Shape textureShapeInRepeatSpace = textureToRepeatAt.createTransformedShape(unitRect);
+        textureRepeatBounds = textureShapeInRepeatSpace.getBounds2D();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.awt.Paint#createContext(java.awt.image.ColorModel, java.awt.Rectangle, java.awt.geom.Rectangle2D,
+     * java.awt.geom.AffineTransform, java.awt.RenderingHints)
+     */
+    public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
+            Rectangle2D userBounds, AffineTransform at, RenderingHints hints)
+    {
+        return new Context(cm, at, hints);
+    }
+
+    private class Context extends AbstractImagePaint.AbstractContext
+    {
+        /**
+         * @param cm Color model
+         * @param at Affine transform
+         */
+        public Context(ColorModel cm, AffineTransform contextAt, RenderingHints hints)
+        {
+            super(cm, contextAt, hints);
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see java.awt.PaintContext#getRaster(int, int, int, int)
+         */
+        public Raster getRaster(int x, int y, int w, int h)
+        {
+            ColorModel colorModel = getColorModel();
+            boolean hasAlpha = colorModel.hasAlpha();
+            WritableRaster result = colorModel.createCompatibleWritableRaster(w, h);
+            Point2D.Float pt = new Point2D.Float(0, 0);
+            Point2D.Float ptRepeat = new Point2D.Float(0, 0);
+
+            int textureWidth = getConvertedTexture().getWidth();
+            int textureHeight = getConvertedTexture().getHeight();
+            Raster textureRaster = getConvertedTexture().getRaster();
+
+            int numBands = textureRaster.getNumBands();
+
+            int[] components = new int[numBands];
+            int[] tmpComponents = new int[numBands];
+
+            for (int j = 0; j < h; j++)
+            {
+                for (int i = 0; i < w; i++)
+                {
+                    pt.setLocation(i + x, j + y);
+                    getAtInv().transform(pt, pt);
+                    textureToRepeatAt.transform(pt, ptRepeat);
+
+                    int minRepeatX = (int) Math.ceil(textureRepeatBounds.getMinX() - ptRepeat.x);
+                    int minRepeatY = (int) Math.ceil(textureRepeatBounds.getMinY() - ptRepeat.y);
+                    int maxRepeatX = (int) Math.floor(textureRepeatBounds.getMaxX() - ptRepeat.x);
+                    int maxRepeatY = (int) Math.floor(textureRepeatBounds.getMaxY() - ptRepeat.y);
+
+                    Arrays.fill(components, 0); // Clear...
+                    for (int repY = minRepeatY; repY <= maxRepeatY; repY++)
+                    {
+                        for (int repX = minRepeatX; repX <= maxRepeatX; repX++)
+                        {
+                            int rx = (int) (pt.x + repX * mRepeatX.getX() + repY * mRepeatY.getX());
+                            int ry = (int) (pt.y + repX * mRepeatX.getY() + repY * mRepeatY.getY());
+
+                            if ((rx >= 0) && (ry >= 0) && (rx < textureWidth)
+                                    && (ry < textureHeight))
+                            {
+                                textureRaster.getPixel(rx, ry, tmpComponents);
+
+                                if (hasAlpha)
+                                {
+                                    int dstAlpha = components[numBands - 1];
+                                    int srcAlpha = tmpComponents[numBands - 1];
+                                    int resultAlpha = dstAlpha + srcAlpha - (dstAlpha * srcAlpha)
+                                            / 255;
+                                    if (srcAlpha > 0)
+                                    {
+                                        for (int k = 0; k < numBands - 1; k++)
+                                        {
+                                            components[k] = ((resultAlpha - srcAlpha)
+                                                    * components[k] + srcAlpha * tmpComponents[k])
+                                                    / resultAlpha;
+                                        }
+                                    }
+                                    components[numBands - 1] = resultAlpha;
+                                }
+                                else
+                                {
+                                    components = tmpComponents;
+                                }
+                            }
+                        }
+                    }
+
+                    result.setPixel(i, j, components);
+                }
+            }
+
+            return result;
+        }
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDSoftMask.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDSoftMask.java	(revision 0)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/PDSoftMask.java	(working copy)
@@ -0,0 +1,200 @@
+/*
+ * 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;
+
+import java.awt.image.Raster;
+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.form.PDFormXObject;
+import org.apache.pdfbox.rendering.PageDrawer;
+
+/**
+ * @author kühn &amp; weyh Software, GmbH
+ * 
+ */
+public class PDSoftMask implements COSObjectable
+{
+    /**
+     * Log instance.
+     */
+    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;
+
+    /**
+     *
+     */
+    public PDSoftMask(COSDictionary dic)
+    {
+        super();
+        dictionary = dic;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see de.kwsoft.pdfbox.pdmodel.common.COSObjectable#getCOSObject()
+     */
+    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 {@link PDXObjectForm} 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 BC entry in the dictionary
+     * 
+     * @return
+     */
+    public COSArray getBackdropColor()
+    {
+        if (backdropColor == null)
+        {
+            backdropColor = (COSArray) getCOSDictionary().getDictionaryObject(COSName.BC);
+        }
+        return backdropColor;
+    }
+
+    /**
+     * Returns the TF entry in the dictionary
+     * 
+     * @return
+     * @throws IOException
+     */
+    public PDFunction getTransferFunction() throws IOException
+    {
+        if (transferFunction == null)
+        {
+            COSBase cosTF = getCOSDictionary().getDictionaryObject(COSName.TR);
+            if (cosTF != null)
+            {
+                transferFunction = PDFunction.create(cosTF);
+            }
+        }
+        return transferFunction;
+    }
+
+    /**
+     * @param dictionaryObject
+     * @return
+     */
+    public static PDSoftMask create(COSBase dic)
+    {
+        if (dic instanceof COSName)
+        {
+            if (COSName.NONE.equals(dic))
+            {
+                return null;
+            }
+            else
+            {
+                LOG.warn("Invalid SMask " + dic);
+                return null;
+            }
+        }
+        else if (dic instanceof COSDictionary)
+        {
+            return new PDSoftMask((COSDictionary) dic);
+        }
+        else
+        {
+            LOG.warn("Invalid SMask " + dic);
+            return null;
+        }
+    }
+
+    /**
+     * Generates the awt raster...
+     * 
+     * @param context
+     * @return
+     * @throws IOException
+     */
+    public Raster getAwtRaster(PageDrawer context) throws IOException
+    {
+        if (context != null)
+        {
+            PageDrawer.Group result = getGroup().createPageDrawerGroup(context);
+            COSName sMaskSubType = 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.");
+            }
+        }
+        else
+        {
+            return null;
+        }
+    }
+}
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDExtendedGraphicsState.java	(working copy)
@@ -16,20 +16,25 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.state;
 
+import java.awt.image.Raster;
+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 org.apache.pdfbox.pdmodel.graphics.PDSoftMask;
+import org.apache.pdfbox.pdmodel.graphics.blend.BlendComposite;
+import org.apache.pdfbox.pdmodel.graphics.blend.PDFCompositeFactory;
+import org.apache.pdfbox.rendering.PageDrawer;
+import org.apache.pdfbox.util.PDFStreamEngine;
 
-import java.io.IOException;
 
-
 /**
  * This class represents the graphics state dictionary that is stored in the PDF document.
  * The PDGraphicsStateValue holds the current runtime values as a stream is being executed.
@@ -85,7 +90,7 @@
      *
      * @throws IOException If there is an error copying font information.
      */
-    public void copyIntoGraphicsState( PDGraphicsState gs ) throws IOException
+    public void copyIntoGraphicsState( PDFStreamEngine context, PDGraphicsState gs ) throws IOException
     {
         for( COSName key : graphicsState.keySet() )
         {
@@ -151,6 +156,17 @@
             {
                 gs.getTextState().setKnockoutFlag( getTextKnockoutFlag() );
             }
+            else if( key.equals( COSName.SMASK ) ) 
+            {
+                if( context instanceof PageDrawer ) 
+                {
+                    gs.setSoftMaskRaster(getSoftMaskRaster((PageDrawer) context));
+                }
+            }
+            else if( key.equals( COSName.BM ) ) 
+            {
+                gs.setBlendMode( getBlendMode() );
+            }
         }
     }
 
@@ -513,7 +529,26 @@
         graphicsState.setBoolean( COSName.AIS, alpha );
     }
 
+
     /**
+     * Returns the blending mode stored in the COS dictionary
+     *
+     * @return
+     */
+    public BlendComposite.BlendMode getBlendMode() {
+        return PDFCompositeFactory.createBlendMode(graphicsState.getDictionaryObject(COSName.BM));
+    }
+
+    public PDSoftMask getSoftMask() {
+        return PDSoftMask.create(graphicsState.getDictionaryObject(COSName.SMASK));
+    }
+
+    public Raster getSoftMaskRaster(PageDrawer context) throws IOException {
+        PDSoftMask softMask = getSoftMask();
+        return (softMask != null) ? softMask.getAwtRaster(context) : null;
+    }
+
+    /**
      * This will get the text knockout flag.
      *
      * @return The text knockout flag.
Index: pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/state/PDGraphicsState.java	(working copy)
@@ -16,13 +16,21 @@
  */
 package org.apache.pdfbox.pdmodel.graphics.state;
 
-import java.awt.*;
+import java.awt.BasicStroke;
+import java.awt.Composite;
+import java.awt.Paint;
+import java.awt.Rectangle;
+import java.awt.Shape;
 import java.awt.geom.GeneralPath;
+import java.awt.image.Raster;
+
 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.PDFCompositeFactory;
+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.color.PDDeviceGray;
@@ -78,6 +86,9 @@
 
     private GeneralPath currentClippingPath;
 
+    private BlendComposite.BlendMode blendMode = BlendComposite.COMPATIBLE;
+    private Raster softMaskRaster;
+
     /**
      * Default constructor.
      */
@@ -280,7 +291,49 @@
         alphaSource = value;
     }
 
+
     /**
+     * returns the current softmask
+     *
+     * @return softMask
+     */
+    public Raster getSoftMaskRaster() 
+    {
+        return softMaskRaster;
+    }
+
+
+    /**
+     * Sets the current soft mask
+     *
+     * @param softMask
+     */
+    public void setSoftMaskRaster(Raster softMaskRaster) 
+    {
+        this.softMaskRaster = softMaskRaster;
+    }
+
+    /**
+     * Returns the current blend mode
+     *
+     * @return
+     */
+    public BlendComposite.BlendMode getBlendMode() 
+    {
+        return blendMode;
+    }
+
+    /**
+     * Sets the blend mode in the current graphics state
+     *
+     * @param blendMode
+     */
+    public void setBlendMode(BlendComposite.BlendMode blendMode) 
+    {
+        this.blendMode = blendMode;
+    }
+
+    /**
      * get the value of the overprint property.
      *
      * @return The value of the overprint parameter.
@@ -567,13 +620,25 @@
         return currentClippingPath;
     }
 
-    public Composite getStrokeJavaComposite() {
+    public Paint applySoftMaskToPaint(Paint parentPaint) 
+    {
+        if (softMaskRaster != null) 
+        {
+            return new SoftMaskPaint(parentPaint, softMaskRaster);
+        }
+        else 
+        {
+            return parentPaint;
+        }
+    }
 
-        return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alphaConstants);
+    public Composite getStrokeJavaComposite() 
+    {
+        return PDFCompositeFactory.createComposite(blendMode, (float) alphaConstants);
     }
 
-    public Composite getNonStrokeJavaComposite() {
-
-        return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) nonStrokingAlphaConstants);
+    public Composite getNonStrokeJavaComposite() 
+    {
+        return PDFCompositeFactory.createComposite(blendMode, (float) nonStrokingAlphaConstants);
     }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java	(working copy)
@@ -25,6 +25,9 @@
 import java.awt.Image;
 import java.awt.Paint;
 import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Transparency;
+import java.awt.color.ColorSpace;
 import java.awt.font.FontRenderContext;
 import java.awt.font.GlyphVector;
 import java.awt.geom.AffineTransform;
@@ -32,6 +35,13 @@
 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.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;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -64,21 +74,25 @@
 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.BlendComposite;
+import org.apache.pdfbox.pdmodel.graphics.color.ColorSpaceDeviceGray;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColor;
 import org.apache.pdfbox.pdmodel.graphics.color.PDColorSpace;
+import org.apache.pdfbox.pdmodel.graphics.paint.ImagePaint;
 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.
  * 
@@ -621,8 +635,9 @@
     // returns the stroking AWT Paint
     private Paint getStrokingPaint() throws IOException
     {
-        return getGraphicsState().getStrokingColorSpace()
-                .toPaint(renderer, getGraphicsState().getStrokingColor(), pageHeight);
+        PDGraphicsState graphicsState = getGraphicsState();
+        return graphicsState.applySoftMaskToPaint(graphicsState.getStrokingColorSpace()
+                .toPaint(renderer, graphicsState.getStrokingColor(), pageHeight));
     }
 
     // returns the non-stroking AWT Paint
@@ -815,12 +830,29 @@
     {
         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);
+        Raster softMaskRaster = getGraphicsState().getSoftMaskRaster();
+        if( softMaskRaster != null ) 
+        {
+            // ImagePaint is very slow, we use it only if soft mask is not null...
+            AffineTransform imageTransform = new AffineTransform(at);
+            imageTransform.scale(1, -1);
+            imageTransform.translate(0, -1);
+            Paint awtPaint = new ImagePaint((BufferedImage)awtImage, imageTransform);
+            awtPaint = getGraphicsState().applySoftMaskToPaint(awtPaint);
+            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);
+        }
     }
 
     /**
@@ -841,4 +873,139 @@
         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
+     */
+    public Group createGroup(GeneralPath clippingPath, PDResources resources, COSStream content) throws IOException {
+        return new Group(clippingPath, resources, content);
+    }
+
+    /**
+     * 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(BlendComposite.NORMAL);
+            gs.setAlphaConstants(1.0);
+            gs.setNonStrokeAlphaConstants(1.0);
+            gs.setSoftMaskRaster(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) {
+                pushGraphicsState();
+                drawImage(mImage, mResultMatrix.createAffineTransform());
+                popGraphicsState();
+            }
+        }
+
+        public Raster getAlphaRaster() {
+            return mImage.getAlphaRaster().createTranslatedChild(minX, minY);
+        }
+
+        public Raster getLuminosityRaster() {
+            ColorSpace cs = ColorSpaceDeviceGray.getInstance();
+            ColorModel cm = new ComponentColorModel(cs, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
+            WritableRaster result = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1, null);
+            BufferedImage tmpImage = new BufferedImage(cm, result, false, null);
+            Graphics g = tmpImage.getGraphics();
+            g.drawImage(mImage, 0, 0, null);
+
+            return result.createTranslatedChild(minX, minY);
+        }
+    }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/util/operator/pagedrawer/Invoke.java	(working copy)
@@ -28,17 +28,17 @@
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSStream;
 import org.apache.pdfbox.filter.MissingImageReaderException;
-import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.pdmodel.PDResources;
-import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.pdmodel.graphics.PDXObject;
 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.image.PDImageXObject;
-import org.apache.pdfbox.pdmodel.graphics.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.state.PDGraphicsState;
+import org.apache.pdfbox.rendering.PageDrawer;
 import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.operator.OperatorProcessor;
 import org.apache.pdfbox.util.operator.PDFOperator;
-import org.apache.pdfbox.util.operator.OperatorProcessor;
 
 /**
  * Do Draws an XObject.
@@ -94,27 +94,36 @@
         }
         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 = form.createPageDrawerGroup(drawer);
 
-            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.getGraphicsStack().push((PDGraphicsState) context.getGraphicsState().clone());
 
-            // 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);
+
+                // restore the graphics state
+                context.setGraphicsState(context.getGraphicsStack().pop());
             }
-            getContext().processSubStream(pdResources, formContentStream);
-
-            // restore the graphics state
-            context.setGraphicsState(context.getGraphicsStack().pop());
         }
     }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetGraphicsStateParameters.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetGraphicsStateParameters.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/util/operator/SetGraphicsStateParameters.java	(working copy)
@@ -16,14 +16,13 @@
  */
 package org.apache.pdfbox.util.operator;
 
+import java.io.IOException;
 import java.util.List;
 
 import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
 
-import java.io.IOException;
-
 /**
  * <p>Structal modification of the PDFEngine class :
  * the long sequence of conditions in processOperator is remplaced by
@@ -46,6 +45,6 @@
         //set parameters from graphics state parameter dictionary
         COSName graphicsName = (COSName)arguments.get( 0 );
         PDExtendedGraphicsState gs = (PDExtendedGraphicsState)context.getGraphicsStates().get( graphicsName.getName() );
-        gs.copyIntoGraphicsState( context.getGraphicsState() );
+        gs.copyIntoGraphicsState( context, context.getGraphicsState() );
     }
 }
Index: pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java
===================================================================
--- pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java	(revision 1598501)
+++ pdfbox/src/main/java/org/apache/pdfbox/util/PDFStreamEngine.java	(working copy)
@@ -747,4 +747,21 @@
         }
     }
 
+    /**
+     * The current graphics state is pushed into the graphicsStack, the current graphicsState will be a copy...
+     */
+    public void pushGraphicsState() 
+    {
+        getGraphicsStack().push(getGraphicsState());
+        setGraphicsState((PDGraphicsState) getGraphicsState().clone());
+    }
+
+    /**
+     * Pops the current graphics state from a graphicsStack.
+     */
+    public void popGraphicsState() 
+    {
+        setGraphicsState((PDGraphicsState) getGraphicsStack().pop());
+    }
+
 }
