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 2014/05/05 18:33:13 UTC

svn commit: r1592566 - in /pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font: PDType1CFont.java PDType1Font.java

Author: lehmi
Date: Mon May  5 16:33:13 2014
New Revision: 1592566

URL: http://svn.apache.org/r1592566
Log:
PDFBOX-2058: use the build-in character mapping of a type1c font to map special characters for text extraction

Modified:
    pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java
    pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java

Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java?rev=1592566&r1=1592565&r2=1592566&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java Mon May  5 16:33:13 2014
@@ -21,40 +21,28 @@ import java.awt.Font;
 import java.awt.FontFormatException;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
-import java.lang.reflect.Field;
+import java.io.InputStream;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.apache.fontbox.afm.AFMParser;
 import org.apache.fontbox.afm.FontMetric;
 import org.apache.fontbox.cff.AFMFormatter;
-import org.apache.fontbox.cff.charset.CFFCharset;
-import org.apache.fontbox.cff.encoding.CFFEncoding;
 import org.apache.fontbox.cff.CFFFont;
 import org.apache.fontbox.cff.CFFParser;
 import org.apache.fontbox.cff.Type1FontFormatter;
 import org.apache.fontbox.util.BoundingBox;
-
 import org.apache.pdfbox.cos.COSArray;
-import org.apache.pdfbox.cos.COSBase;
 import org.apache.pdfbox.cos.COSDictionary;
 import org.apache.pdfbox.cos.COSFloat;
-import org.apache.pdfbox.cos.COSName;
-import org.apache.pdfbox.cos.COSNumber;
 import org.apache.pdfbox.encoding.Encoding;
-import org.apache.pdfbox.encoding.EncodingManager;
 import org.apache.pdfbox.exceptions.WrappedIOException;
 import org.apache.pdfbox.pdmodel.common.PDMatrix;
 import org.apache.pdfbox.pdmodel.common.PDRectangle;
@@ -63,17 +51,20 @@ import org.apache.pdfbox.pdmodel.common.
 /**
  * This class represents a CFF/Type2 Font (aka Type1C Font).
  * @author Villu Ruusmann
- * @version $Revision: 10.0$
  */
 public class PDType1CFont extends PDSimpleFont
 {
     private CFFFont cffFont = null;
 
-    private Map<Integer, String> codeToName = new HashMap<Integer, String>();
+    private String fontname = null;
 
-    private Map<Integer, String> codeToCharacter = new HashMap<Integer, String>();
+    private Map<Integer, String> sidToName = new HashMap<Integer, String>();
 
-    private Map<String, Integer> characterToCode = new HashMap<String, Integer>();
+    private Map<Integer, Integer> codeToSID = new HashMap<Integer, Integer>();
+
+    private Map<Integer, String> sidToCharacter = new HashMap<Integer, String>();
+
+    private Map<String, Integer> characterToSID = new HashMap<String, Integer>();
 
     private FontMetric fontMetric = null;
 
@@ -91,8 +82,6 @@ public class PDType1CFont extends PDSimp
 
     private static final byte[] SPACE_BYTES = {(byte)32};
 
-    private COSDictionary fontDict = null;
-    
     /**
      * Constructor.
      * @param fontDictionary the corresponding dictionary
@@ -100,31 +89,64 @@ public class PDType1CFont extends PDSimp
     public PDType1CFont( COSDictionary fontDictionary ) throws IOException
     {
         super( fontDictionary );
-        fontDict = fontDictionary;
         load();
     }
 
-    public int encodeToCID( byte[] bytes, int offset, int length )
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String encode(byte[] bytes, int offset, int length) throws IOException
     {
-      if (length > 2)
-      {
-          return -1;
-      }
-      int code = bytes[offset] & 0xff;
-      if (length == 2)
-      {
-          code = code * 256 + bytes[offset+1] & 0xff;
-      }
-      return code;
+        String character = getCharacter(bytes, offset, length);
+        if (character == null)
+        {
+            log.debug("No character for code " + (bytes[offset] & 0xff) + " in " + fontname);
+            return null;
+        }
+        return character;
     }
-    
+
+    private String getCharacter(byte[] bytes, int offset, int length)
+    {
+        int code = getCodeFromArray(bytes, offset, length);
+        String character = null;
+        if (codeToSID.containsKey(code))
+        {
+            code = codeToSID.get(code);
+        }
+        if (sidToCharacter.containsKey(code))
+        {
+            character = sidToCharacter.get(code);
+        }
+        return character;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int encodeToCID(byte[] bytes, int offset, int length)
+    {
+        if (length > 2)
+        {
+            return -1;
+        }
+        int code = bytes[offset] & 0xff;
+        if (length == 2)
+        {
+            code = code * 256 + bytes[offset + 1] & 0xff;
+        }
+        return code;
+    }
+
     /**
      * {@inheritDoc}
      */
     public float getFontWidth( byte[] bytes, int offset, int length ) throws IOException
     {
         String name = getName(bytes, offset, length);
-        if( name == null && !Arrays.equals(SPACE_BYTES, bytes) )
+        if ( name == null && !Arrays.equals(SPACE_BYTES, bytes) )
         {
             log.debug("No name for code " + (bytes[offset] & 0xff) + " in " + this.cffFont.getName());
 
@@ -177,7 +199,7 @@ public class PDType1CFont extends PDSimp
             code = code * 256 + bytes[offset+1] & 0xff;
         }
 
-        return (String)this.codeToName.get(code);
+        return sidToName.get(code);
     }
 
     /**
@@ -207,7 +229,7 @@ public class PDType1CFont extends PDSimp
 
     private Integer getCode( String character )
     {
-        return (Integer)this.characterToCode.get(character);
+        return characterToSID.get(character);
     }
 
 
@@ -314,87 +336,45 @@ public class PDType1CFont extends PDSimp
             this.cffFont = (CFFFont)fonts.get(0);
         }
 
-        CFFEncoding encoding = this.cffFont.getEncoding();
-        PDFEncoding pdfEncoding = new PDFEncoding(encoding);
+        // cache the font name
+        fontname = cffFont.getName();
 
-        CFFCharset charset = this.cffFont.getCharset();
-        PDFCharset pdfCharset = new PDFCharset(charset);
-
-        Map<String,byte[]> charStringsDict = this.cffFont.getCharStringsDict();
-        Map<String,byte[]> pdfCharStringsDict = new LinkedHashMap<String,byte[]>();
-        pdfCharStringsDict.put(".notdef", charStringsDict.get(".notdef"));
-
-        Map<Integer,String> codeToNameMap = new LinkedHashMap<Integer,String>();
+        Number defaultWidthX = (Number) this.cffFont.getProperty("defaultWidthX");
+        this.glyphWidths.put(null, Float.valueOf(defaultWidthX.floatValue()));
 
-        Collection<CFFFont.Mapping> mappings = this.cffFont.getMappings();
-        for( Iterator<CFFFont.Mapping> it = mappings.iterator(); it.hasNext();)
+        Encoding encoding = getFontEncoding();
+        Map<String, Integer> nameToCode = encoding != null ? encoding.getNameToCodeMap() : null;
+        Collection<CFFFont.Mapping> mappings = cffFont.getMappings();
+        Map<Integer, String> codeToNameMap = new LinkedHashMap<Integer, String>();
+        for (CFFFont.Mapping mapping : mappings)
         {
-            CFFFont.Mapping mapping = it.next();
-            Integer code = Integer.valueOf(mapping.getCode());
-            String name = mapping.getName();
-            codeToNameMap.put(code, name);
+            codeToNameMap.put(mapping.getCode(), mapping.getName());
         }
-
-        Set<String> knownNames = new HashSet<String>(codeToNameMap.values());
-
-        Map<Integer,String> codeToNameOverride = loadOverride();
-        for( Iterator<Map.Entry<Integer, String>> it = (codeToNameOverride.entrySet()).iterator(); it.hasNext();)
+        for (CFFFont.Mapping mapping : mappings)
         {
-            Map.Entry<Integer, String> entry = it.next();
-            Integer code = (Integer)entry.getKey();
-            String name = (String)entry.getValue();
-            if(knownNames.contains(name))
+            int sid = mapping.getSID();
+            String name = mapping.getName();
+            String character = null;
+            if (nameToCode != null && nameToCode.containsKey(name))
             {
-                codeToNameMap.put(code, name);
+                sid = nameToCode.get(name);
+                character = encoding.getCharacter(name);
             }
-        }
-
-        Map<String,String> nameToCharacter;
-        try
-        {
-            // TODO remove access by reflection
-            Field nameToCharacterField = Encoding.class.getDeclaredField("NAME_TO_CHARACTER");
-            nameToCharacterField.setAccessible(true);
-            nameToCharacter = (Map<String,String>)nameToCharacterField.get(null);
-        }
-        catch( Exception e )
-        {
-            throw new RuntimeException(e);
-        }
-
-        for( Iterator<Map.Entry<Integer,String>> it = (codeToNameMap.entrySet()).iterator(); it.hasNext();)
-        {
-            Map.Entry<Integer,String> entry = it.next();
-            Integer code = (Integer)entry.getKey();
-            String name = (String)entry.getValue();
-            String uniName = "uni";
-            String character = (String)nameToCharacter.get(name);
-            if( character != null )
+            if (character == null)
             {
-                for( int j = 0; j < character.length(); j++ )
-                {
-                    uniName += hexString(character.charAt(j), 4);
-                }
+                character = Encoding.getCharacterForName(name);
             }
-            else
+            if (character == null)
             {
-                uniName += hexString(code.intValue(), 4);
-                character = String.valueOf((char)code.intValue());
+                name = "uni" + hexString(sid, 4);
+                character = String.valueOf(Character.toChars(sid));
             }
-            pdfEncoding.register(code.intValue(), code.intValue());
-            pdfCharset.register(code.intValue(), uniName);
-            this.codeToName.put(code, uniName);
-            this.codeToCharacter.put(code, character);
-            this.characterToCode.put(character, code);
-            pdfCharStringsDict.put(uniName, charStringsDict.get(name));
+            sidToName.put(sid, name);
+            sidToCharacter.put(sid, character);
+            characterToSID.put(character, sid);
+            codeToSID.put(mapping.getCode(), sid);
         }
 
-        this.cffFont.setEncoding(pdfEncoding);
-        this.cffFont.setCharset(pdfCharset);
-        charStringsDict.clear();
-        charStringsDict.putAll(pdfCharStringsDict);
-        Number defaultWidthX = (Number)this.cffFont.getProperty("defaultWidthX");
-        this.glyphWidths.put(null, Float.valueOf(defaultWidthX.floatValue()));
     }
 
     private byte[] loadBytes() throws IOException
@@ -433,73 +413,6 @@ public class PDType1CFont extends PDSimp
         throw new IOException();
     }
 
-    private Map<Integer,String> loadOverride() throws IOException
-    {
-        Map<Integer,String> result = new LinkedHashMap<Integer,String>();
-        COSBase encoding = fontDict.getDictionaryObject(COSName.ENCODING);
-        if( encoding instanceof COSName )
-        {
-            COSName name = (COSName)encoding;
-            result.putAll(loadEncoding(name));
-        }
-        else if( encoding instanceof COSDictionary )
-        {
-            COSDictionary encodingDic = (COSDictionary)encoding;
-            COSName baseName = (COSName)encodingDic.getDictionaryObject(COSName.BASE_ENCODING);
-            if( baseName != null )
-            {
-                result.putAll(loadEncoding(baseName));
-            }
-            COSArray differences = (COSArray)encodingDic.getDictionaryObject(COSName.DIFFERENCES);
-            if( differences != null )
-            {
-                result.putAll(loadDifferences(differences));
-            }
-        }
-
-        return result;
-    }
-
-    private Map<Integer,String> loadEncoding(COSName name) throws IOException
-    {
-        Map<Integer,String> result = new LinkedHashMap<Integer,String>();
-        Encoding encoding = EncodingManager.INSTANCE.getEncoding(name);
-        for( Iterator<Map.Entry<Integer,String>> it = (encoding.getCodeToNameMap().entrySet()).iterator();
-                    it.hasNext();)
-        {
-            Map.Entry<Integer,String> entry = it.next();
-            result.put(entry.getKey(), (entry.getValue()));
-        }
-
-        return result;
-    }
-
-    private Map<Integer,String> loadDifferences(COSArray differences)
-    {
-        Map<Integer,String> result = new LinkedHashMap<Integer,String>();
-        Integer code = null;
-        for( int i = 0; i < differences.size(); i++)
-        {
-            COSBase element = differences.get(i);
-            if( element instanceof COSNumber )
-            {
-                COSNumber number = (COSNumber)element;
-                code = Integer.valueOf(number.intValue());
-            } 
-            else 
-            {
-                if( element instanceof COSName )
-                {
-                    COSName name = (COSName)element;
-                    result.put(code, name.getName());
-                    code = Integer.valueOf(code.intValue() + 1);
-                }
-            }
-        }
-        return result;
-    }
-
-    
     private static String hexString( int code, int length )
     {
         String string = Integer.toHexString(code);
@@ -560,49 +473,4 @@ public class PDType1CFont extends PDSimp
         }
     }
 
-    /**
-     * This class represents a PDFEncoding.
-     *
-     */
-    private static class PDFEncoding extends CFFEncoding
-    {
-
-        private PDFEncoding( CFFEncoding parent )
-        {
-            Iterator<Entry> parentEntries = parent.getEntries().iterator();
-            while(parentEntries.hasNext())
-            {
-                addEntry(parentEntries.next());
-            }
-        }
-
-        public boolean isFontSpecific()
-        {
-            return true;
-        }
-
-    }
-
-    /**
-     * This class represents a PDFCharset.
-     *
-     */
-    private static class PDFCharset extends CFFCharset
-    {
-        private PDFCharset( CFFCharset parent )
-        {
-            Iterator<Entry> parentEntries = parent.getEntries().iterator();
-            while(parentEntries.hasNext())
-            {
-                addEntry(parentEntries.next());
-            }
-        }
-
-        public boolean isFontSpecific()
-        {
-            return true;
-        }
-
-    }
-
 }

Modified: pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java
URL: http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java?rev=1592566&r1=1592565&r2=1592566&view=diff
==============================================================================
--- pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java (original)
+++ pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Mon May  5 16:33:13 2014
@@ -454,7 +454,29 @@ public class PDType1Font extends PDSimpl
         }
     }
 
-    public int encodeToCID( byte[] c, int offset, int length ) throws IOException {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String encode(byte[] c, int offset, int length) throws IOException
+    {
+        if (type1CFont != null && getFontEncoding() == null)
+        {
+            return type1CFont.encode(c, offset, length);
+        }
+        else
+        {
+            return super.encode(c, offset, length);
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int encodeToCID( byte[] c, int offset, int length ) throws IOException 
+    {
       if (type1CFont != null && getFontEncoding() == null)
       {
           return type1CFont.encodeToCID(c, offset, length);
@@ -464,6 +486,7 @@ public class PDType1Font extends PDSimpl
           return super.encodeToCID(c, offset, length);
       }
     }
+    
     /**
      * {@inheritDoc}
      */