//--------------------------------------------------------------------// // 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); } }