You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2012/12/26 16:36:46 UTC
svn commit: r1425954 - in /pdfbox/trunk:
fontbox/src/main/java/org/apache/fontbox/cff/
fontbox/src/test/java/org/apache/fontbox/cff/
preflight/src/main/java/org/apache/pdfbox/preflight/font/util/
Author: lehmi
Date: Wed Dec 26 15:36:45 2012
New Revision: 1425954
URL: http://svn.apache.org/viewvc?rev=1425954&view=rev
Log:
PDFBOX-1473: fixed the handling of "callsubr" and "callgsubr" commands based on a proposal by Juraj Lonc
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CFFFont.java Wed Dec 26 15:36:45 2012
@@ -248,12 +248,12 @@ public class CFFFont
byte[] glyphDesc = this.getCharStringsDict().get(".notdef");
if (((Number)getProperty("CharstringType")).intValue() == 2 ) {
Type2CharStringParser parser = new Type2CharStringParser();
- List<Object> lSeq = parser.parse(glyphDesc);
+ List<Object> lSeq = parser.parse(glyphDesc, getGlobalSubrIndex(), getLocalSubrIndex());
csr = new CharStringRenderer(false);
csr.render(lSeq);
} else {
Type1CharStringParser parser = new Type1CharStringParser();
- List<Object> lSeq = parser.parse(glyphDesc);
+ List<Object> lSeq = parser.parse(glyphDesc, getLocalSubrIndex());
csr = new CharStringRenderer();
csr.render(lSeq);
}
@@ -313,8 +313,7 @@ public class CFFFont
{
Number defaultWidthX = (Number) getProperty("defaultWidthX");
Number nominalWidthX = (Number) getProperty("nominalWidthX");
- return new CharStringConverter(defaultWidthX.intValue(), nominalWidthX
- .intValue(), getGlobalSubrIndex(), getLocalSubrIndex());
+ return new CharStringConverter(defaultWidthX.intValue(), nominalWidthX.intValue());
}
/**
@@ -400,7 +399,7 @@ public class CFFFont
public List<Object> toType2Sequence() throws IOException
{
Type2CharStringParser parser = new Type2CharStringParser();
- return parser.parse(getBytes());
+ return parser.parse(getBytes(), getGlobalSubrIndex(), getLocalSubrIndex());
}
/**
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/CharStringConverter.java Wed Dec 26 15:36:45 2012
@@ -16,7 +16,6 @@
*/
package org.apache.fontbox.cff;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -35,24 +34,34 @@ public class CharStringConverter extends
private int nominalWidthX = 0;
private List<Object> sequence = null;
private int pathCount = 0;
- private IndexData globalSubrIndex = null;
- private IndexData localSubrIndex = null;
/**
* Constructor.
*
* @param defaultWidth default width
* @param nominalWidth nominal width
+ *
+ * @deprecated Use {@link CharStringConverter#CharStringConverter(int, int)} instead
*/
public CharStringConverter(int defaultWidth, int nominalWidth, IndexData fontGlobalSubrIndex, IndexData fontLocalSubrIndex)
{
defaultWidthX = defaultWidth;
nominalWidthX = nominalWidth;
- globalSubrIndex = fontGlobalSubrIndex;
- localSubrIndex = fontLocalSubrIndex;
}
/**
+ * Constructor.
+ *
+ * @param defaultWidth default width
+ * @param nominalWidth nominal width
+ *
+ */
+ public CharStringConverter(int defaultWidth, int nominalWidth)
+ {
+ defaultWidthX = defaultWidth;
+ nominalWidthX = nominalWidth;
+ }
+ /**
* Converts a sequence of Type1/Type2 commands into a sequence of CharStringCommands.
* @param commandSequence the type1/type2 sequence
* @return the CHarStringCommandSequence
@@ -145,44 +154,6 @@ public class CharStringConverter extends
{
drawAlternatingCurve(numbers, true);
}
- else if ("callsubr".equals(name))
- {
- //get subrbias
- int bias = 0;
- int nSubrs = localSubrIndex.getCount();
-
- if (nSubrs < 1240)
- {
- bias = 107;
- }
- else if (nSubrs < 33900)
- {
- bias = 1131;
- }
- else
- {
- bias = 32768;
- }
-
- List<Integer> result = null;
- int subrNumber = bias+numbers.get(numbers.size()-1);
- if (subrNumber < localSubrIndex.getCount())
- {
- Type2CharStringParser parser = new Type2CharStringParser();
- byte[] bytes = localSubrIndex.getBytes(subrNumber);
- List<Object> parsed = null;
- try {
- parsed = parser.parse(bytes);
- parsed.addAll(0,numbers.subList(0, numbers.size()-1));
- result = handleSequence(parsed);
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- return result;
- }
else if ("return".equals(name))
{
return numbers;
@@ -276,42 +247,6 @@ public class CharStringConverter extends
{
drawCurve(numbers, true);
}
- else if ("callgsubr".equals(name))
- {
- //get subrbias
- int bias = 0;
- int nSubrs = globalSubrIndex.getCount();
-
- if (nSubrs < 1240)
- {
- bias = 107;
- }
- else if (nSubrs < 33900)
- {
- bias = 1131;
- }
- else
- {
- bias = 32768;
- }
- List<Integer> result = null;
- int subrNumber = bias+numbers.get(numbers.size()-1);
- if (subrNumber < nSubrs)
- {
- Type2CharStringParser parser = new Type2CharStringParser();
- byte[] bytes = globalSubrIndex.getBytes(subrNumber);
- List<Object> parsed = null;
- try {
- parsed = parser.parse(bytes);
- parsed.addAll(0,numbers.subList(0, numbers.size()-1));
- result = handleSequence(parsed);
- } catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- return result;
- }
else
{
addCommand(numbers, command);
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type1CharStringParser.java Wed Dec 26 15:36:45 2012
@@ -34,18 +34,61 @@ public class Type1CharStringParser
/**
* The given byte array will be parsed and converted to a Type1 sequence.
* @param bytes the given mapping as byte array
+ * @param localSubrIndex index containing all local subroutines
+ *
* @return the Type1 sequence
* @throws IOException if an error occurs during reading
*/
- public List<Object> parse(byte[] bytes) throws IOException
+ public List<Object> parse(byte[] bytes, IndexData localSubrIndex) throws IOException
{
+ return parse(bytes, localSubrIndex, true);
+ }
+
+ private List<Object> parse(byte[] bytes, IndexData localSubrIndex, boolean init) throws IOException
+ {
+ if (init)
+ {
+ sequence = new ArrayList<Object>();
+ }
input = new DataInput(bytes);
- sequence = new ArrayList<Object>();
+ boolean localSubroutineIndexProvided = localSubrIndex != null && localSubrIndex.getCount() > 0;
while (input.hasRemaining())
{
int b0 = input.readUnsignedByte();
- if (b0 >= 0 && b0 <= 31)
+ if (b0 == 10 && localSubroutineIndexProvided)
+ { // process subr command
+ Integer operand=(Integer)sequence.remove(sequence.size()-1);
+ //get subrbias
+ int bias = 0;
+ int nSubrs = localSubrIndex.getCount();
+
+ if (nSubrs < 1240)
+ {
+ bias = 107;
+ }
+ else if (nSubrs < 33900)
+ {
+ bias = 1131;
+ }
+ else
+ {
+ bias = 32768;
+ }
+ int subrNumber = bias+operand;
+ if (subrNumber < localSubrIndex.getCount())
+ {
+ byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
+ parse(subrBytes, localSubrIndex, false);
+ Object lastItem = sequence.get(sequence.size()-1);
+ if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0] == 11)
+ {
+ sequence.remove(sequence.size()-1); // remove "return" command
+ }
+ }
+
+ }
+ else if (b0 >= 0 && b0 <= 31)
{
sequence.add(readCommand(b0));
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/cff/Type2CharStringParser.java Wed Dec 26 15:36:45 2012
@@ -28,7 +28,6 @@ import java.util.List;
public class Type2CharStringParser
{
- private DataInput input = null;
private int hstemCount = 0;
private int vstemCount = 0;
private List<Object> sequence = null;
@@ -36,48 +35,122 @@ public class Type2CharStringParser
/**
* The given byte array will be parsed and converted to a Type2 sequence.
* @param bytes the given mapping as byte array
+ * @param globalSubrIndex index containing all global subroutines
+ * @param localSubrIndex index containing all local subroutines
+ *
* @return the Type2 sequence
* @throws IOException if an error occurs during reading
*/
- public List<Object> parse(byte[] bytes) throws IOException
+ public List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex) throws IOException
{
- input = new DataInput(bytes);
-
- hstemCount = 0;
- vstemCount = 0;
-
- sequence = new ArrayList<Object>();
+ return parse(bytes, globalSubrIndex, localSubrIndex, true);
+ }
+
+ private List<Object> parse(byte[] bytes, IndexData globalSubrIndex, IndexData localSubrIndex, boolean init) throws IOException
+ {
+ if (init)
+ {
+ hstemCount = 0;
+ vstemCount = 0;
+ sequence = new ArrayList<Object>();
+ }
+ DataInput input = new DataInput(bytes);
+ boolean localSubroutineIndexProvided = localSubrIndex != null && localSubrIndex.getCount() > 0;
+ boolean globalSubroutineIndexProvided = globalSubrIndex != null && globalSubrIndex.getCount() > 0;
while (input.hasRemaining())
{
int b0 = input.readUnsignedByte();
-
- if (b0 >= 0 && b0 <= 27)
+ if (b0 == 10 && localSubroutineIndexProvided)
+ { // process subr command
+ Integer operand=(Integer)sequence.remove(sequence.size()-1);
+ //get subrbias
+ int bias = 0;
+ int nSubrs = localSubrIndex.getCount();
+
+ if (nSubrs < 1240)
+ {
+ bias = 107;
+ }
+ else if (nSubrs < 33900)
+ {
+ bias = 1131;
+ }
+ else
+ {
+ bias = 32768;
+ }
+ int subrNumber = bias+operand;
+ if (subrNumber < localSubrIndex.getCount())
+ {
+ byte[] subrBytes = localSubrIndex.getBytes(subrNumber);
+ parse(subrBytes, globalSubrIndex, localSubrIndex, false);
+ Object lastItem=sequence.get(sequence.size()-1);
+ if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0] == 11)
+ {
+ sequence.remove(sequence.size()-1); // remove "return" command
+ }
+ }
+
+ }
+ else if (b0 == 29 && globalSubroutineIndexProvided)
+ { // process globalsubr command
+ Integer operand=(Integer)sequence.remove(sequence.size()-1);
+ //get subrbias
+ int bias = 0;
+ int nSubrs = globalSubrIndex.getCount();
+
+ if (nSubrs < 1240)
+ {
+ bias = 107;
+ }
+ else if (nSubrs < 33900)
+ {
+ bias = 1131;
+ }
+ else
+ {
+ bias = 32768;
+ }
+
+ int subrNumber = bias+operand;
+ if (subrNumber < globalSubrIndex.getCount())
+ {
+ byte[] subrBytes = globalSubrIndex.getBytes(subrNumber);
+ parse(subrBytes, globalSubrIndex, localSubrIndex, false);
+ Object lastItem=sequence.get(sequence.size()-1);
+ if (lastItem instanceof CharStringCommand && ((CharStringCommand)lastItem).getKey().getValue()[0]==11)
+ {
+ sequence.remove(sequence.size()-1); // remove "return" command
+ }
+ }
+
+ }
+ else if (b0 >= 0 && b0 <= 27)
{
- sequence.add(readCommand(b0));
+ sequence.add(readCommand(b0, input));
}
else if (b0 == 28)
{
- sequence.add(readNumber(b0));
+ sequence.add(readNumber(b0, input));
}
else if (b0 >= 29 && b0 <= 31)
{
- sequence.add(readCommand(b0));
+ sequence.add(readCommand(b0, input));
}
else if (b0 >= 32 && b0 <= 255)
{
- sequence.add(readNumber(b0));
+ sequence.add(readNumber(b0, input));
}
else
{
throw new IllegalArgumentException();
}
}
-
return sequence;
}
- private CharStringCommand readCommand(int b0) throws IOException
+ private CharStringCommand readCommand(int b0, DataInput input) throws IOException
{
if (b0 == 1 || b0 == 18)
@@ -111,7 +184,7 @@ public class Type2CharStringParser
return new CharStringCommand(b0);
}
- private Integer readNumber(int b0) throws IOException
+ private Integer readNumber(int b0, DataInput input) throws IOException
{
if (b0 == 28)
@@ -141,11 +214,10 @@ public class Type2CharStringParser
{
int b1 = input.readUnsignedByte();
int b2 = input.readUnsignedByte();
- int b3 = input.readUnsignedByte();
- int b4 = input.readUnsignedByte();
-
// The lower bytes are representing the digits after
// the decimal point and aren't needed in this context
+ input.readUnsignedByte();
+ input.readUnsignedByte();
return Integer.valueOf((short)(b1 << 8 | b2));
}
else
Modified: pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java (original)
+++ pdfbox/trunk/fontbox/src/test/java/org/apache/fontbox/cff/Type1CharStringTest.java Wed Dec 26 15:36:45 2012
@@ -42,7 +42,8 @@ public class Type1CharStringTest
new int[] { 12, 0 }, new int[] { 31 });
byte[] encodedCommands = new Type1CharStringFormatter().format(commands);
- List<Object> decodedCommands = new Type1CharStringParser().parse(encodedCommands);
+ List<Object> decodedCommands = new Type1CharStringParser()
+ .parse(encodedCommands, new IndexData(0));
assertEquals(1 + 2 + 1, encodedCommands.length);
@@ -61,7 +62,7 @@ public class Type1CharStringTest
byte[] encodedNumbers = new Type1CharStringFormatter().format(numbers);
List<Object> decodedNumbers = new Type1CharStringParser()
- .parse(encodedNumbers);
+ .parse(encodedNumbers, new IndexData(0));
assertEquals(5 + 2 * 2 + 3 * 1 + 2 * 2 + 5, encodedNumbers.length);
Modified: pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java?rev=1425954&r1=1425953&r2=1425954&view=diff
==============================================================================
--- pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java (original)
+++ pdfbox/trunk/preflight/src/main/java/org/apache/pdfbox/preflight/font/util/Type1Parser.java Wed Dec 26 15:36:45 2012
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
+import org.apache.fontbox.cff.IndexData;
import org.apache.fontbox.cff.Type1CharStringParser;
import org.apache.fontbox.cff.Type1FontUtil;
import org.apache.pdfbox.encoding.Encoding;
@@ -281,7 +282,8 @@ public final class Type1Parser {
stream.read(descBinary, 0, sizeOfCharString);
byte[] description = Type1FontUtil.charstringDecrypt(descBinary, lenIV);
Type1CharStringParser t1p = new Type1CharStringParser();
- List<Object> operations = t1p.parse(description);
+ // TODO provide the local subroutine indexes
+ List<Object> operations = t1p.parse(description, new IndexData(0));
type1Font.addGlyphDescription(label, new GlyphDescription(operations));
readToken(stream); // skip "ND" or "|-" token