//--------------------------------------------------------------------// // M e t h o d // // w r i t e C h a r // //--------------------------------------------------------------------// // // // Write PCL format character data: // // // // <esc>*c#E Character Code: // // # = decimal character code // // <esc>(s#W[data] Character Descriptor / Data // // # = number of bytes of data // // [data] = font character data // // // // Note that the function may be called recursively, if a glyph is // // composite (i.e. made up of two or more components). // // // //--------------------------------------------------------------------// private void writeChar(UInt16 charCode, UInt16 codepoint, UInt16 glyphId, UInt16 depth, UInt16 maxGlyphId) { UInt16 glyphWidth = 0, glyphHeight = 0, charBlockSize = 0, charDataSize = 0; Int16 glyphLSB = 0, glyphTSB = 0; UInt32 glyphOffset = 0, glyphLength = 0; Boolean glyphComposite = false; Byte checksumMod256; Byte[] charHddr = new Byte[cSizeCharHddr]; Byte[] charGlyphHddr = new Byte[cSizeCharGlyphHddr]; Byte[] charTrail = new Byte[cSizeCharTrail]; Byte[] glyphData = null; //----------------------------------------------------------------// // // // Mark glyph as used. // // These markers are checked for composite sub-glyphs. // // // //----------------------------------------------------------------// _ttfHandler.glyphReferencedMark(glyphId); //----------------------------------------------------------------// // // // Get glyph details: // // advance width. // // left-side bearing. // // offset and length of the glyph data in the TTF file. // // // //----------------------------------------------------------------// _ttfHandler.getGlyphData(glyphId, ref glyphWidth, ref glyphHeight, // not used here ref glyphLSB, ref glyphTSB, // not used here ref glyphOffset, ref glyphLength, ref glyphComposite); //----------------------------------------------------------------// // // // Log character details. // // // //----------------------------------------------------------------// ToolSoftFontGenLog.logCharDetails(_tableLog, false, glyphComposite, charCode, codepoint, glyphId, depth, glyphWidth, glyphHeight, glyphLSB, glyphTSB, glyphOffset, glyphLength); //----------------------------------------------------------------// // // // Calculate total size of header. // // // // Write PCL 'Character Code' escape sequence. // // Write PCL 'Character Definition' escape sequence. // // // //----------------------------------------------------------------// charBlockSize = (UInt16)(cSizeCharHddr + cSizeCharGlyphHddr + glyphLength + cSizeCharTrail); PCLWriter.charDownloadCode(_binWriter, charCode); PCLWriter.charDownloadDesc(_binWriter, charBlockSize); //----------------------------------------------------------------// // // // Write Format 15 header. // // This character format is used with both Format 15 and // // Format 16 font headers. // // // //----------------------------------------------------------------// charHddr[0] = 15; // Format = 15 charHddr[1] = 0; // Continuation = false charHddr[2] = 2; // Descriptor size charHddr[3] = 15; // Class = 15 _baseHandler.writeBuffer(cSizeCharHddr, charHddr); //----------------------------------------------------------------// // // // Write glyph header. // // This counts towards the checksum recorded in the trailer. // // // //----------------------------------------------------------------// checksumMod256 = 0; charDataSize = (UInt16)(cSizeCharGlyphHddr + glyphLength); charGlyphHddr[0] = msByte(charDataSize); charGlyphHddr[1] = lsByte(charDataSize); charGlyphHddr[2] = msByte(glyphId); charGlyphHddr[3] = lsByte(glyphId); _baseHandler.writeCharFragment(cSizeCharGlyphHddr, charGlyphHddr, ref checksumMod256); //----------------------------------------------------------------// // // // Write TrueType glyph data (copied from TrueType font file). // // The data is read into a dynamically allocated buffer because: // // - This avoids the complication of having a fixed-length // // buffer and a loop to read the data in chunks. // // - Not having a static buffer allows the function to be // // called recursively. // // // //----------------------------------------------------------------// if (glyphLength > 0) { Boolean flagOK = true; glyphData = new Byte[glyphLength]; flagOK = _ttfHandler.readByteArray((Int32)glyphOffset, (Int32)glyphLength, ref glyphData); // TODO: what if flagOK = true (i.e. read fails? _baseHandler.writeCharFragment((Int32)glyphLength, glyphData, ref checksumMod256); } //----------------------------------------------------------------// // // // Write trailer (Reserved byte and Checksum byte). // // // //----------------------------------------------------------------// checksumMod256 = (Byte)((256 - checksumMod256) % 256); charTrail[0] = 0; // Reserved byte charTrail[1] = checksumMod256; // Checksum byte _baseHandler.writeBuffer(cSizeCharTrail, charTrail); //----------------------------------------------------------------// // // // Handler composite glyphs. // // // //----------------------------------------------------------------// if (glyphComposite) { // if we move this to TTFHandler, do the maxGlyphId check there instead Int32 indBuf; UInt16 glyphCompFlags, glyphCompId; indBuf = 10; // point to first set of component data // do { glyphCompFlags = (UInt16)((glyphData[indBuf] << 8) + glyphData[indBuf + 1]); glyphCompId = (UInt16)((glyphData[indBuf + 2] << 8) + glyphData[indBuf + 3]); if (glyphCompId > maxGlyphId) { // flagOK = false; ToolSoftFontGenLog.logError( _tableLog, MessageBoxImage.Error, "Composite glyph identifier " + glyphCompId + " > maximum of " + maxGlyphId); } else { if (_ttfHandler.glyphReferencedCheck(glyphCompId)) { ToolSoftFontGenLog.logCharDetails( _tableLog, true, _ttfHandler.glyphCompositeCheck(glyphCompId), 0, 0, glyphCompId, depth, 0, 0, 0, 0, 0, 0); } else { // flagOK = writeChar(0xffff, 0, glyphCompId, (UInt16)(depth + 1), maxGlyphId); } } // if flagOK { indBuf += 4; if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_ARG_1_AND_2_ARE_WORDS) != 0) { indBuf += 4; } else { indBuf += 2; } if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_A_TWO_BY_TWO) != 0) { indBuf += 8; } else if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_AN_X_AND_Y_SCALE) != 0) { indBuf += 4; } else if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_A_SCALE) != 0) { indBuf += 2; } } } while ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_MORE_COMPONENTS) != 0); } }
//--------------------------------------------------------------------// // M e t h o d // // w r i t e C h a r // //--------------------------------------------------------------------// // // // Write PCL XL format character: // // // // ReadChar operator // // Embedded Data header // // character data // // // // Note that the function may be called recursively, if a glyph is // // composite (i.e. made up of two or more components). // // // // Unbound fonts: write Class 0 characters; these rely on the GT // // GT segment in the font header // // containing the 'hhea' and 'htmx' // // tables. // // Bound fonts: write Class 1 characters, which include advance // // width and LSB in each character // // header. // // // //--------------------------------------------------------------------// private void writeChar(Int32 charClass, UInt16 charCode, UInt16 codepoint, UInt16 glyphId, UInt16 depth, UInt16 maxGlyphId) { UInt16 glyphWidth = 0, glyphHeight = 0, charDataSize = 0, charSize, hddrSize; Int16 glyphLSB = 0, glyphTSB = 0; UInt32 glyphOffset = 0, glyphLength = 0; Boolean glyphComposite = false; Byte checksumMod256 = 0; Byte[] glyphData = null; Byte[] charHddr; if (charClass == 1) { hddrSize = cSizeCharHddrClass1; } else if (charClass == 2) { hddrSize = cSizeCharHddrClass2; } else { hddrSize = cSizeCharHddrClass0; } charHddr = new Byte[hddrSize]; //----------------------------------------------------------------// // // // Mark glyph as used. // // These markers are checked for composite sub-glyphs. // // // //----------------------------------------------------------------// _ttfHandler.glyphReferencedMark(glyphId); //----------------------------------------------------------------// // // // Get glyph details: // // advance width. // // left-side bearing. // // offset and length of the glyph data in the TTF file. // // // //----------------------------------------------------------------// _ttfHandler.getGlyphData(glyphId, ref glyphWidth, ref glyphHeight, // not used ref glyphLSB, ref glyphTSB, ref glyphOffset, ref glyphLength, ref glyphComposite); //----------------------------------------------------------------// // // // Log character details. // // // //----------------------------------------------------------------// ToolSoftFontGenLog.logCharDetails(_tableLog, false, glyphComposite, charCode, codepoint, glyphId, depth, glyphWidth, glyphHeight, glyphLSB, glyphTSB, glyphOffset, glyphLength); //----------------------------------------------------------------// // // // Calculate total size of header. // // // // Write ReadChar operator and associated Attribute List. // // Write Embedded Data Introduction sequence. // // // //----------------------------------------------------------------// charDataSize = (UInt16)(hddrSize + glyphLength); charSize = (UInt16)(charDataSize - 2); PCLXLWriter.fontCharRead(_binWriter, false, charCode, charDataSize); PCLXLWriter.embedDataIntro(_binWriter, false, charDataSize); if (charClass == 0) { //------------------------------------------------------------// // // // Write Format 1 Class 0 header. // // // //------------------------------------------------------------// charHddr [0] = 1; // Format charHddr [1] = 0; // Class charHddr [2] = msByte(charSize); // CharSize MSB charHddr [3] = lsByte(charSize); // CharSize LSB charHddr [4] = msByte(glyphId); // Glyph Id MSB charHddr [5] = lsByte(glyphId); // Glyph Id LSB } else if (charClass == 1) { //------------------------------------------------------------// // // // Write Format 1 Class 1 header. // // // //------------------------------------------------------------// charHddr [0] = 1; // Format charHddr [1] = 1; // Class charHddr [2] = msByte(charSize); // CharSize MSB charHddr [3] = lsByte(charSize); // CharSize LSB charHddr [4] = msByte((UInt16)glyphLSB); // Glyph Left Side Bearing charHddr [5] = lsByte((UInt16)glyphLSB); // Glyph Left Side Bearing charHddr [6] = msByte(glyphWidth); // Glyph Width MSB charHddr [7] = lsByte(glyphWidth); // Glyph Width LSB charHddr [8] = msByte(glyphId); // Glyph Id MSB charHddr [9] = lsByte(glyphId); // Glyph Id LSB } else // charClass == 2 { //------------------------------------------------------------// // // // Write Format 1 Class 2 header. // // // //------------------------------------------------------------// charHddr [0] = 1; // Format charHddr [1] = 2; // Class charHddr [2] = msByte(charSize); // CharSize MSB charHddr [3] = lsByte(charSize); // CharSize LSB charHddr [4] = msByte((UInt16)glyphLSB); // Glyph Left Side Bearing charHddr [5] = lsByte((UInt16)glyphLSB); // Glyph Left Side Bearing charHddr [6] = msByte(glyphWidth); // Glyph Width MSB charHddr [7] = lsByte(glyphWidth); // Glyph Width LSB charHddr [8] = msByte((UInt16)glyphTSB); // Glyph Top Side Bearing charHddr [9] = lsByte((UInt16)glyphTSB); // Glyph Top Side Bearing charHddr [10] = msByte(glyphId); // Glyph Id MSB charHddr [11] = lsByte(glyphId); // Glyph Id LSB } _baseHandler.writeBuffer(hddrSize, charHddr); //----------------------------------------------------------------// // // // Write TrueType glyph data (copied from TrueType font file). // // The data is read into a dynamically allocated buffer because: // // - This avoids the complication of having a fixed-length // // buffer and a loop to read the data in chunks. // // - Not having a static buffer allows the function to be // // called recursively. // // // //----------------------------------------------------------------// if (glyphLength > 0) { Boolean flagOK = true; glyphData = new Byte[glyphLength]; flagOK = _ttfHandler.readByteArray((Int32)glyphOffset, (Int32)glyphLength, ref glyphData); // TODO: what if flagOK = true (i.e. read fails? _baseHandler.writeCharFragment((Int32)glyphLength, glyphData, ref checksumMod256); } //----------------------------------------------------------------// // // // Handler composite glyphs. // // // //----------------------------------------------------------------// if (glyphComposite) { // if we move this to TTFHandler, do the maxGlyphId check there instead Int32 indBuf; UInt16 glyphCompFlags, glyphCompId; indBuf = 10; // point to first set of component data // do { glyphCompFlags = (UInt16)((glyphData[indBuf] << 8) + glyphData[indBuf + 1]); glyphCompId = (UInt16)((glyphData[indBuf + 2] << 8) + glyphData[indBuf + 3]); if (glyphCompId > maxGlyphId) { // flagOK = false; ToolSoftFontGenLog.logError( _tableLog, MessageBoxImage.Error, "Composite glyph identifier " + glyphCompId + " > maximum of " + maxGlyphId); } else { if (_ttfHandler.glyphReferencedCheck(glyphCompId)) { ToolSoftFontGenLog.logCharDetails( _tableLog, true, _ttfHandler.glyphCompositeCheck(glyphCompId), 0, 0, glyphCompId, depth, 0, 0, 0, 0, 0, 0); } else { // flagOK = writeChar(charClass, 0xffff, 0, glyphCompId, (UInt16)(depth + 1), maxGlyphId); } } // if flagOK { indBuf += 4; if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_ARG_1_AND_2_ARE_WORDS) != 0) { indBuf += 4; } else { indBuf += 2; } if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_A_TWO_BY_TWO) != 0) { indBuf += 8; } else if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_AN_X_AND_Y_SCALE) != 0) { indBuf += 4; } else if ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_WE_HAVE_A_SCALE) != 0) { indBuf += 2; } } } while ((glyphCompFlags & ToolSoftFontGenTTF.mask_glyf_compFlag_MORE_COMPONENTS) != 0); } }