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();