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 2013/07/23 19:13:11 UTC
svn commit: r1506164 - in
/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf:
AbstractTTFParser.java CMAPEncodingEntry.java CMAPTable.java Glyph2D.java
TTFParser.java
Author: lehmi
Date: Tue Jul 23 17:13:11 2013
New Revision: 1506164
URL: http://svn.apache.org/r1506164
Log:
PDFBOX-490: fixed CMap format 2, added some new constants fixed some parser checks, removed Glyph2D class
Removed:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/Glyph2D.java
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/AbstractTTFParser.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPEncodingEntry.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPTable.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/AbstractTTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/AbstractTTFParser.java?rev=1506164&r1=1506163&r2=1506164&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/AbstractTTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/AbstractTTFParser.java Tue Jul 23 17:13:11 2013
@@ -23,70 +23,86 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-abstract class AbstractTTFParser {
-
+/**
+ * This class represents a true type font parser.
+ *
+ */
+abstract class AbstractTTFParser
+{
+
protected boolean isEmbedded = false;
- public AbstractTTFParser(boolean isEmbedded) {
- this.isEmbedded = isEmbedded;
- }
-
+ /**
+ * Constructor.
+ *
+ * @param fontIsEmbedded indicates whether the font is embedded or not.
+ *
+ */
+ public AbstractTTFParser(boolean fontIsEmbedded)
+ {
+ isEmbedded = fontIsEmbedded;
+ }
+
/**
* Parse a file and get a true type font.
+ *
* @param ttfFile The TTF file.
* @return A true type font.
* @throws IOException If there is an error parsing the true type font.
*/
- public TrueTypeFont parseTTF( String ttfFile ) throws IOException
+ public TrueTypeFont parseTTF(String ttfFile) throws IOException
{
- RAFDataStream raf = new RAFDataStream( ttfFile, "r" );
- return parseTTF( raf );
+ RAFDataStream raf = new RAFDataStream(ttfFile, "r");
+ return parseTTF(raf);
}
-
+
/**
* Parse a file and get a true type font.
+ *
* @param ttfFile The TTF file.
* @return A true type font.
* @throws IOException If there is an error parsing the true type font.
*/
- public TrueTypeFont parseTTF( File ttfFile ) throws IOException
+ public TrueTypeFont parseTTF(File ttfFile) throws IOException
{
- RAFDataStream raf = new RAFDataStream( ttfFile, "r" );
- return parseTTF( raf );
+ RAFDataStream raf = new RAFDataStream(ttfFile, "r");
+ return parseTTF(raf);
}
-
+
/**
* Parse a file and get a true type font.
+ *
* @param ttfData The TTF data to parse.
* @return A true type font.
* @throws IOException If there is an error parsing the true type font.
*/
- public TrueTypeFont parseTTF( InputStream ttfData ) throws IOException
+ public TrueTypeFont parseTTF(InputStream ttfData) throws IOException
{
- return parseTTF( new MemoryTTFDataStream( ttfData ));
+ return parseTTF(new MemoryTTFDataStream(ttfData));
}
-
+
/**
* Parse a file and get a true type font.
+ *
* @param raf The TTF file.
* @return A true type font.
* @throws IOException If there is an error parsing the true type font.
*/
- public TrueTypeFont parseTTF( TTFDataStream raf ) throws IOException
+ public TrueTypeFont parseTTF(TTFDataStream raf) throws IOException
{
- TrueTypeFont font = new TrueTypeFont( raf );
- font.setVersion( raf.read32Fixed() );
+ TrueTypeFont font = new TrueTypeFont(raf);
+ font.setVersion(raf.read32Fixed());
int numberOfTables = raf.readUnsignedShort();
int searchRange = raf.readUnsignedShort();
int entrySelector = raf.readUnsignedShort();
int rangeShift = raf.readUnsignedShort();
- for( int i=0; i<numberOfTables; i++ )
+ for (int i = 0; i < numberOfTables; i++)
{
- TTFTable table = readTableDirectory( raf );
- font.addTable( table );
+ TTFTable table = readTableDirectory(raf);
+ font.addTable(table);
}
- //need to initialize a couple tables in a certain order
+ // need to initialize a couple tables in a certain order
parseTables(font, raf);
return font;
@@ -94,177 +110,149 @@ abstract class AbstractTTFParser {
/**
* Parse all tables and check if all needed tables are present.
+ *
* @param font the TrueTypeFont instance holding the parsed data.
* @param raf the data stream of the to be parsed ttf font
* @throws IOException If there is an error parsing the true type font.
*/
- protected void parseTables(TrueTypeFont font, TTFDataStream raf)
- throws IOException {
+ protected void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOException
+ {
List<TTFTable> initialized = new ArrayList<TTFTable>();
HeaderTable head = font.getHeader();
- if (head == null)
+ if (head == null)
{
throw new IOException("head is mandatory");
}
- raf.seek( head.getOffset() );
- head.initData( font, raf );
- initialized.add( head );
+ raf.seek(head.getOffset());
+ head.initData(font, raf);
+ initialized.add(head);
HorizontalHeaderTable hh = font.getHorizontalHeader();
- if (hh == null)
+ if (hh == null)
{
throw new IOException("hhead is mandatory");
}
- raf.seek( hh.getOffset() );
- hh.initData( font, raf );
- initialized.add( hh );
+ raf.seek(hh.getOffset());
+ hh.initData(font, raf);
+ initialized.add(hh);
MaximumProfileTable maxp = font.getMaximumProfile();
- if (maxp != null)
+ if (maxp != null)
{
- raf.seek( maxp.getOffset() );
- maxp.initData( font, raf );
- initialized.add( maxp );
- }
- else
+ raf.seek(maxp.getOffset());
+ maxp.initData(font, raf);
+ initialized.add(maxp);
+ }
+ else
{
throw new IOException("maxp is mandatory");
}
PostScriptTable post = font.getPostScript();
- if (post != null) {
- raf.seek( post.getOffset() );
- post.initData( font, raf );
- initialized.add( post );
- }
- else if ( !isEmbedded )
+ if (post != null)
+ {
+ raf.seek(post.getOffset());
+ post.initData(font, raf);
+ initialized.add(post);
+ }
+ else if (!isEmbedded)
{
// in an embedded font this table is optional
throw new IOException("post is mandatory");
}
IndexToLocationTable loc = font.getIndexToLocation();
- if (loc == null)
+ if (loc == null)
{
throw new IOException("loca is mandatory");
}
- raf.seek( loc.getOffset() );
- loc.initData( font, raf );
- initialized.add( loc );
+ raf.seek(loc.getOffset());
+ loc.initData(font, raf);
+ initialized.add(loc);
- boolean cvt = false, prep = false, fpgm = false;
Iterator<TTFTable> iter = font.getTables().iterator();
- while( iter.hasNext() )
+ while (iter.hasNext())
{
TTFTable table = iter.next();
- if( !initialized.contains( table ) )
+ if (!initialized.contains(table))
{
- raf.seek( table.getOffset() );
- table.initData( font, raf );
+ raf.seek(table.getOffset());
+ table.initData(font, raf);
}
- if (table.getTag().startsWith("cvt"))
- {
- cvt = true;
- }
- else if ("prep".equals(table.getTag()))
- {
- prep = true;
- }
- else if ("fpgm".equals(table.getTag()))
- {
- fpgm = true;
- }
- }
+ }
- // check others mandatory tables
- if ( font.getGlyph() == null )
+ // check other mandatory tables
+ if (font.getGlyph() == null)
{
throw new IOException("glyf is mandatory");
}
- if ( font.getNaming() == null && !isEmbedded )
+ if (font.getNaming() == null && !isEmbedded)
{
throw new IOException("name is mandatory");
}
- if ( font.getHorizontalMetrics() == null )
+ if (font.getHorizontalMetrics() == null)
{
throw new IOException("hmtx is mandatory");
}
-
- if (isEmbedded) {
- // in a embedded truetype font prep, cvt_ and fpgm tables
- // are mandatory
- if (!fpgm)
- {
- throw new IOException("fpgm is mandatory");
- }
- if (!prep)
- {
- throw new IOException("prep is mandatory");
- }
- if (!cvt)
- {
- throw new IOException("cvt_ is mandatory");
- }
- }
}
- private TTFTable readTableDirectory( TTFDataStream raf ) throws IOException
+ private TTFTable readTableDirectory(TTFDataStream raf) throws IOException
{
TTFTable retval = null;
- String tag = raf.readString( 4 );
- if( tag.equals( CMAPTable.TAG ) )
+ String tag = raf.readString(4);
+ if (tag.equals(CMAPTable.TAG))
{
retval = new CMAPTable();
}
- else if( tag.equals( GlyphTable.TAG ) )
+ else if (tag.equals(GlyphTable.TAG))
{
retval = new GlyphTable();
}
- else if( tag.equals( HeaderTable.TAG ) )
+ else if (tag.equals(HeaderTable.TAG))
{
retval = new HeaderTable();
}
- else if( tag.equals( HorizontalHeaderTable.TAG ) )
+ else if (tag.equals(HorizontalHeaderTable.TAG))
{
retval = new HorizontalHeaderTable();
}
- else if( tag.equals( HorizontalMetricsTable.TAG ) )
+ else if (tag.equals(HorizontalMetricsTable.TAG))
{
retval = new HorizontalMetricsTable();
}
- else if( tag.equals( IndexToLocationTable.TAG ) )
+ else if (tag.equals(IndexToLocationTable.TAG))
{
retval = new IndexToLocationTable();
}
- else if( tag.equals( MaximumProfileTable.TAG ) )
+ else if (tag.equals(MaximumProfileTable.TAG))
{
retval = new MaximumProfileTable();
}
- else if( tag.equals( NamingTable.TAG ) )
+ else if (tag.equals(NamingTable.TAG))
{
retval = new NamingTable();
}
- else if( tag.equals( OS2WindowsMetricsTable.TAG ) )
+ else if (tag.equals(OS2WindowsMetricsTable.TAG))
{
retval = new OS2WindowsMetricsTable();
}
- else if( tag.equals( PostScriptTable.TAG ) )
+ else if (tag.equals(PostScriptTable.TAG))
{
retval = new PostScriptTable();
}
- else if( tag.equals( DigitalSignatureTable.TAG ) )
+ else if (tag.equals(DigitalSignatureTable.TAG))
{
retval = new DigitalSignatureTable();
}
else
{
- //unknown table type but read it anyway.
+ // unknown table type but read it anyway.
retval = new TTFTable();
}
- retval.setTag( tag );
- retval.setCheckSum( raf.readUnsignedInt() );
- retval.setOffset( raf.readUnsignedInt() );
- retval.setLength( raf.readUnsignedInt() );
+ retval.setTag(tag);
+ retval.setCheckSum(raf.readUnsignedInt());
+ retval.setOffset(raf.readUnsignedInt());
+ retval.setLength(raf.readUnsignedInt());
return retval;
}
}
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=1506164&r1=1506163&r2=1506164&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 Tue Jul 23 17:13:11 2013
@@ -22,566 +22,608 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+
/**
* An encoding entry for a cmap.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.2 $
+ *
*/
public class CMAPEncodingEntry
{
+ private static final long LEAD_OFFSET = 0xD800 - (0x10000 >> 10);
+ private static final long SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
- private int platformId;
- private int platformEncodingId;
- private long subTableOffset;
- private int[] glyphIdToCharacterCode;
- private Map<Integer, Integer> characterCodeToGlyphId = new HashMap<Integer, Integer>();
-
- /**
- * This will read the required data from the stream.
- *
- * @param ttf The font that is being read.
- * @param data The stream to read the data from.
- * @throws IOException If there is an error reading the data.
- */
- public void initData( TrueTypeFont ttf, TTFDataStream data ) throws IOException
- {
- platformId = data.readUnsignedShort();
- platformEncodingId = data.readUnsignedShort();
- subTableOffset = data.readUnsignedInt();
- }
-
- /**
- * This will read the required data from the stream.
- *
- * @param ttf The font that is being read.
- * @param data The stream to read the data from.
- * @throws IOException If there is an error reading the data.
- */
- public void initSubtable( TrueTypeFont ttf, TTFDataStream data ) throws IOException
- {
- data.seek( ttf.getCMAP().getOffset() + subTableOffset );
- int subtableFormat = data.readUnsignedShort();
- long length;
- long version;
- int numGlyphs;
- if (subtableFormat < 8) {
- length = data.readUnsignedShort();
- version = data.readUnsignedShort();
- numGlyphs = ttf.getMaximumProfile().getNumGlyphs();
- } else {
- // read an other UnsignedShort to read a Fixed32
- data.readUnsignedShort();
- length = data.readUnsignedInt();
- version = data.readUnsignedInt();
- numGlyphs = ttf.getMaximumProfile().getNumGlyphs();
- }
-
- switch (subtableFormat) {
- case 0:
- processSubtype0(ttf, data);
- break;
- case 2:
- processSubtype2(ttf, data, numGlyphs);
- break;
- case 4:
- processSubtype4(ttf, data, numGlyphs);
- break;
- case 6:
- processSubtype6(ttf, data, numGlyphs);
- break;
- case 8:
- processSubtype8(ttf, data, numGlyphs);
- break;
- case 10:
- processSubtype10(ttf, data, numGlyphs);
- break;
- case 12:
- processSubtype12(ttf, data, numGlyphs);
- break;
- case 13:
- processSubtype13(ttf, data, numGlyphs);
- break;
- case 14:
- processSubtype14(ttf, data, numGlyphs);
- break;
- default:
- throw new IOException( "Unknown cmap format:" + subtableFormat );
- }
- }
-
- /**
- * Reads a format 8 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype8( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- // --- is32 is a 65536 BITS array ( = 8192 BYTES)
- int[] is32 = data.readUnsignedByteArray(8192);
- long nbGroups = data.readUnsignedInt();
-
- // --- nbGroups shouldn't be greater than 65536
- if (nbGroups > 65536) {
- throw new IOException("CMap ( Subtype8 ) is invalid");
- }
-
- glyphIdToCharacterCode = new int[numGlyphs];
- // -- Read all sub header
- for (long i = 0; i <= nbGroups ; ++i )
- {
- long firstCode = data.readUnsignedInt();
- long endCode = data.readUnsignedInt();
- long startGlyph = data.readUnsignedInt();
-
- // -- process simple validation
- if (firstCode > endCode || 0 > firstCode) {
- throw new IOException("Range invalid");
- }
-
- for (long j = firstCode; j <= endCode; ++j) {
- // -- Convert the Character code in decimal
- if (j > Integer.MAX_VALUE) {
- throw new IOException("[Sub Format 8] Invalid Character code");
- }
-
- int currentCharCode;
- if ( (is32[ (int)j / 8 ] & (1 << ((int)j % 8 ))) == 0) {
- currentCharCode = (int)j;
- } else {
- // the character code uses a 32bits format
- // convert it in decimal : see http://www.unicode.org/faq//utf_bom.html#utf16-4
- long LEAD_OFFSET = 0xD800 - (0x10000 >> 10);
- long SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
- long lead = LEAD_OFFSET + (j >> 10);
- long trail = 0xDC00 + (j & 0x3FF);
-
- long codepoint = (lead << 10) + trail + SURROGATE_OFFSET;
- if (codepoint > Integer.MAX_VALUE) {
- throw new IOException("[Sub Format 8] Invalid Character code");
- }
- currentCharCode = (int)codepoint;
- }
-
- long glyphIndex = startGlyph + (j-firstCode);
- if (glyphIndex > numGlyphs || glyphIndex > Integer.MAX_VALUE) {
- throw new IOException("CMap contains an invalid glyph index");
- }
-
- glyphIdToCharacterCode[(int)glyphIndex] = currentCharCode;
- characterCodeToGlyphId.put(currentCharCode, (int)glyphIndex);
- }
- }
- }
-
- /**
- * Reads a format 10 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype10( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- long startCode = data.readUnsignedInt();
- long numChars = data.readUnsignedInt();
- if (numChars > Integer.MAX_VALUE) {
- throw new IOException("Invalid number of Characters");
- }
-
- if ( startCode < 0 || startCode > 0x0010FFFF
- || (startCode + numChars) > 0x0010FFFF
- || ((startCode + numChars) >= 0x0000D800 && (startCode + numChars) <= 0x0000DFFF)) {
- throw new IOException("Invalid Characters codes");
-
- }
- }
-
- /**
- * Reads a format 12 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype12( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- long nbGroups = data.readUnsignedInt();
- glyphIdToCharacterCode = new int[numGlyphs];
- for (long i = 0; i <= nbGroups ; ++i )
- {
- long firstCode = data.readUnsignedInt();
- long endCode = data.readUnsignedInt();
- long startGlyph = data.readUnsignedInt();
-
- if ( firstCode < 0 || firstCode > 0x0010FFFF
- || ( firstCode >= 0x0000D800 && firstCode <= 0x0000DFFF ) ) {
- throw new IOException("Invalid Characters codes");
- }
-
- if ( endCode > 0 && (endCode < firstCode || endCode > 0x0010FFFF
- || ( endCode >= 0x0000D800 && endCode <= 0x0000DFFF ) ) ) {
- throw new IOException("Invalid Characters codes");
- }
-
- for (long j = 0; j <= (endCode - firstCode); ++j) {
-
- if ( (firstCode + j) > Integer.MAX_VALUE ) {
- throw new IOException("Character Code greater than Integer.MAX_VALUE");
- }
-
- long glyphIndex = (startGlyph + j);
- if (glyphIndex > numGlyphs || glyphIndex > Integer.MAX_VALUE) {
- throw new IOException("CMap contains an invalid glyph index");
- }
- glyphIdToCharacterCode[(int)glyphIndex] = (int)(firstCode + j);
- characterCodeToGlyphId.put((int)(firstCode + j), (int)glyphIndex);
- }
- }
- }
-
- /**
- * Reads a format 13 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype13( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- long nbGroups = data.readUnsignedInt();
- for (long i = 0; i <= nbGroups ; ++i )
- {
- long firstCode = data.readUnsignedInt();
- long endCode = data.readUnsignedInt();
- long glyphId = data.readUnsignedInt();
-
- if (glyphId > numGlyphs) {
- throw new IOException("CMap contains an invalid glyph index");
- }
-
- if ( firstCode < 0 || firstCode > 0x0010FFFF
- || ( firstCode >= 0x0000D800 && firstCode <= 0x0000DFFF ) ) {
- throw new IOException("Invalid Characters codes");
- }
-
- if ( endCode > 0 && (endCode < firstCode || endCode > 0x0010FFFF
- || ( endCode >= 0x0000D800 && endCode <= 0x0000DFFF )) ) {
- throw new IOException("Invalid Characters codes");
- }
-
- for (long j = 0; j <= (endCode - firstCode); ++j) {
-
- if ( (firstCode + j) > Integer.MAX_VALUE ) {
- throw new IOException("Character Code greater than Integer.MAX_VALUE");
- }
- glyphIdToCharacterCode[(int)glyphId] = (int)(firstCode + j);
- characterCodeToGlyphId.put((int)(firstCode + j), (int)glyphId);
- }
- }
- }
-
- /**
- * Reads a format 14 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype14( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- throw new IOException("CMap subtype 14 not yet implemented");
- }
-
- /**
- * Reads a format 6 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype6( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- int firstCode = data.readUnsignedShort();
- int entryCount = data.readUnsignedShort();
- glyphIdToCharacterCode = new int[numGlyphs];
- int[] glyphIdArray = data.readUnsignedShortArray( entryCount );
- for( int i=0; i<entryCount; i++)
- {
- glyphIdToCharacterCode[glyphIdArray[i]] = firstCode+i;
- characterCodeToGlyphId.put((firstCode+i), glyphIdArray[i]);
- }
- }
-
- /**
- * Reads a format 4 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype4( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- int segCountX2 = data.readUnsignedShort();
- int segCount = segCountX2/2;
- int searchRange = data.readUnsignedShort();
- int entrySelector = data.readUnsignedShort();
- int rangeShift = data.readUnsignedShort();
- int[] endCount = data.readUnsignedShortArray( segCount );
- int reservedPad = data.readUnsignedShort();
- int[] startCount = data.readUnsignedShortArray( segCount );
- int[] idDelta = data.readUnsignedShortArray( segCount );
- int[] idRangeOffset = data.readUnsignedShortArray( segCount );
-
- Map<Integer, Integer> tmpGlyphToChar = new HashMap<Integer, Integer>();
-
- long currentPosition = data.getCurrentPosition();
-
- for( int i=0; i<segCount; i++ )
- {
- int start = startCount[i];
- int end = endCount[i];
- int delta = idDelta[i];
- int rangeOffset = idRangeOffset[i];
- if( start != 65535 && end != 65535 )
- {
- for( int j=start; j<=end; j++ )
- {
- if( rangeOffset == 0 )
- {
- int glyphid = (j+delta)%65536;
- tmpGlyphToChar.put(glyphid,j);
- characterCodeToGlyphId.put(j, glyphid);
- }
- else
- {
- long glyphOffset = currentPosition +
- ((rangeOffset/2) + //idRangeOffset[i]/2
- (j-start) + //(c - startCount[i])
- (i-segCount))*2; //&idRangeOffset[i]);
- data.seek( glyphOffset );
- int glyphIndex = data.readUnsignedShort();
- if( glyphIndex != 0 )
- {
- glyphIndex += delta;
- glyphIndex = glyphIndex % 65536;
- if(!tmpGlyphToChar.containsKey(glyphIndex))
- {
- tmpGlyphToChar.put(glyphIndex,j);
- characterCodeToGlyphId.put(j, glyphIndex);
- }
- }
- }
- }
- }
- }
-
- /* this is the final result
- * key=glyphId, value is character codes
- * Create an array that contains MAX(GlyphIds) element and fill this array with the .notdef character
- */
- glyphIdToCharacterCode = new int[Collections.max(tmpGlyphToChar.keySet())+1];
- Arrays.fill(glyphIdToCharacterCode, 0);
- for (Entry<Integer, Integer> entry : tmpGlyphToChar.entrySet()) {
- // link the glyphId with the right character code
- glyphIdToCharacterCode[entry.getKey()] = entry.getValue();
- }
- }
-
- /**
- * Read a format 2 subtable.
- * @param ttf the TrueTypeFont instance holding the parsed data.
- * @param data the data stream of the to be parsed ttf font
- * @param numGlyphs number of glyphs to be read
- * @throws IOException If there is an error parsing the true type font.
- */
- protected void processSubtype2( TrueTypeFont ttf, TTFDataStream data, int numGlyphs )
- throws IOException {
- 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));
- }
-
- // ---- 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);
- }
- }
- }
-
- /**
- * Initialize the CMapEntry when it is a subtype 0
- *
- * @param ttf
- * @param data
- * @throws IOException
- */
- protected void processSubtype0( TrueTypeFont ttf, TTFDataStream data )
- throws IOException {
- byte[] glyphMapping = data.read( 256 );
- glyphIdToCharacterCode = new int[256];
- for( int i=0;i < glyphMapping.length; i++ )
- {
- int glyphIndex = (glyphMapping[i]+256)%256;
- glyphIdToCharacterCode[glyphIndex]=i;
- characterCodeToGlyphId.put(i, glyphIndex);
- }
- }
-
- /**
- * @return Returns the glyphIdToCharacterCode.
- */
- public int[] getGlyphIdToCharacterCode()
- {
- return glyphIdToCharacterCode;
- }
- /**
- * @param glyphIdToCharacterCodeValue The glyphIdToCharacterCode to set.
- */
- public void setGlyphIdToCharacterCode(int[] glyphIdToCharacterCodeValue)
- {
- this.glyphIdToCharacterCode = glyphIdToCharacterCodeValue;
- }
-
- /**
- * @return Returns the platformEncodingId.
- */
- public int getPlatformEncodingId()
- {
- return platformEncodingId;
- }
- /**
- * @param platformEncodingIdValue The platformEncodingId to set.
- */
- public void setPlatformEncodingId(int platformEncodingIdValue)
- {
- this.platformEncodingId = platformEncodingIdValue;
- }
- /**
- * @return Returns the platformId.
- */
- public int getPlatformId()
- {
- return platformId;
- }
- /**
- * @param platformIdValue The platformId to set.
- */
- public void setPlatformId(int platformIdValue)
- {
- this.platformId = platformIdValue;
- }
-
- /**
- * Returns the GlyphId linked with the given character code.
- * @param characterCode
- * @return glyphId
- */
- public int getGlyphId(int characterCode) {
- if (this.characterCodeToGlyphId.containsKey(characterCode))
- {
- return this.characterCodeToGlyphId.get(characterCode);
- }
- else
- {
- 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;
- }
- }
+ private int platformId;
+ private int platformEncodingId;
+ private long subTableOffset;
+ private int[] glyphIdToCharacterCode;
+ private Map<Integer, Integer> characterCodeToGlyphId = new HashMap<Integer, Integer>();
+
+ /**
+ * This will read the required data from the stream.
+ *
+ * @param ttf The font that is being read.
+ * @param data The stream to read the data from.
+ * @throws IOException If there is an error reading the data.
+ */
+ public void initData(TrueTypeFont ttf, TTFDataStream data) throws IOException
+ {
+ platformId = data.readUnsignedShort();
+ platformEncodingId = data.readUnsignedShort();
+ subTableOffset = data.readUnsignedInt();
+ }
+
+ /**
+ * This will read the required data from the stream.
+ *
+ * @param ttf The font that is being read.
+ * @param data The stream to read the data from.
+ * @throws IOException If there is an error reading the data.
+ */
+ public void initSubtable(TrueTypeFont ttf, TTFDataStream data) throws IOException
+ {
+ data.seek(ttf.getCMAP().getOffset() + subTableOffset);
+ int subtableFormat = data.readUnsignedShort();
+ long length;
+ long version;
+ int numGlyphs;
+ if (subtableFormat < 8)
+ {
+ length = data.readUnsignedShort();
+ version = data.readUnsignedShort();
+ numGlyphs = ttf.getMaximumProfile().getNumGlyphs();
+ }
+ else
+ {
+ // read an other UnsignedShort to read a Fixed32
+ data.readUnsignedShort();
+ length = data.readUnsignedInt();
+ version = data.readUnsignedInt();
+ numGlyphs = ttf.getMaximumProfile().getNumGlyphs();
+ }
+
+ switch (subtableFormat)
+ {
+ case 0:
+ processSubtype0(ttf, data);
+ break;
+ case 2:
+ processSubtype2(ttf, data, numGlyphs);
+ break;
+ case 4:
+ processSubtype4(ttf, data, numGlyphs);
+ break;
+ case 6:
+ processSubtype6(ttf, data, numGlyphs);
+ break;
+ case 8:
+ processSubtype8(ttf, data, numGlyphs);
+ break;
+ case 10:
+ processSubtype10(ttf, data, numGlyphs);
+ break;
+ case 12:
+ processSubtype12(ttf, data, numGlyphs);
+ break;
+ case 13:
+ processSubtype13(ttf, data, numGlyphs);
+ break;
+ case 14:
+ processSubtype14(ttf, data, numGlyphs);
+ break;
+ default:
+ throw new IOException("Unknown cmap format:" + subtableFormat);
+ }
+ }
+
+ /**
+ * Reads a format 8 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype8(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ // --- is32 is a 65536 BITS array ( = 8192 BYTES)
+ int[] is32 = data.readUnsignedByteArray(8192);
+ long nbGroups = data.readUnsignedInt();
+
+ // --- nbGroups shouldn't be greater than 65536
+ if (nbGroups > 65536)
+ {
+ throw new IOException("CMap ( Subtype8 ) is invalid");
+ }
+
+ glyphIdToCharacterCode = new int[numGlyphs];
+ // -- Read all sub header
+ for (long i = 0; i <= nbGroups; ++i)
+ {
+ long firstCode = data.readUnsignedInt();
+ long endCode = data.readUnsignedInt();
+ long startGlyph = data.readUnsignedInt();
+
+ // -- process simple validation
+ if (firstCode > endCode || 0 > firstCode)
+ {
+ throw new IOException("Range invalid");
+ }
+
+ for (long j = firstCode; j <= endCode; ++j)
+ {
+ // -- Convert the Character code in decimal
+ if (j > Integer.MAX_VALUE)
+ {
+ throw new IOException("[Sub Format 8] Invalid Character code");
+ }
+
+ int currentCharCode;
+ if ((is32[(int) j / 8] & (1 << ((int) j % 8))) == 0)
+ {
+ currentCharCode = (int) j;
+ }
+ else
+ {
+ // the character code uses a 32bits format
+ // convert it in decimal : see http://www.unicode.org/faq//utf_bom.html#utf16-4
+ long lead = LEAD_OFFSET + (j >> 10);
+ long trail = 0xDC00 + (j & 0x3FF);
+
+ long codepoint = (lead << 10) + trail + SURROGATE_OFFSET;
+ if (codepoint > Integer.MAX_VALUE)
+ {
+ throw new IOException("[Sub Format 8] Invalid Character code");
+ }
+ currentCharCode = (int) codepoint;
+ }
+
+ long glyphIndex = startGlyph + (j - firstCode);
+ if (glyphIndex > numGlyphs || glyphIndex > Integer.MAX_VALUE)
+ {
+ throw new IOException("CMap contains an invalid glyph index");
+ }
+
+ glyphIdToCharacterCode[(int) glyphIndex] = currentCharCode;
+ characterCodeToGlyphId.put(currentCharCode, (int) glyphIndex);
+ }
+ }
+ }
+
+ /**
+ * Reads a format 10 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype10(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ long startCode = data.readUnsignedInt();
+ long numChars = data.readUnsignedInt();
+ if (numChars > Integer.MAX_VALUE)
+ {
+ throw new IOException("Invalid number of Characters");
+ }
+
+ if (startCode < 0 || startCode > 0x0010FFFF || (startCode + numChars) > 0x0010FFFF
+ || ((startCode + numChars) >= 0x0000D800 && (startCode + numChars) <= 0x0000DFFF))
+ {
+ throw new IOException("Invalid Characters codes");
+
+ }
+ }
+
+ /**
+ * Reads a format 12 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype12(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ long nbGroups = data.readUnsignedInt();
+ glyphIdToCharacterCode = new int[numGlyphs];
+ for (long i = 0; i <= nbGroups; ++i)
+ {
+ long firstCode = data.readUnsignedInt();
+ long endCode = data.readUnsignedInt();
+ long startGlyph = data.readUnsignedInt();
+
+ if (firstCode < 0 || firstCode > 0x0010FFFF || (firstCode >= 0x0000D800 && firstCode <= 0x0000DFFF))
+ {
+ throw new IOException("Invalid Characters codes");
+ }
+
+ if ((endCode > 0 && endCode < firstCode) || endCode > 0x0010FFFF
+ || (endCode >= 0x0000D800 && endCode <= 0x0000DFFF))
+ {
+ throw new IOException("Invalid Characters codes");
+ }
+
+ for (long j = 0; j <= (endCode - firstCode); ++j)
+ {
+
+ if ((firstCode + j) > Integer.MAX_VALUE)
+ {
+ throw new IOException("Character Code greater than Integer.MAX_VALUE");
+ }
+
+ long glyphIndex = (startGlyph + j);
+ if (glyphIndex > numGlyphs || glyphIndex > Integer.MAX_VALUE)
+ {
+ throw new IOException("CMap contains an invalid glyph index");
+ }
+ glyphIdToCharacterCode[(int) glyphIndex] = (int) (firstCode + j);
+ characterCodeToGlyphId.put((int) (firstCode + j), (int) glyphIndex);
+ }
+ }
+ }
+
+ /**
+ * Reads a format 13 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype13(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ long nbGroups = data.readUnsignedInt();
+ for (long i = 0; i <= nbGroups; ++i)
+ {
+ long firstCode = data.readUnsignedInt();
+ long endCode = data.readUnsignedInt();
+ long glyphId = data.readUnsignedInt();
+
+ if (glyphId > numGlyphs)
+ {
+ throw new IOException("CMap contains an invalid glyph index");
+ }
+
+ if (firstCode < 0 || firstCode > 0x0010FFFF || (firstCode >= 0x0000D800 && firstCode <= 0x0000DFFF))
+ {
+ throw new IOException("Invalid Characters codes");
+ }
+
+ if ((endCode > 0 && endCode < firstCode) || endCode > 0x0010FFFF
+ || (endCode >= 0x0000D800 && endCode <= 0x0000DFFF))
+ {
+ throw new IOException("Invalid Characters codes");
+ }
+
+ for (long j = 0; j <= (endCode - firstCode); ++j)
+ {
+
+ if ((firstCode + j) > Integer.MAX_VALUE)
+ {
+ throw new IOException("Character Code greater than Integer.MAX_VALUE");
+ }
+ glyphIdToCharacterCode[(int) glyphId] = (int) (firstCode + j);
+ characterCodeToGlyphId.put((int) (firstCode + j), (int) glyphId);
+ }
+ }
+ }
+
+ /**
+ * Reads a format 14 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype14(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ throw new IOException("CMap subtype 14 not yet implemented");
+ }
+
+ /**
+ * Reads a format 6 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype6(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ int firstCode = data.readUnsignedShort();
+ int entryCount = data.readUnsignedShort();
+ glyphIdToCharacterCode = new int[numGlyphs];
+ int[] glyphIdArray = data.readUnsignedShortArray(entryCount);
+ for (int i = 0; i < entryCount; i++)
+ {
+ glyphIdToCharacterCode[glyphIdArray[i]] = firstCode + i;
+ characterCodeToGlyphId.put((firstCode + i), glyphIdArray[i]);
+ }
+ }
+
+ /**
+ * Reads a format 4 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype4(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ int segCountX2 = data.readUnsignedShort();
+ int segCount = segCountX2 / 2;
+ int searchRange = data.readUnsignedShort();
+ int entrySelector = data.readUnsignedShort();
+ int rangeShift = data.readUnsignedShort();
+ int[] endCount = data.readUnsignedShortArray(segCount);
+ int reservedPad = data.readUnsignedShort();
+ int[] startCount = data.readUnsignedShortArray(segCount);
+ int[] idDelta = data.readUnsignedShortArray(segCount);
+ int[] idRangeOffset = data.readUnsignedShortArray(segCount);
+
+ Map<Integer, Integer> tmpGlyphToChar = new HashMap<Integer, Integer>();
+
+ long currentPosition = data.getCurrentPosition();
+
+ for (int i = 0; i < segCount; i++)
+ {
+ int start = startCount[i];
+ int end = endCount[i];
+ int delta = idDelta[i];
+ int rangeOffset = idRangeOffset[i];
+ if (start != 65535 && end != 65535)
+ {
+ for (int j = start; j <= end; j++)
+ {
+ if (rangeOffset == 0)
+ {
+ int glyphid = (j + delta) % 65536;
+ tmpGlyphToChar.put(glyphid, j);
+ characterCodeToGlyphId.put(j, glyphid);
+ }
+ else
+ {
+ long glyphOffset = currentPosition + ((rangeOffset / 2) +
+ (j - start) +
+ (i - segCount)) * 2;
+ data.seek(glyphOffset);
+ int glyphIndex = data.readUnsignedShort();
+ if (glyphIndex != 0)
+ {
+ glyphIndex += delta;
+ glyphIndex = glyphIndex % 65536;
+ if (!tmpGlyphToChar.containsKey(glyphIndex))
+ {
+ tmpGlyphToChar.put(glyphIndex, j);
+ characterCodeToGlyphId.put(j, glyphIndex);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * this is the final result key=glyphId, value is character codes Create an array that contains MAX(GlyphIds)
+ * element and fill this array with the .notdef character
+ */
+ glyphIdToCharacterCode = new int[Collections.max(tmpGlyphToChar.keySet()) + 1];
+ Arrays.fill(glyphIdToCharacterCode, 0);
+ for (Entry<Integer, Integer> entry : tmpGlyphToChar.entrySet())
+ {
+ // link the glyphId with the right character code
+ glyphIdToCharacterCode[entry.getKey()] = entry.getValue();
+ }
+ }
+
+ /**
+ * Read a format 2 subtable.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @param numGlyphs number of glyphs to be read
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype2(TrueTypeFont ttf, TTFDataStream data, int numGlyphs) throws IOException
+ {
+ 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));
+ }
+
+ // ---- 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() - (maxSubHeaderIndex + 1 - i - 1) * 8 - 2;
+ 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();
+ int idRangeOffset = sh.getIdRangeOffset();
+ int idDelta = sh.getIdDelta();
+ int entryCount = sh.getEntryCount();
+ data.seek(startGlyphIndexOffset + idRangeOffset);
+ for (int j = 0; j < entryCount; ++j)
+ {
+ // ---- compute the Character Code
+ int charCode = i;
+ 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
+ int p = data.readUnsignedShort();
+ // ---- compute the glyphIndex
+ if (p > 0)
+ {
+ p = (p + idDelta) % 65536;
+ }
+ glyphIdToCharacterCode[p] = charCode;
+ characterCodeToGlyphId.put(charCode, p);
+ }
+ }
+ }
+
+ /**
+ * Initialize the CMapEntry when it is a subtype 0.
+ *
+ * @param ttf the TrueTypeFont instance holding the parsed data.
+ * @param data the data stream of the to be parsed ttf font
+ * @throws IOException If there is an error parsing the true type font.
+ */
+ protected void processSubtype0(TrueTypeFont ttf, TTFDataStream data) throws IOException
+ {
+ byte[] glyphMapping = data.read(256);
+ glyphIdToCharacterCode = new int[256];
+ for (int i = 0; i < glyphMapping.length; i++)
+ {
+ int glyphIndex = (glyphMapping[i] + 256) % 256;
+ glyphIdToCharacterCode[glyphIndex] = i;
+ characterCodeToGlyphId.put(i, glyphIndex);
+ }
+ }
+
+ /**
+ * @return Returns the glyphIdToCharacterCode.
+ */
+ public int[] getGlyphIdToCharacterCode()
+ {
+ return glyphIdToCharacterCode;
+ }
+
+ /**
+ * @param glyphIdToCharacterCodeValue The glyphIdToCharacterCode to set.
+ */
+ public void setGlyphIdToCharacterCode(int[] glyphIdToCharacterCodeValue)
+ {
+ glyphIdToCharacterCode = glyphIdToCharacterCodeValue;
+ }
+
+ /**
+ * @return Returns the platformEncodingId.
+ */
+ public int getPlatformEncodingId()
+ {
+ return platformEncodingId;
+ }
+
+ /**
+ * @param platformEncodingIdValue The platformEncodingId to set.
+ */
+ public void setPlatformEncodingId(int platformEncodingIdValue)
+ {
+ platformEncodingId = platformEncodingIdValue;
+ }
+
+ /**
+ * @return Returns the platformId.
+ */
+ public int getPlatformId()
+ {
+ return platformId;
+ }
+
+ /**
+ * @param platformIdValue The platformId to set.
+ */
+ public void setPlatformId(int platformIdValue)
+ {
+ platformId = platformIdValue;
+ }
+
+ /**
+ * Returns the GlyphId linked with the given character code.
+ *
+ * @param characterCode the given character code to be mapped
+ * @return glyphId the corresponding glyph id for the given character code
+ */
+ public int getGlyphId(int characterCode)
+ {
+ if (characterCodeToGlyphId.containsKey(characterCode))
+ {
+ return characterCodeToGlyphId.get(characterCode);
+ }
+ else
+ {
+ 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 firstCodeValue, int entryCountValue, short idDeltaValue, int idRangeOffsetValue)
+ {
+ firstCode = firstCodeValue;
+ entryCount = entryCountValue;
+ idDelta = idDeltaValue;
+ idRangeOffset = idRangeOffsetValue;
+ }
+
+ /**
+ * @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/CMAPTable.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPTable.java?rev=1506164&r1=1506163&r2=1506164&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPTable.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/CMAPTable.java Tue Jul 23 17:13:11 2013
@@ -19,10 +19,10 @@ package org.apache.fontbox.ttf;
import java.io.IOException;
/**
- * A table in a true type font.
+ * The CMAP table of a true type font.
*
* @author Ben Litchfield (ben@benlitchfield.com)
- * @version $Revision: 1.1 $
+ *
*/
public class CMAPTable extends TTFTable
{
@@ -30,12 +30,22 @@ public class CMAPTable extends TTFTable
* A tag used to identify this table.
*/
public static final String TAG = "cmap";
-
+
+ /**
+ * A constant for the platform.
+ */
+ public static final int PLATFORM_MISC = 0;
+
+ /**
+ * A constant for the platform.
+ */
+ public static final int PLATFORM_MACINTOSH = 1;
+
/**
* A constant for the platform.
*/
public static final int PLATFORM_WINDOWS = 3;
-
+
/**
* An encoding constant.
*/
@@ -64,9 +74,9 @@ public class CMAPTable extends TTFTable
* An encoding constant.
*/
public static final int ENCODING_JOHAB = 6;
-
+
private CMAPEncodingEntry[] cmaps;
-
+
/**
* This will read the required data from the stream.
*
@@ -74,23 +84,24 @@ public class CMAPTable extends TTFTable
* @param data The stream to read the data from.
* @throws IOException If there is an error reading the data.
*/
- public void initData( TrueTypeFont ttf, TTFDataStream data ) throws IOException
+ public void initData(TrueTypeFont ttf, TTFDataStream data) throws IOException
{
int version = data.readUnsignedShort();
int numberOfTables = data.readUnsignedShort();
- cmaps = new CMAPEncodingEntry[ numberOfTables ];
- for( int i=0; i< numberOfTables; i++ )
+ cmaps = new CMAPEncodingEntry[numberOfTables];
+ for (int i = 0; i < numberOfTables; i++)
{
CMAPEncodingEntry cmap = new CMAPEncodingEntry();
- cmap.initData( ttf, data );
- cmaps[i]=cmap;
+ cmap.initData(ttf, data);
+ cmaps[i] = cmap;
}
- for( int i=0; i< numberOfTables; i++ )
+ for (int i = 0; i < numberOfTables; i++)
{
- cmaps[i].initSubtable( ttf, data );
+ cmaps[i].initSubtable(ttf, data);
}
-
+
}
+
/**
* @return Returns the cmaps.
*/
@@ -98,11 +109,12 @@ public class CMAPTable extends TTFTable
{
return cmaps;
}
+
/**
* @param cmapsValue The cmaps to set.
*/
public void setCmaps(CMAPEncodingEntry[] cmapsValue)
{
- this.cmaps = cmapsValue;
+ cmaps = cmapsValue;
}
}
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=1506164&r1=1506163&r2=1506164&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 Tue Jul 23 17:13:11 2013
@@ -17,6 +17,7 @@
package org.apache.fontbox.ttf;
import java.io.IOException;
+
/**
* A true type font file parser.
*
@@ -24,15 +25,17 @@ import java.io.IOException;
* @version $Revision: 1.2 $
*/
public class TTFParser extends AbstractTTFParser
-{
- public TTFParser() {
+{
+ public TTFParser()
+ {
super(false);
}
-
- public TTFParser(boolean isEmbedded) {
+
+ public TTFParser(boolean isEmbedded)
+ {
super(isEmbedded);
}
-
+
/**
* A simple command line program to test parsing of a TTF file. <br/>
* usage: java org.pdfbox.ttf.TTFParser <ttf-file>
@@ -41,29 +44,30 @@ public class TTFParser extends AbstractT
*
* @throws IOException If there is an error while parsing the font file.
*/
- public static void main( String[] args ) throws IOException
+ public static void main(String[] args) throws IOException
{
- if( args.length != 1 )
+ if (args.length != 1)
{
- System.err.println( "usage: java org.pdfbox.ttf.TTFParser <ttf-file>" );
- System.exit( -1 );
+ System.err.println("usage: java org.pdfbox.ttf.TTFParser <ttf-file>");
+ System.exit(-1);
}
TTFParser parser = new TTFParser();
- TrueTypeFont font = parser.parseTTF( args[0] );
- System.out.println( "Font:" + font );
+ TrueTypeFont font = parser.parseTTF(args[0]);
+ System.out.println("Font:" + font);
}
-
+
/**
* {@inheritDoc}
*/
- protected void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOException
+ protected void parseTables(TrueTypeFont font, TTFDataStream raf) throws IOException
{
super.parseTables(font, raf);
-
+
// check others mandatory tables
- if ( font.getCMAP() == null ){
+ if (!isEmbedded && font.getCMAP() == null)
+ {
throw new IOException("cmap is mandatory");
}
}
-}
\ No newline at end of file
+}