You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by je...@apache.org on 2011/10/18 17:23:57 UTC

svn commit: r1185719 [1/2] - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/pdmodel/common/function/ main/java/org/apache/pdfbox/pdmodel/common/function/type4/ main/java/org/apache/pdfbox/pdmodel/graphics/color/ test/java/org/apache/pdfbox/ t...

Author: jeremias
Date: Tue Oct 18 15:23:56 2011
New Revision: 1185719

URL: http://svn.apache.org/viewvc?rev=1185719&view=rev
Log:
PDFBOX-1142: Added support for Type 4 functions.

Added:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/package.html   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/type4/
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/type4/TestOperators.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/type4/TestParser.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/type4/Type4Tester.java   (with props)
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html   (with props)
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType4.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType4.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType4.java?rev=1185719&r1=1185718&r2=1185719&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType4.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/PDFunctionType4.java Tue Oct 18 15:23:56 2011
@@ -18,26 +18,39 @@ package org.apache.pdfbox.pdmodel.common
 
 import org.apache.pdfbox.cos.COSArray;
 import org.apache.pdfbox.cos.COSBase;
+import org.apache.pdfbox.pdmodel.common.PDRange;
+import org.apache.pdfbox.pdmodel.common.function.type4.ExecutionContext;
+import org.apache.pdfbox.pdmodel.common.function.type4.InstructionSequence;
+import org.apache.pdfbox.pdmodel.common.function.type4.InstructionSequenceBuilder;
+import org.apache.pdfbox.pdmodel.common.function.type4.Operators;
 
 import java.io.IOException;
 
 /**
  * This class represents a type 4 function in a PDF document.
+ * <p>
+ * See section 3.9.4 of the PDF 1.4 Reference.
  *
- * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
  * @version $Revision: 1.2 $
  */
 public class PDFunctionType4 extends PDFunction
 {
 
+    private static final Operators OPERATORS = new Operators();
+
+    private final InstructionSequence instructions;
+
     /**
      * Constructor.
      *
-     * @param functionStream The function .
+     * @param functionStream The function stream.
+     * @throws IOException if an I/O error occurs while reading the function
      */
-    public PDFunctionType4(COSBase function)
+    public PDFunctionType4(COSBase functionStream) throws IOException
     {
-        super( function );
+        super( functionStream );
+        this.instructions = InstructionSequenceBuilder.parse(
+                getPDStream().getInputStreamAsString());
     }
 
 
@@ -54,8 +67,41 @@ public class PDFunctionType4 extends PDF
     */
     public COSArray eval(COSArray input) throws IOException
     {
-        //Implementation here will require evaluation of PostScript functions.
-        //See section 3.9.4 of the PDF Reference.
-        throw new IOException("Not Implemented");
+        //Setup the input values
+        float[] inputValues = input.toFloatArray();
+        int numberOfInputValues = inputValues.length;
+        ExecutionContext context = new ExecutionContext(OPERATORS);
+        for (int i = numberOfInputValues - 1; i >= 0; i--)
+        {
+            PDRange domain = getDomainForInput(i);
+            float value = clipToRange(inputValues[i], domain.getMin(), domain.getMax());
+            context.getStack().push(value);
+        }
+
+        //Execute the type 4 function.
+        instructions.execute(context);
+
+        //Extract the output values
+        int numberOfOutputValues = getNumberOfOutputParameters();
+        int numberOfActualOutputValues = context.getStack().size();
+        if (numberOfActualOutputValues < numberOfOutputValues)
+        {
+            throw new IllegalStateException("The type 4 function returned "
+                    + numberOfActualOutputValues
+                    + " values but the Range entry indicates that "
+                    + numberOfOutputValues + " values be returned.");
+        }
+        float[] outputValues = new float[numberOfOutputValues];
+        for (int i = numberOfOutputValues - 1; i >= 0; i--)
+        {
+            PDRange range = getRangeForOutput(i);
+            outputValues[i] = context.popReal();
+            outputValues[i] = clipToRange(outputValues[i], range.getMin(), range.getMax());
+        }
+
+        //Return the resulting array
+        COSArray result = new COSArray();
+        result.setFloatArray(outputValues);
+        return result;
     }
 }

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,401 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+
+/**
+ * Provides the arithmetic operators such as "add" and "sub".
+ *
+ * @version $Revision$
+ */
+class ArithmeticOperators
+{
+
+    /** Implements the "abs" operator. */
+    static class Abs implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                context.getStack().push(Math.abs(num.intValue()));
+            }
+            else
+            {
+                context.getStack().push(Math.abs(num.floatValue()));
+            }
+        }
+
+    }
+
+    /** Implements the "add" operator. */
+    static class Add implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num2 = context.popNumber();
+            Number num1 = context.popNumber();
+            if (num1 instanceof Integer && num2 instanceof Integer)
+            {
+                long sum = num1.longValue() + num2.longValue();
+                if (sum < Integer.MIN_VALUE || sum > Integer.MAX_VALUE)
+                {
+                    context.getStack().push(Float.valueOf(sum));
+                }
+                else
+                {
+                    context.getStack().push(Integer.valueOf((int)sum));
+                }
+            }
+            else
+            {
+                float sum = num1.floatValue() + num2.floatValue();
+                context.getStack().push(Float.valueOf(sum));
+            }
+        }
+
+    }
+
+    /** Implements the "atan" operator. */
+    static class Atan implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            float den = context.popReal();
+            float num = context.popReal();
+            float atan = (float)Math.atan2(num, den);
+            atan = (float)Math.toDegrees(atan) % 360;
+            if (atan < 0)
+            {
+                atan = atan + 360;
+            }
+            context.getStack().push(atan);
+        }
+
+    }
+
+    /** Implements the "ceiling" operator. */
+    static class Ceiling implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                context.getStack().push(num);
+            }
+            else
+            {
+                context.getStack().push((float)Math.ceil(num.doubleValue()));
+            }
+        }
+
+    }
+
+    /** Implements the "cos" operator. */
+    static class Cos implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            float angle = context.popReal();
+            float cos = (float)Math.cos(Math.toRadians(angle));
+            context.getStack().push(cos);
+        }
+
+    }
+
+    /** Implements the "cvi" operator. */
+    static class Cvi implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            context.getStack().push(num.intValue());
+        }
+
+    }
+
+    /** Implements the "cvr" operator. */
+    static class Cvr implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            context.getStack().push(num.floatValue());
+        }
+
+    }
+
+    /** Implements the "div" operator. */
+    static class Div implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num2 = context.popNumber();
+            Number num1 = context.popNumber();
+            context.getStack().push(num1.floatValue() / num2.floatValue());
+        }
+
+    }
+
+    /** Implements the "exp" operator. */
+    static class Exp implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number exp = context.popNumber();
+            Number base = context.popNumber();
+            double value = Math.pow(base.doubleValue(), exp.doubleValue());
+            context.getStack().push((float)value);
+        }
+
+    }
+
+    /** Implements the "floor" operator. */
+    static class Floor implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                context.getStack().push(num);
+            }
+            else
+            {
+                context.getStack().push((float)Math.floor(num.doubleValue()));
+            }
+        }
+
+    }
+
+    /** Implements the "idiv" operator. */
+    static class IDiv implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            int num2 = context.popInt();
+            int num1 = context.popInt();
+            context.getStack().push(num1 / num2);
+        }
+
+    }
+
+    /** Implements the "ln" operator. */
+    static class Ln implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            context.getStack().push((float)Math.log(num.doubleValue()));
+        }
+
+    }
+
+    /** Implements the "log" operator. */
+    static class Log implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            context.getStack().push((float)Math.log10(num.doubleValue()));
+        }
+
+    }
+
+    /** Implements the "mod" operator. */
+    static class Mod implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            int int2 = context.popInt();
+            int int1 = context.popInt();
+            context.getStack().push(int1 % int2);
+        }
+
+    }
+
+    /** Implements the "mul" operator. */
+    static class Mul implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num2 = context.popNumber();
+            Number num1 = context.popNumber();
+            if (num1 instanceof Integer && num2 instanceof Integer)
+            {
+                long result = num1.longValue() * num2.longValue();
+                if (result >= Integer.MIN_VALUE && result <= Integer.MAX_VALUE)
+                {
+                    context.getStack().push((int)result);
+                }
+                else
+                {
+                    context.getStack().push((float)result);
+                }
+            }
+            else
+            {
+                double result = num1.doubleValue() * num2.doubleValue();
+                context.getStack().push((float)result);
+            }
+        }
+
+    }
+
+    /** Implements the "neg" operator. */
+    static class Neg implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                int v = num.intValue();
+                if (v == Integer.MIN_VALUE)
+                {
+                    context.getStack().push(-num.floatValue());
+                }
+                else
+                {
+                    context.getStack().push(-num.intValue());
+                }
+            }
+            else
+            {
+                context.getStack().push(-num.floatValue());
+            }
+        }
+
+    }
+
+    /** Implements the "round" operator. */
+    static class Round implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                context.getStack().push(num.intValue());
+            }
+            else
+            {
+                context.getStack().push((float)Math.round(num.doubleValue()));
+            }
+        }
+
+    }
+
+    /** Implements the "sin" operator. */
+    static class Sin implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            float angle = context.popReal();
+            float sin = (float)Math.sin(Math.toRadians(angle));
+            context.getStack().push(sin);
+        }
+
+    }
+
+    /** Implements the "sqrt" operator. */
+    static class Sqrt implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            float num = context.popReal();
+            if (num < 0)
+            {
+                throw new IllegalArgumentException("argument must be nonnegative");
+            }
+            context.getStack().push((float)Math.sqrt(num));
+        }
+
+    }
+
+    /** Implements the "sub" operator. */
+    static class Sub implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Number num2 = context.popNumber();
+            Number num1 = context.popNumber();
+            if (num1 instanceof Integer && num2 instanceof Integer)
+            {
+                long result = num1.longValue() - num2.longValue();
+                if (result < Integer.MIN_VALUE || result > Integer.MAX_VALUE)
+                {
+                    stack.push(Float.valueOf(result));
+                }
+                else
+                {
+                    stack.push(Integer.valueOf((int)result));
+                }
+            }
+            else
+            {
+                float result = num1.floatValue() - num2.floatValue();
+                stack.push(Float.valueOf(result));
+            }
+        }
+
+    }
+
+    /** Implements the "truncate" operator. */
+    static class Truncate implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Number num = context.popNumber();
+            if (num instanceof Integer)
+            {
+                context.getStack().push(num.intValue());
+            }
+            else
+            {
+                context.getStack().push((float)(int)(num.floatValue()));
+            }
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ArithmeticOperators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,193 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+
+/**
+ * Provides the bitwise operators such as "and" and "xor".
+ *
+ * @version $Revision$
+ */
+class BitwiseOperators
+{
+
+    /** Abstract base class for logical operators. */
+    private abstract static class AbstractLogicalOperator implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Object op2 = stack.pop();
+            Object op1 = stack.pop();
+            if (op1 instanceof Boolean && op2 instanceof Boolean)
+            {
+                boolean bool1 = (Boolean)op1;
+                boolean bool2 = (Boolean)op2;
+                boolean result = applyForBoolean(bool1, bool2);
+                stack.push(result);
+            }
+            else if (op1 instanceof Integer && op2 instanceof Integer)
+            {
+                int int1 = (Integer)op1;
+                int int2 = (Integer)op2;
+                int result = applyforInteger(int1, int2);
+                stack.push(result);
+            }
+            else
+            {
+                throw new ClassCastException("Operands must be bool/bool or int/int");
+            }
+        }
+
+
+        protected abstract boolean applyForBoolean(boolean bool1, boolean bool2);
+
+        protected abstract int applyforInteger(int int1, int int2);
+
+    }
+
+    /** Implements the "and" operator. */
+    static class And extends AbstractLogicalOperator
+    {
+
+        @Override
+        protected boolean applyForBoolean(boolean bool1, boolean bool2)
+        {
+            return bool1 & bool2;
+        }
+
+        @Override
+        protected int applyforInteger(int int1, int int2)
+        {
+            return int1 & int2;
+        }
+    }
+
+    /** Implements the "bitshift" operator. */
+    static class Bitshift implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            int shift = (Integer)stack.pop();
+            int int1 = (Integer)stack.pop();
+            if (shift < 0)
+            {
+                int result = int1 >> Math.abs(shift);
+                stack.push(result);
+            }
+            else
+            {
+                int result = int1 << shift;
+                stack.push(result);
+            }
+        }
+
+    }
+
+    /** Implements the "false" operator. */
+    static class False implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            stack.push(Boolean.FALSE);
+        }
+
+    }
+
+    /** Implements the "not" operator. */
+    static class Not implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Object op1 = stack.pop();
+            if (op1 instanceof Boolean)
+            {
+                boolean bool1 = (Boolean)op1;
+                boolean result = !bool1;
+                stack.push(result);
+            }
+            else if (op1 instanceof Integer)
+            {
+                int int1 = (Integer)op1;
+                int result = -int1;
+                stack.push(result);
+            }
+            else
+            {
+                throw new ClassCastException("Operand must be bool or int");
+            }
+        }
+
+    }
+
+    /** Implements the "or" operator. */
+    static class Or extends AbstractLogicalOperator
+    {
+
+        @Override
+        protected boolean applyForBoolean(boolean bool1, boolean bool2)
+        {
+            return bool1 | bool2;
+        }
+
+        @Override
+        protected int applyforInteger(int int1, int int2)
+        {
+            return int1 | int2;
+        }
+
+    }
+
+    /** Implements the "true" operator. */
+    static class True implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            stack.push(Boolean.TRUE);
+        }
+
+    }
+
+    /** Implements the "xor" operator. */
+    static class Xor extends AbstractLogicalOperator
+    {
+
+        @Override
+        protected boolean applyForBoolean(boolean bool1, boolean bool2)
+        {
+            return bool1 ^ bool2;
+        }
+
+        @Override
+        protected int applyforInteger(int int1, int int2)
+        {
+            return int1 ^ int2;
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/BitwiseOperators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,68 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+
+/**
+ * Provides the conditional operators such as "if" and "ifelse".
+ *
+ * @version $Revision$
+ */
+class ConditionalOperators
+{
+
+    /** Implements the "if" operator. */
+    static class If implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            InstructionSequence proc = (InstructionSequence)stack.pop();
+            Boolean condition = (Boolean)stack.pop();
+            if (condition)
+            {
+                proc.execute(context);
+            }
+        }
+
+    }
+
+    /** Implements the "ifelse" operator. */
+    static class IfElse implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            InstructionSequence proc2 = (InstructionSequence)stack.pop();
+            InstructionSequence proc1 = (InstructionSequence)stack.pop();
+            Boolean condition = (Boolean)stack.pop();
+            if (condition)
+            {
+                proc1.execute(context);
+            }
+            else
+            {
+                proc2.execute(context);
+            }
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ConditionalOperators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,89 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+
+/**
+ * Makes up the execution context, holding the available operators and the execution stack.
+ *
+ * @version $Revision$
+ */
+public class ExecutionContext
+{
+
+    private Operators operators;
+    private Stack<Object> stack = new Stack<Object>();
+
+    /**
+     * Creates a new execution context.
+     * @param operatorSet the operator set
+     */
+    public ExecutionContext(Operators operatorSet)
+    {
+        this.operators = operatorSet;
+    }
+
+    /**
+     * Returns the stack used by this execution context.
+     * @return the stack
+     */
+    public Stack<Object> getStack()
+    {
+        return this.stack;
+    }
+
+    /**
+     * Returns the operator set used by this execution context.
+     * @return the operator set
+     */
+    public Operators getOperators()
+    {
+        return this.operators;
+    }
+
+    /**
+     * Pops a number (int or real) from the stack. If it's neither data type, a
+     * ClassCastException is thrown.
+     * @return the number
+     */
+    public Number popNumber()
+    {
+        return (Number)stack.pop();
+    }
+
+    /**
+     * Pops a value of type int from the stack. If the value is not of type int, a
+     * ClassCastException is thrown.
+     * @return the int value
+     */
+    public int popInt()
+    {
+        return ((Integer)stack.pop()).intValue();
+    }
+
+    /**
+     * Pops a number from the stack and returns it as a real value. If the value is not of a
+     * numeric type, a ClassCastException is thrown.
+     * @return the real value
+     */
+    public float popReal()
+    {
+        return ((Number)stack.pop()).floatValue();
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/ExecutionContext.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,113 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Represents an instruction sequence, a combination of values, operands and nested procedures.
+ *
+ * @version $Revision$
+ */
+public class InstructionSequence
+{
+
+    private List<Object> instructions = new java.util.ArrayList<Object>();
+
+    /**
+     * Add a name (ex. an operator)
+     * @param name the name
+     */
+    public void addName(String name)
+    {
+        this.instructions.add(name);
+    }
+
+    /**
+     * Adds an int value.
+     * @param value the value
+     */
+    public void addInteger(int value)
+    {
+        this.instructions.add(Integer.valueOf(value));
+    }
+
+    /**
+     * Adds a real value.
+     * @param value the value
+     */
+    public void addReal(float value)
+    {
+        this.instructions.add(Float.valueOf(value));
+    }
+
+    /**
+     * Adds a bool value.
+     * @param value the value
+     */
+    public void addBoolean(boolean value)
+    {
+        this.instructions.add(Boolean.valueOf(value));
+    }
+
+    /**
+     * Adds a proc (sub-sequence of instructions).
+     * @param child the child proc
+     */
+    public void addProc(InstructionSequence child)
+    {
+        this.instructions.add(child);
+    }
+
+    /**
+     * Executes the instruction sequence.
+     * @param context the execution context
+     */
+    public void execute(ExecutionContext context)
+    {
+        Stack<Object> stack = context.getStack();
+        for (Object o : instructions)
+        {
+            if (o instanceof String)
+            {
+                String name = (String)o;
+                Operator cmd = context.getOperators().getOperator(name);
+                if (cmd != null)
+                {
+                    cmd.execute(context);
+                }
+                else
+                {
+                    throw new UnsupportedOperationException("Unknown operator or name: " + name);
+                }
+            }
+            else
+            {
+                stack.push(o);
+            }
+        }
+
+        //Handles top-level procs that simply need to be executed
+        while (!stack.isEmpty() && stack.peek() instanceof InstructionSequence)
+        {
+            InstructionSequence nested = (InstructionSequence)stack.pop();
+            nested.execute(context);
+        }
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequence.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,134 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Basic parser for Type 4 functions which is used to build up instruction sequences.
+ *
+ * @version $Revision$
+ */
+public class InstructionSequenceBuilder extends Parser.AbstractSyntaxHandler
+{
+
+    private InstructionSequence mainSequence = new InstructionSequence();
+    private Stack<InstructionSequence> seqStack = new Stack<InstructionSequence>();
+
+    private InstructionSequenceBuilder()
+    {
+        this.seqStack.push(this.mainSequence);
+    }
+
+    /**
+     * Returns the instruction sequence that has been build from the syntactic elements.
+     * @return the instruction sequence
+     */
+    public InstructionSequence getInstructionSequence()
+    {
+        return this.mainSequence;
+    }
+
+    /**
+     * Parses the given text into an instruction sequence representing a Type 4 function
+     * that can be executed.
+     * @param text the Type 4 function text
+     * @return the instruction sequence
+     */
+    public static InstructionSequence parse(CharSequence text)
+    {
+        InstructionSequenceBuilder builder = new InstructionSequenceBuilder();
+        Parser.parse(text, builder);
+        return builder.getInstructionSequence();
+    }
+
+    private InstructionSequence getCurrentSequence()
+    {
+        return this.seqStack.peek();
+    }
+
+    private static final Pattern INTEGER_PATTERN = Pattern.compile("[\\+\\-]?\\d+");
+    private static final Pattern REAL_PATTERN = Pattern.compile("[\\-]?\\d*\\.\\d*([Ee]\\-?\\d+)?");
+
+    /** {@inheritDoc} */
+    public void token(CharSequence text)
+    {
+        String token = text.toString();
+        token(token);
+    }
+
+    private void token(String token)
+    {
+        if ("{".equals(token))
+        {
+            InstructionSequence child = new InstructionSequence();
+            getCurrentSequence().addProc(child);
+            this.seqStack.push(child);
+        }
+        else if ("}".equals(token))
+        {
+            this.seqStack.pop();
+        }
+        else
+        {
+            Matcher m = INTEGER_PATTERN.matcher(token);
+            if (m.matches())
+            {
+                getCurrentSequence().addInteger(parseInt(token.toString()));
+                return;
+            }
+
+            m = REAL_PATTERN.matcher(token);
+            if (m.matches())
+            {
+                getCurrentSequence().addReal(parseReal(token));
+                return;
+            }
+
+            //TODO Maybe implement radix numbers, such as 8#1777 or 16#FFFE
+
+            getCurrentSequence().addName(token.toString());
+        }
+    }
+
+    /**
+     * Parses a value of type "int".
+     * @param token the token to be parsed
+     * @return the parsed value
+     */
+    public static int parseInt(String token)
+    {
+        if (token.startsWith("+"))
+        {
+            token = token.substring(1);
+        }
+        return Integer.parseInt(token);
+    }
+
+    /**
+     * Parses a value of type "real".
+     * @param token the token to be parsed
+     * @return the parsed value
+     */
+    public static float parseReal(String token)
+    {
+        return Float.parseFloat(token);
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/InstructionSequenceBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.common.function.type4;
+
+/**
+ * Interface for PostScript operators.
+ *
+ * @version $Revision$
+ */
+public interface Operator
+{
+
+    /**
+     * Executes the operator. The method can inspect and manipulate the stack.
+     * @param context the execution context
+     */
+    void execute(ExecutionContext context);
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operator.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,142 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Map;
+
+/**
+ * This class provides all the supported operators.
+ * @version $Revision$
+ */
+public class Operators
+{
+
+    //Arithmetic operators
+    private static final Operator ABS = new ArithmeticOperators.Abs();
+    private static final Operator ADD = new ArithmeticOperators.Add();
+    private static final Operator ATAN = new ArithmeticOperators.Atan();
+    private static final Operator CEILING = new ArithmeticOperators.Ceiling();
+    private static final Operator COS = new ArithmeticOperators.Cos();
+    private static final Operator CVI = new ArithmeticOperators.Cvi();
+    private static final Operator CVR = new ArithmeticOperators.Cvr();
+    private static final Operator DIV = new ArithmeticOperators.Div();
+    private static final Operator EXP = new ArithmeticOperators.Exp();
+    private static final Operator FLOOR = new ArithmeticOperators.Floor();
+    private static final Operator IDIV = new ArithmeticOperators.IDiv();
+    private static final Operator LN = new ArithmeticOperators.Ln();
+    private static final Operator LOG = new ArithmeticOperators.Log();
+    private static final Operator MOD = new ArithmeticOperators.Mod();
+    private static final Operator MUL = new ArithmeticOperators.Mul();
+    private static final Operator NEG = new ArithmeticOperators.Neg();
+    private static final Operator ROUND = new ArithmeticOperators.Round();
+    private static final Operator SIN = new ArithmeticOperators.Sin();
+    private static final Operator SQRT = new ArithmeticOperators.Sqrt();
+    private static final Operator SUB = new ArithmeticOperators.Sub();
+    private static final Operator TRUNCATE = new ArithmeticOperators.Truncate();
+
+    //Relational, boolean and bitwise operators
+    private static final Operator AND = new BitwiseOperators.And();
+    private static final Operator BITSHIFT = new BitwiseOperators.Bitshift();
+    private static final Operator EQ = new RelationalOperators.Eq();
+    private static final Operator FALSE = new BitwiseOperators.False();
+    private static final Operator GE = new RelationalOperators.Ge();
+    private static final Operator GT = new RelationalOperators.Gt();
+    private static final Operator LE = new RelationalOperators.Le();
+    private static final Operator LT = new RelationalOperators.Lt();
+    private static final Operator NE = new RelationalOperators.Ne();
+    private static final Operator NOT = new BitwiseOperators.Not();
+    private static final Operator OR = new BitwiseOperators.Or();
+    private static final Operator TRUE = new BitwiseOperators.True();
+    private static final Operator XOR = new BitwiseOperators.Xor();
+
+    //Conditional operators
+    private static final Operator IF = new ConditionalOperators.If();
+    private static final Operator IFELSE = new ConditionalOperators.IfElse();
+
+    //Stack operators
+    private static final Operator COPY = new StackOperators.Copy();
+    private static final Operator DUP = new StackOperators.Dup();
+    private static final Operator EXCH = new StackOperators.Exch();
+    private static final Operator INDEX = new StackOperators.Index();
+    private static final Operator POP = new StackOperators.Pop();
+    private static final Operator ROLL = new StackOperators.Roll();
+
+    private Map<String, Operator> operators = new java.util.HashMap<String, Operator>();
+
+    /**
+     * Creates a new Operators object with the default set of operators.
+     */
+    public Operators()
+    {
+        operators.put("add", ADD);
+        operators.put("abs", ABS);
+        operators.put("atan", ATAN);
+        operators.put("ceiling", CEILING);
+        operators.put("cos", COS);
+        operators.put("cvi", CVI);
+        operators.put("cvr", CVR);
+        operators.put("div", DIV);
+        operators.put("exp", EXP);
+        operators.put("floor", FLOOR);
+        operators.put("idiv", IDIV);
+        operators.put("ln", LN);
+        operators.put("log", LOG);
+        operators.put("mod", MOD);
+        operators.put("mul", MUL);
+        operators.put("neg", NEG);
+        operators.put("round", ROUND);
+        operators.put("sin", SIN);
+        operators.put("sqrt", SQRT);
+        operators.put("sub", SUB);
+        operators.put("truncate", TRUNCATE);
+
+        operators.put("and", AND);
+        operators.put("bitshift", BITSHIFT);
+        operators.put("eq", EQ);
+        operators.put("false", FALSE);
+        operators.put("ge", GE);
+        operators.put("gt", GT);
+        operators.put("le", LE);
+        operators.put("lt", LT);
+        operators.put("ne", NE);
+        operators.put("not", NOT);
+        operators.put("or", OR);
+        operators.put("true", TRUE);
+        operators.put("xor", XOR);
+
+        operators.put("if", IF);
+        operators.put("ifelse", IFELSE);
+
+        operators.put("copy", COPY);
+        operators.put("dup", DUP);
+        operators.put("exch", EXCH);
+        operators.put("index", INDEX);
+        operators.put("pop", POP);
+        operators.put("roll", ROLL);
+    }
+
+    /**
+     * Returns the operator for the given operator name.
+     * @param operatorName the operator name
+     * @return the operator (or null if there's no such operator
+     */
+    public Operator getOperator(String operatorName)
+    {
+        return this.operators.get(operatorName);
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Operators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,317 @@
+/*
+ * 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.common.function.type4;
+
+/**
+ * Parser for PDF Type 4 functions. This implements a small subset of the PostScript
+ * language but is no full PostScript interpreter.
+ *
+ * @version $Revision$
+ */
+public class Parser
+{
+
+    /** Used to indicate the parsers current state. */
+    private static enum State
+    {
+        NEWLINE, WHITESPACE, COMMENT, TOKEN
+    }
+
+    private Parser()
+    {
+        //nop
+    }
+
+    /**
+     * Parses a Type 4 function and sends the syntactic elements to the given
+     * syntax handler.
+     * @param input the text source
+     * @param handler the syntax handler
+     */
+    public static void parse(CharSequence input, SyntaxHandler handler)
+    {
+        Tokenizer tokenizer = new Tokenizer(input, handler);
+        tokenizer.tokenize();
+    }
+
+    /**
+     * This interface defines all possible syntactic elements of a Type 4 function.
+     * It is called by the parser as the function is interpreted.
+     */
+    public interface SyntaxHandler
+    {
+
+        /**
+         * Indicates that a new line starts.
+         * @param text the new line character (CR, LF, CR/LF or FF)
+         */
+        void newLine(CharSequence text);
+
+        /**
+         * Called when whitespace characters are encountered.
+         * @param text the whitespace text
+         */
+        void whitespace(CharSequence text);
+
+        /**
+         * Called when a token is encountered. No distinction between operators and values
+         * is done here.
+         * @param text the token text
+         */
+        void token(CharSequence text);
+
+        /**
+         * Called for a comment.
+         * @param text the comment
+         */
+        void comment(CharSequence text);
+    }
+
+    /**
+     * Abstract base class for a {@link SyntaxHandler}.
+     */
+    public abstract static class AbstractSyntaxHandler implements SyntaxHandler
+    {
+
+        /** {@inheritDoc} */
+        public void comment(CharSequence text)
+        {
+            //nop
+        }
+
+        /** {@inheritDoc} */
+        public void newLine(CharSequence text)
+        {
+            //nop
+        }
+
+        /** {@inheritDoc} */
+        public void whitespace(CharSequence text)
+        {
+            //nop
+        }
+
+    }
+
+    /**
+     * Tokenizer for Type 4 functions.
+     */
+    private static class Tokenizer
+    {
+
+        private static final char NUL = '\u0000'; //NUL
+        private static final char EOT = '\u0004'; //END OF TRANSMISSION
+        private static final char TAB = '\u0009'; //TAB CHARACTER
+        private static final char FF = '\u000C'; //FORM FEED
+        private static final char CR = '\r'; //CARRIAGE RETURN
+        private static final char LF = '\n'; //LINE FEED
+        private static final char SPACE = '\u0020'; //SPACE
+
+        private CharSequence input;
+        private int index;
+        private SyntaxHandler handler;
+        private State state = State.WHITESPACE;
+        private StringBuilder buffer = new StringBuilder();
+
+        private Tokenizer(CharSequence text, SyntaxHandler syntaxHandler)
+        {
+            this.input = text;
+            this.handler = syntaxHandler;
+        }
+
+        private boolean hasMore()
+        {
+            return index < input.length();
+        }
+
+        private char currentChar()
+        {
+            return input.charAt(index);
+        }
+
+        private char nextChar()
+        {
+            index++;
+            if (!hasMore())
+            {
+                return EOT;
+            }
+            else
+            {
+                return currentChar();
+            }
+        }
+
+        private char peek()
+        {
+            if (index < input.length() - 1)
+            {
+                return input.charAt(index + 1);
+            }
+            else
+            {
+                return EOT;
+            }
+        }
+
+        private State nextState()
+        {
+            char ch = currentChar();
+            switch (ch)
+            {
+            case CR:
+            case LF:
+            case FF: //FF
+                state = State.NEWLINE;
+                break;
+            case NUL:
+            case TAB:
+            case SPACE:
+                state = State.WHITESPACE;
+                break;
+            case '%':
+                state = State.COMMENT;
+                break;
+            default:
+                state = State.TOKEN;
+            }
+            return state;
+        }
+
+        private void tokenize()
+        {
+            while (hasMore())
+            {
+                buffer.setLength(0);
+                nextState();
+                switch (state)
+                {
+                case NEWLINE:
+                    scanNewLine();
+                    break;
+                case WHITESPACE:
+                    scanWhitespace();
+                    break;
+                case COMMENT:
+                    scanComment();
+                    break;
+                default:
+                    scanToken();
+                }
+            }
+        }
+
+        private void scanNewLine()
+        {
+            assert state == State.NEWLINE;
+            char ch = currentChar();
+            buffer.append(ch);
+            if (ch == CR)
+            {
+                if (peek() == LF)
+                {
+                    //CRLF is treated as one newline
+                    buffer.append(nextChar());
+                }
+            }
+            handler.newLine(buffer);
+        }
+
+        private void scanWhitespace()
+        {
+            assert state == State.WHITESPACE;
+            buffer.append(currentChar());
+            loop:
+            while (hasMore())
+            {
+                char ch = nextChar();
+                switch (ch)
+                {
+                case NUL:
+                case TAB:
+                case SPACE:
+                    buffer.append(ch);
+                    break;
+                default:
+                    break loop;
+                }
+            }
+            handler.whitespace(buffer);
+        }
+
+        private void scanComment()
+        {
+            assert state == State.COMMENT;
+            buffer.append(currentChar());
+            loop:
+            while (hasMore())
+            {
+                char ch = nextChar();
+                switch (ch)
+                {
+                case CR:
+                case LF:
+                case FF:
+                    break loop;
+                default:
+                    buffer.append(ch);
+                }
+            }
+            //EOF reached
+            handler.comment(buffer);
+        }
+
+        private void scanToken()
+        {
+            assert state == State.TOKEN;
+            char ch = currentChar();
+            buffer.append(ch);
+            switch (ch)
+            {
+            case '{':
+            case '}':
+                handler.token(buffer);
+                nextChar();
+                return;
+            default:
+                //continue
+            }
+            loop:
+            while (hasMore())
+            {
+                ch = nextChar();
+                switch (ch)
+                {
+                case NUL:
+                case TAB:
+                case SPACE:
+                case CR:
+                case LF:
+                case FF:
+                case EOT:
+                    break loop;
+                default:
+                    buffer.append(ch);
+                }
+            }
+            //EOF reached
+            handler.token(buffer);
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/Parser.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,140 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.Stack;
+
+/**
+ * Provides the relational operators such as "eq" and "le".
+ *
+ * @version $Revision$
+ */
+class RelationalOperators
+{
+
+    /** Implements the "eq" operator. */
+    static class Eq implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Object op2 = stack.pop();
+            Object op1 = stack.pop();
+            boolean result = isEqual(op1, op2);
+            stack.push(result);
+        }
+
+        protected boolean isEqual(Object op1, Object op2)
+        {
+            boolean result = false;
+            if (op1 instanceof Number && op2 instanceof Number)
+            {
+                Number num1 = (Number)op1;
+                Number num2 = (Number)op2;
+                result = num1.floatValue() == num2.floatValue();
+            }
+            else
+            {
+                result = op1.equals(op2);
+            }
+            return result;
+        }
+
+    }
+
+    /** Abstract base class for number comparison operators. */
+    private abstract static class AbstractNumberComparisonOperator implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Object op2 = stack.pop();
+            Object op1 = stack.pop();
+            Number num1 = (Number)op1;
+            Number num2 = (Number)op2;
+            boolean result = compare(num1, num2);
+            stack.push(result);
+        }
+
+        protected abstract boolean compare(Number num1, Number num2);
+
+    }
+
+    /** Implements the "ge" operator. */
+    static class Ge extends AbstractNumberComparisonOperator
+    {
+
+        @Override
+        protected boolean compare(Number num1, Number num2)
+        {
+            return num1.floatValue() >= num2.floatValue();
+        }
+
+    }
+
+    /** Implements the "gt" operator. */
+    static class Gt extends AbstractNumberComparisonOperator
+    {
+
+        @Override
+        protected boolean compare(Number num1, Number num2)
+        {
+            return num1.floatValue() > num2.floatValue();
+        }
+
+    }
+
+    /** Implements the "le" operator. */
+    static class Le extends AbstractNumberComparisonOperator
+    {
+
+        @Override
+        protected boolean compare(Number num1, Number num2)
+        {
+            return num1.floatValue() <= num2.floatValue();
+        }
+
+    }
+
+    /** Implements the "lt" operator. */
+    static class Lt extends AbstractNumberComparisonOperator
+    {
+
+        @Override
+        protected boolean compare(Number num1, Number num2)
+        {
+            return num1.floatValue() < num2.floatValue();
+        }
+
+    }
+
+    /** Implements the "ne" operator. */
+    static class Ne extends Eq
+    {
+
+        @Override
+        protected boolean isEqual(Object op1, Object op2)
+        {
+            boolean result = super.isEqual(op1, op2);
+            return !result;
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/RelationalOperators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,162 @@
+/*
+ * 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.common.function.type4;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Provides the stack operators such as "pop" and "dup".
+ *
+ * @version $Revision$
+ */
+class StackOperators
+{
+
+    /** Implements the "copy" operator. */
+    static class Copy implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            int n = ((Number)stack.pop()).intValue();
+            if (n > 0)
+            {
+                int size = stack.size();
+                //Need to copy to a new list to avoid ConcurrentModificationException
+                List<Object> copy = new java.util.ArrayList<Object>(
+                        stack.subList(size - n, size));
+                stack.addAll(copy);
+            }
+        }
+
+    }
+
+    /** Implements the "dup" operator. */
+    static class Dup implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            stack.push(stack.peek());
+        }
+
+    }
+
+    /** Implements the "exch" operator. */
+    static class Exch implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            Object any2 = stack.pop();
+            Object any1 = stack.pop();
+            stack.push(any2);
+            stack.push(any1);
+        }
+
+    }
+
+    /** Implements the "index" operator. */
+    static class Index implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            int n = ((Number)stack.pop()).intValue();
+            if (n < 0)
+            {
+                throw new IllegalArgumentException("rangecheck: " + n);
+            }
+            int size = stack.size();
+            stack.push(stack.get(size - n - 1));
+        }
+
+    }
+
+    /** Implements the "pop" operator. */
+    static class Pop implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            stack.pop();
+        }
+
+    }
+
+    /** Implements the "roll" operator. */
+    static class Roll implements Operator
+    {
+
+        public void execute(ExecutionContext context)
+        {
+            Stack<Object> stack = context.getStack();
+            int j = ((Number)stack.pop()).intValue();
+            int n = ((Number)stack.pop()).intValue();
+            if (j == 0)
+            {
+                return; //Nothing to do
+            }
+            if (n < 0)
+            {
+                throw new IllegalArgumentException("rangecheck: " + n);
+            }
+
+            LinkedList<Object> rolled = new LinkedList<Object>();
+            LinkedList<Object> moved = new LinkedList<Object>();
+            if (j < 0)
+            {
+                //negative roll
+                int n1 = n + j;
+                for (int i = 0; i < n1; i++)
+                {
+                    moved.addFirst(stack.pop());
+                }
+                for (int i = j; i < 0; i++)
+                {
+                    rolled.addFirst(stack.pop());
+                }
+                stack.addAll(moved);
+                stack.addAll(rolled);
+            }
+            else
+            {
+                //positive roll
+                int n1 = n - j;
+                for (int i = j; i > 0; i--)
+                {
+                    rolled.addFirst(stack.pop());
+                }
+                for (int i = 0; i < n1; i++)
+                {
+                    moved.addFirst(stack.pop());
+                }
+                stack.addAll(rolled);
+                stack.addAll(moved);
+            }
+        }
+
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/StackOperators.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html (added)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html Tue Oct 18 15:23:56 2011
@@ -0,0 +1,25 @@
+<!--
+ ! 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.
+ !-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This package contains Type 4 function support.
+</body>
+</html>

Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/common/function/type4/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java?rev=1185719&r1=1185718&r2=1185719&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDDeviceN.java Tue Oct 18 15:23:56 2011
@@ -27,13 +27,11 @@ 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.COSInteger;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.cos.COSNull;
 
 import org.apache.pdfbox.pdmodel.common.COSArrayList;
 import org.apache.pdfbox.pdmodel.common.function.PDFunction;
-import org.apache.pdfbox.pdmodel.common.function.PDFunctionType4;
 
 /**
  * This class represents a DeviceN color space.
@@ -43,14 +41,14 @@ import org.apache.pdfbox.pdmodel.common.
  */
 public class PDDeviceN extends PDColorSpace
 {
-   
+
     /**
      * Log instance.
      */
     private static final Log LOG = LogFactory.getLog(PDDeviceN.class);
 
     private static final int COLORANT_NAMES = 1;
-    
+
     private static final int ALTERNATE_CS = 2;
 
     private static final int TINT_TRANSFORM = 3;
@@ -259,7 +257,7 @@ public class PDDeviceN extends PDColorSp
             array.set( DEVICEN_ATTRIBUTES, attributes.getCOSDictionary() );
         }
     }
-    
+
     /**
      * Returns the components of the color in the alternate colorspace for the given tint value.
      * @param tintValues a list containing the tint values
@@ -269,32 +267,9 @@ public class PDDeviceN extends PDColorSp
     public COSArray calculateColorValues(List<COSBase> tintValues) throws IOException
     {
         PDFunction tintTransform = getTintTransform();
-        if(tintTransform instanceof PDFunctionType4)
-        {
-            LOG.warn("Unsupported tint transformation type: "+tintTransform.getClass().getName() 
-                    + " in "+getClass().getName()+".getColorValues()"
-                    + " using color black instead.");
-            int numberOfComponents = getAlternateColorSpace().getNumberOfComponents();
-            // To get black as color:
-            // 0 is used for the single value(s) if the colorspace is gray or RGB based
-            COSArray retval = new COSArray();
-            for ( int i=0; i < numberOfComponents; i++ ) 
-            {
-                retval.add(COSInteger.ZERO);
-            }
-            // 1 is used as forth value if the colorspace is CMYK based
-            if (numberOfComponents == PDDeviceCMYK.INSTANCE.getNumberOfComponents())
-            {
-                retval.set(3, COSInteger.ONE);
-            }
-            return retval;
-        }
-        else
-        {
-            COSArray tint = new COSArray();
-            tint.addAll(tintValues);
-            return tintTransform.eval(tint);
-        }
+        COSArray tint = new COSArray();
+        tint.addAll(tintValues);
+        return tintTransform.eval(tint);
     }
 
 }

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java?rev=1185719&r1=1185718&r2=1185719&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/color/PDSeparation.java Tue Oct 18 15:23:56 2011
@@ -25,10 +25,8 @@ 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.COSFloat;
 import org.apache.pdfbox.cos.COSName;
 import org.apache.pdfbox.pdmodel.common.function.PDFunction;
-import org.apache.pdfbox.pdmodel.common.function.PDFunctionType4;
 
 /**
  * This class represents a Separation color space.
@@ -205,37 +203,18 @@ public class PDSeparation extends PDColo
     {
         array.set( 3, tint );
     }
-    
+
     /**
      * Returns the components of the color in the alternate colorspace for the given tint value.
+     * @param tintValue the tint value
      * @return COSArray with the color components
      * @throws IOException If the tint function is not supported
      */
     public COSArray calculateColorValues(COSBase tintValue) throws IOException
     {
         PDFunction tintTransform = getTintTransform();
-        if(tintTransform instanceof PDFunctionType4)
-        {
-            log.warn("Unsupported tint transformation type: "+tintTransform.getClass().getName() 
-                    + " in "+getClass().getName()+".getColorValues()"
-                    + " using color black instead.");
-            int numberOfComponents = getAlternateColorSpace().getNumberOfComponents();
-            // To get black as color:
-            // 0.0f is used for the single value(s) if the colorspace is gray or RGB based
-            // 1.0f is used for the single value if the colorspace is CMYK based
-            float colorValue = numberOfComponents == 4 ? 1.0f : 0.0f;
-            COSArray retval = new COSArray();
-            for (int i=0;i<numberOfComponents;i++) 
-            {
-                retval.add(new COSFloat(colorValue));
-            }
-            return retval;
-        }
-        else
-        {
-            COSArray tint = new COSArray();
-            tint.add(tintValue);
-            return tintTransform.eval(tint);
-        }
+        COSArray tint = new COSArray();
+        tint.add(tintValue);
+        return tintTransform.eval(tint);
     }
 }

Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java?rev=1185719&r1=1185718&r2=1185719&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/TestAll.java Tue Oct 18 15:23:56 2011
@@ -86,6 +86,7 @@ public class TestAll extends TestCase
         suite.addTestSuite( org.apache.pdfbox.pdmodel.graphics.optionalcontent.TestOptionalContentGroups.class );
         suite.addTestSuite( org.apache.pdfbox.util.TestLayerUtility.class );
         suite.addTestSuite( org.apache.pdfbox.TestTextToPdf.class );
+        suite.addTest( org.apache.pdfbox.pdmodel.common.function.TestFunctions.suite() );
 
         suite.addTestSuite( TestIOUtils.class );
         suite.addTestSuite( TestPackedBitArray.class );

Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,58 @@
+/*
+ * 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.common.function;
+
+import org.apache.pdfbox.pdmodel.common.function.type4.TestOperators;
+import org.apache.pdfbox.pdmodel.common.function.type4.TestParser;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Tests PDF functions.
+ *
+ * @version $Revision$
+ */
+public class TestFunctions extends TestCase
+{
+
+    /**
+     * The main method to run tests.
+     *
+     * @param args The command line arguments.
+     */
+    public static void main( String[] args )
+    {
+        String[] arg = {TestFunctions.class.getName()};
+        junit.textui.TestRunner.main( arg );
+    }
+
+    /**
+     * This will get the suite of test that this class holds.
+     *
+     * @return All of the tests that this class holds.
+     */
+    public static Test suite()
+    {
+        TestSuite suite = new TestSuite(TestFunctions.class.getName());
+        suite.addTestSuite(TestOperators.class);
+        suite.addTestSuite(TestParser.class);
+        suite.addTestSuite(TestPDFunctionType4.class);
+        return suite;
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestFunctions.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java?rev=1185719&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java Tue Oct 18 15:23:56 2011
@@ -0,0 +1,116 @@
+/*
+ * 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.common.function;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSFloat;
+import org.apache.pdfbox.cos.COSStream;
+import org.apache.pdfbox.io.RandomAccessBuffer;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests the {@link PDFunctionType4} class.
+ *
+ * @version $Revision$
+ */
+public class TestPDFunctionType4 extends TestCase
+{
+
+    private PDFunctionType4 createFunction(String function, float[] domain, float[] range)
+            throws IOException
+    {
+        COSDictionary dict = new COSDictionary();
+        dict.setInt("FunctionType", 4);
+        COSArray domainArray = new COSArray();
+        domainArray.setFloatArray(domain);
+        dict.setItem("Domain", domainArray);
+        COSArray rangeArray = new COSArray();
+        rangeArray.setFloatArray(range);
+        dict.setItem("Range", rangeArray);
+
+        COSStream functionStream = new COSStream(dict, new RandomAccessBuffer());
+        OutputStream out = functionStream.createUnfilteredStream();
+        byte[] data = function.getBytes("US-ASCII");
+        out.write(data, 0, data.length);
+        out.flush();
+
+        return new PDFunctionType4(functionStream);
+    }
+
+    /**
+     * Checks the {@link PDFunctionType4}.
+     * @throws Exception if an error occurs
+     */
+    public void testFunctionSimple() throws Exception
+    {
+        String functionText = "{ add }";
+        //Simply adds the two arguments and returns the result
+
+        PDFunctionType4 function = createFunction(functionText,
+                new float[] {-1.0f, 1.0f, -1.0f, 1.0f},
+                new float[] {-1.0f, 1.0f});
+
+        COSArray input = new COSArray();
+        input.setFloatArray(new float[] {0.8f, 0.1f});
+        COSArray output = function.eval(input);
+
+        assertEquals(1, output.size());
+        assertEquals(0.9f, ((COSFloat)output.get(0)).floatValue(), 0.0001f);
+
+        input = new COSArray();
+        input.setFloatArray(new float[] {0.8f, 0.3f}); //results in 1.1f being outside Range
+        output = function.eval(input);
+
+        assertEquals(1, output.size());
+        assertEquals(new COSFloat(1.0f), output.get(0));
+
+        input = new COSArray();
+        input.setFloatArray(new float[] {0.8f, 1.2f}); //input argument outside Dimension
+        output = function.eval(input);
+
+        assertEquals(1, output.size());
+        assertEquals(new COSFloat(1.0f), output.get(0));
+    }
+
+    /**
+     * Checks the handling of the argument order for a {@link PDFunctionType4}.
+     * @throws Exception if an error occurs
+     */
+    public void testFunctionArgumentOrder() throws Exception
+    {
+        String functionText = "{ pop }";
+        //pops the top-most argument and returns the second as is.
+
+        PDFunctionType4 function = createFunction(functionText,
+                new float[] {-1.0f, 1.0f, -1.0f, 1.0f},
+                new float[] {-1.0f, 1.0f});
+
+        COSArray input = new COSArray();
+        input.setFloatArray(new float[] {-0.7f, 0.0f});
+        COSArray output = function.eval(input);
+
+        assertEquals(1, output.size());
+        assertEquals(0.0f, ((COSFloat)output.get(0)).floatValue(), 0.0001f);
+        //TODO not sure if this is really correct
+    }
+
+}

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/common/function/TestPDFunctionType4.java
------------------------------------------------------------------------------
    svn:keywords = Id