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 2010/06/14 19:21:30 UTC

svn commit: r954561 - in /pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf: CMAPEncodingEntry.java TTFParser.java

Author: lehmi
Date: Mon Jun 14 17:21:30 2010
New Revision: 954561

URL: http://svn.apache.org/viewvc?rev=954561&view=rev
Log:
PDFBOX-670: added management of CMap format 2 for true type fonts. Patch by Eric Leleu (eric dot leleu at atosorigin dot com)

Modified:
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java
    pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java?rev=954561&r1=954560&r2=954561&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java Mon Jun 14 17:21:30 2010
@@ -75,19 +75,50 @@ public class CMAPEncodingEntry
         else if( subtableFormat == 2 )
         {
             int[] subHeaderKeys = new int[256];
+            // ---- keep the Max Index of the SubHeader array to know its length
+            int maxSubHeaderIndex = 0;
             for( int i=0; i<256; i++)
             {
                 subHeaderKeys[i] = data.readUnsignedShort();
+                maxSubHeaderIndex = Math.max(maxSubHeaderIndex, (int)(subHeaderKeys[i]/8));
             }
-            int firstCode = data.readUnsignedShort();
-            int entryCount = data.readUnsignedShort();
-            short idDelta = data.readSignedShort();
-            int idRangeOffset = data.readUnsignedShort();
-            //BJL
-            //HMM the TTF spec is not very clear about what is suppose to
-            //happen here.  If you know please submit a patch or point
-            //me to some better documentation.
-            throw new IOException( "Not yet implemented:" + subtableFormat );
+                
+            // ---- Read all SubHeaders to avoid useless seek on DataSource
+            SubHeader[] subHeaders = new SubHeader[maxSubHeaderIndex + 1]; 
+            for (int i = 0; i <= maxSubHeaderIndex ; ++i ) 
+            {
+                int firstCode = data.readUnsignedShort();
+                int entryCount = data.readUnsignedShort();
+                short idDelta = data.readSignedShort();
+                int idRangeOffset = data.readUnsignedShort();
+                subHeaders[i] = new SubHeader(firstCode, entryCount, idDelta, idRangeOffset);
+            }
+                
+            long startGlyphIndexOffset = data.getCurrentPosition();
+            glyphIdToCharacterCode = new int[numGlyphs];
+            for ( int i = 0; i <= maxSubHeaderIndex ; ++i )
+            {
+                SubHeader sh = subHeaders[i];
+                int firstCode = sh.getFirstCode();
+                for ( int j = 0 ; j < sh.getEntryCount() ; ++j)
+                {
+                    // ---- compute the Character Code
+                    int charCode = ( i * 8 );
+                    charCode = (charCode << 8 ) + (firstCode + j);
+                    
+                    // ---- Go to the CharacterCOde position in the Sub Array 
+                    //      of the glyphIndexArray 
+                    //      glyphIndexArray contains Unsigned Short so add (j * 2) bytes 
+                    //      at the index position
+                    data.seek(startGlyphIndexOffset + sh.getIdRangeOffset() + (j*2));
+                    int p = data.readUnsignedShort();
+                    // ---- compute the glyphIndex 
+                    p = p + sh.getIdDelta() % 65536;
+                    
+                    glyphIdToCharacterCode[p] = charCode;
+                    characterCodeToGlyphId.put(charCode, p);
+                }
+            }        
         }
         else if( subtableFormat == 4 )
         {
@@ -225,4 +256,65 @@ public class CMAPEncodingEntry
     		return 0;
     	}
     }
+    
+    /**
+     * Class used to manage CMap - Format 2
+     */
+    private class SubHeader {
+        
+        private int firstCode;
+        private int entryCount;
+        /**
+         * used to compute the GlyphIndex :
+         * P = glyphIndexArray.SubArray[pos]
+         * GlyphIndex = P + idDelta % 65536
+         */
+        private short idDelta;
+        /**
+         * Number of bytes to skip to reach the firstCode in the 
+         * glyphIndexArray 
+         */
+        private int idRangeOffset;
+        
+        private SubHeader(int firstCode, int entryCount, short idDelta, int idRangeOffset) 
+        {
+            this.firstCode = firstCode;
+            this.entryCount = entryCount;
+            this.idDelta = idDelta;
+            this.idRangeOffset = idRangeOffset;
+        }    
+    
+        /**
+         * @return the firstCode
+         */
+        private int getFirstCode() 
+        {
+            return firstCode;
+        }
+    
+        /**
+         * @return the entryCount
+         */
+        private int getEntryCount() 
+        {
+            return entryCount;
+        }    
+    
+        /**
+         * @return the idDelta
+         */
+        private short getIdDelta() 
+        {
+            return idDelta;
+        }
+    
+        /**
+         * @return the idRangeOffset
+         */
+        private int getIdRangeOffset() 
+        {
+            return idRangeOffset;
+        }
+    }
+
 }

Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java?rev=954561&r1=954560&r2=954561&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java Mon Jun 14 17:21:30 2010
@@ -109,27 +109,41 @@ public class TTFParser
         List<TTFTable> initialized = new ArrayList<TTFTable>();
         //need to initialize a couple tables in a certain order
         HeaderTable head = font.getHeader();
+        if (head == null) {
+        	throw new IOException("head is mandatory");
+        }
         raf.seek( head.getOffset() );
         head.initData( font, raf );
         initialized.add( head );
         
-        
         HorizontalHeaderTable hh = font.getHorizontalHeader();
+        if (hh == null) {
+        	throw new IOException("hhead is mandatory");
+        }
         raf.seek( hh.getOffset() );
         hh.initData( font, raf );
         initialized.add( hh );
         
         MaximumProfileTable maxp = font.getMaximumProfile();
+        if (maxp == null) {
+        	throw new IOException("maxp is mandatory");
+        }
         raf.seek( maxp.getOffset() );
         maxp.initData( font, raf );
         initialized.add( maxp );
         
         PostScriptTable post = font.getPostScript();
+        if (post == null) {
+        	throw new IOException("post is mandatory");
+        }
         raf.seek( post.getOffset() );
         post.initData( font, raf );
         initialized.add( post );
         
         IndexToLocationTable loc = font.getIndexToLocation();
+        if (loc == null) {
+        	throw new IOException("loca is mandatory");
+        }
         raf.seek( loc.getOffset() );
         loc.initData( font, raf );
         initialized.add( loc );
@@ -191,14 +205,6 @@ public class TTFParser
         {
             retval = new PostScriptTable();
         }
-        else if( tag.equals( GlyphTable.TAG ) )
-        {
-            retval = new GlyphTable();
-        }
-        else if( tag.equals( GlyphTable.TAG ) )
-        {
-            retval = new GlyphTable();
-        }
         else if( tag.equals( DigitalSignatureTable.TAG ) )
         {
             retval = new DigitalSignatureTable();