//////////////////////////////////////////////////////////////////// // build new cmap table //////////////////////////////////////////////////////////////////// private void BuildCharMapTable() { // create a new cmap sub table cmapSubTbl NewSubTbl = new cmapSubTbl(cmapSubTbl.PlatformID, cmapSubTbl.EncodingID, 4); NewSubTbl.Language = cmapSubTbl.Language; NewSubTbl.SegCount = 2; NewSubTbl.SegArray = new cmapSeg[2]; NewSubTbl.GlyphArray = CharToGlyphArray; // test type of font if(cmapSubTbl.EncodingID != 0) // alphabetic font NewSubTbl.SegArray[0] = new cmapSeg(FirstChar, LastChar, 0, 2); else // symbolic font NewSubTbl.SegArray[0] = new cmapSeg(0xf000 + FirstChar, 0xf000 + LastChar, 0, 2); NewSubTbl.SegArray[1] = new cmapSeg(0xffff, 0xffff, 1, 0); // table size Int32 TblSize = 4 + 8 + 16 + 8 * NewSubTbl.SegCount + 2 * CharToGlyphArray.Length; Buffer = new Byte[TblSize]; BufPtr = 0; // table version number is 0 WriteUInt16BigEndian(0); // number of tables is 1 WriteUInt16BigEndian(1); // platform id WriteUInt16BigEndian(NewSubTbl.PlatformID); // encoding id WriteUInt16BigEndian(NewSubTbl.EncodingID); // offset WriteUInt32BigEndian(4 + 8); // format WriteUInt16BigEndian(NewSubTbl.Format); // table length WriteInt16BigEndian((16 + 8 * NewSubTbl.SegCount + 2 * CharToGlyphArray.Length)); // language WriteUInt16BigEndian(NewSubTbl.Language); // segment count times 2 WriteInt16BigEndian((NewSubTbl.SegCount * 2)); // search range WriteUInt16BigEndian(NewSubTbl.SearchRange); // entry selector WriteUInt16BigEndian(NewSubTbl.EntrySelector); // range shift WriteUInt16BigEndian(NewSubTbl.RangeShift); // end character for(Int32 Seg = 0; Seg < NewSubTbl.SegCount; Seg++) WriteUInt16BigEndian(NewSubTbl.SegArray[Seg].EndChar); // padding WriteUInt16BigEndian(0); // start character for(Int32 Seg = 0; Seg < NewSubTbl.SegCount; Seg++) WriteUInt16BigEndian(NewSubTbl.SegArray[Seg].StartChar); // IDDelta for(Int32 Seg = 0; Seg < NewSubTbl.SegCount; Seg++) WriteInt16BigEndian(NewSubTbl.SegArray[Seg].IDDelta); // IDRangeOffset for(Int32 Seg = 0; Seg < NewSubTbl.SegCount; Seg++) WriteUInt16BigEndian((UInt16) (NewSubTbl.SegArray[Seg].IDRangeOffset * 2)); // char to glyph translation for(Int32 Glyph = 0; Glyph < NewSubTbl.GlyphArray.Length; Glyph++) WriteUInt16BigEndian(NewSubTbl.GlyphArray[Glyph]); // save TableRecordArray[(Int32) Tag.cmap].Data = Buffer; // calculate checksum TableRecordArray[(Int32) Tag.cmap].Checksum = TableChecksum(Buffer); // exit return; }
//////////////////////////////////////////////////////////////////// // Read "cmap" table //////////////////////////////////////////////////////////////////// private void GetcmapTable() { // set buffer for decoding Buffer = TableRecordArray[(Int32) Tag.cmap].Data; BufPtr = 0; // create cmap object if(ReadUInt16BigEndian() != 0) throw new ApplicationException("CMAP table version number is not zero"); Int32 NumberOfTables = ReadUInt16BigEndian(); cmapSubTbl[] SubTblArray = new cmapSubTbl[NumberOfTables]; // loop for tables for(Int32 Index = 0; Index < NumberOfTables; Index++) { cmapSubTbl SubTbl = new cmapSubTbl(); SubTblArray[Index] = SubTbl; SubTbl.PlatformID = ReadUInt16BigEndian(); SubTbl.EncodingID = ReadUInt16BigEndian(); SubTbl.Offset = ReadUInt32BigEndian(); // save buffer pointer Int32 SaveBufPtr = BufPtr; // set offset BufPtr = (Int32) SubTbl.Offset; // read format code SubTbl.Format = ReadUInt16BigEndian(); // process format 0 if(SubTbl.Format == 0) { SubTbl.Length = ReadUInt16BigEndian(); SubTbl.Language = ReadUInt16BigEndian(); SubTbl.GlyphArray = new UInt16[256]; for(Int32 Code = 0; Code < 256; Code++) SubTbl.GlyphArray[Code] = Buffer[BufPtr++]; } // process format 4 else if(SubTbl.Format == 4) { SubTbl.Length = ReadUInt16BigEndian(); SubTbl.Language = ReadUInt16BigEndian(); SubTbl.SegCount = (UInt16) (ReadUInt16BigEndian() / 2); BufPtr += 6; // skip search range, entry selector and range shift SubTbl.SegArray = new cmapSeg[SubTbl.SegCount]; for(Int32 Seg = 0; Seg < SubTbl.SegCount; Seg++) SubTbl.SegArray[Seg] = new cmapSeg(ReadUInt16BigEndian()); // EndChar ReadUInt16BigEndian(); // skip reserved padding for(Int32 Seg = 0; Seg < SubTbl.SegCount; Seg++) SubTbl.SegArray[Seg].StartChar = ReadUInt16BigEndian(); for(Int32 Seg = 0; Seg < SubTbl.SegCount; Seg++) SubTbl.SegArray[Seg].IDDelta = ReadInt16BigEndian(); for(Int32 Seg = 0; Seg < SubTbl.SegCount; Seg++) SubTbl.SegArray[Seg].IDRangeOffset = (UInt16) (ReadUInt16BigEndian() / 2); Int32 GlyphCount = (SubTbl.Length - 16 - 8 * SubTbl.SegCount) / 2; SubTbl.GlyphArray = new UInt16[GlyphCount]; for(Int32 Glyph = 0; Glyph < GlyphCount; Glyph++) SubTbl.GlyphArray[Glyph] = ReadUInt16BigEndian(); } // restore buffer pointer BufPtr = SaveBufPtr; } // sort table Array.Sort(SubTblArray); // select 'best' sub-table for character code to glyph code translation cmapSubTbl = SelectcmapSubTable(SubTblArray); // exit return; }
//////////////////////////////////////////////////////////////////// // Select best sub-table in "cmap" table //////////////////////////////////////////////////////////////////// private cmapSubTbl SelectcmapSubTable( cmapSubTbl[] SubTblArray ) { // search for platform ID = 3 Windows, encoding ID = 0 or 1 Unicode and format 4 cmapSubTbl SearchSubTbl = new cmapSubTbl(3, (UInt16) (SymbolicFont ? 0 : 1), 4); Int32 Index = Array.BinarySearch(SubTblArray, SearchSubTbl); if(Index >= 0) return(SubTblArray[Index]); // search for platform ID = 3 Windows, encoding ID = 0 or 1 Unicode and format 0 SearchSubTbl.Format = 0; Index = Array.BinarySearch(SubTblArray, SearchSubTbl); if(Index >= 0) return(SubTblArray[Index]); // not found throw new ApplicationException("Required cmap sub-table is missing"); }