public static BitmapSizeTable ReadBitmapSizeTable(BinaryReader reader) { //EBLC's BitmapSize Table (https://docs.microsoft.com/en-us/typography/opentype/spec/eblc) //Type Name Description //Offset32 indexSubTableArrayOffset Offset to IndexSubtableArray, from beginning of EBLC. //uint32 indexTablesSize Number of bytes in corresponding index subtables and array. //uint32 numberOfIndexSubTables There is an IndexSubtable for each range or format change. //uint32 colorRef Not used; set to 0. //SbitLineMetrics hori Line metrics for text rendered horizontally. //SbitLineMetrics vert Line metrics for text rendered vertically. //uint16 startGlyphIndex Lowest glyph index for this size. //uint16 endGlyphIndex Highest glyph index for this size. //uint8 ppemX Horizontal pixels per em. //uint8 ppemY Vertical pixels per em. //uint8 bitDepth The Microsoft rasterizer v.1.7 or greater supports the following bitDepth values, as described below: 1, 2, 4, and 8. //int8 flags Vertical or horizontal(see Bitmap Flags, below). //CBLC's BitmapSize Table (https://docs.microsoft.com/en-us/typography/opentype/spec/cblc) //Type Name Description //Offset32 indexSubTableArrayOffset Offset to index subtable from beginning of CBLC. //uint32 indexTablesSize Number of bytes in corresponding index subtables and array. //uint32 numberofIndexSubTables There is an index subtable for each range or format change. //uint32 colorRef Not used; set to 0. //SbitLineMetrics hori Line metrics for text rendered horizontally. //SbitLineMetrics vert Line metrics for text rendered vertically. //uint16 startGlyphIndex Lowest glyph index for this size. //uint16 endGlyphIndex Highest glyph index for this size. //uint8 ppemX Horizontal pixels per em. //uint8 ppemY Vertical pixels per em. //uint8 bitDepth In addtition to already defined bitDepth values 1, 2, 4, and 8 // supported by existing implementations, the value of 32 is used to // identify color bitmaps with 8 bit per pixel RGBA channels. //int8 flags Vertical or horizontal(see the Bitmap Flags section of the EBLC table chapter). //The indexSubTableArrayOffset is the offset from the beginning of //the CBLC table to the indexSubTableArray. //Each strike has one of these arrays to support various formats and //discontiguous ranges of bitmaps.The indexTablesSize is //the total number of bytes in the indexSubTableArray and //the associated indexSubTables. //The numberOfIndexSubTables is a count of the indexSubTables for this strike. //The rest of the CBLC table structure is identical to one already defined for EBLC. BitmapSizeTable bmpSizeTable = new BitmapSizeTable(); bmpSizeTable.indexSubTableArrayOffset = reader.ReadUInt32(); bmpSizeTable.indexTablesSize = reader.ReadUInt32(); bmpSizeTable.numberOfIndexSubTables = reader.ReadUInt32(); bmpSizeTable.colorRef = reader.ReadUInt32(); BitmapSizeTable.ReadSbitLineMetrics(reader, ref bmpSizeTable.hori); BitmapSizeTable.ReadSbitLineMetrics(reader, ref bmpSizeTable.vert); bmpSizeTable.startGlyphIndex = reader.ReadUInt16(); bmpSizeTable.endGlyphIndex = reader.ReadUInt16(); bmpSizeTable.ppemX = reader.ReadByte(); bmpSizeTable.ppemY = reader.ReadByte(); bmpSizeTable.bitDepth = reader.ReadByte(); bmpSizeTable.flags = (sbyte)reader.ReadByte(); return(bmpSizeTable); }
public static IndexSubTableBase CreateFrom(BitmapSizeTable bmpSizeTable, BinaryReader reader) { //read IndexSubHeader //IndexSubHeader //Type Name Description //uint16 indexFormat Format of this IndexSubTable. //uint16 imageFormat Format of EBDT image data. //Offset32 imageDataOffset Offset to image data in EBDT table. //There are currently five different formats used for the IndexSubTable, //depending upon the size and type of bitmap data in the glyph ID range. //Apple 'bloc' tables support only formats 1 through 3. //The choice of which IndexSubTable format to use is up to the font manufacturer, //but should be made with the aim of minimizing the size of the font file. //Ranges of glyphs with variable metrics — that is, //where glyphs may differ from each other in bounding box height, width, side bearings or //advance — must use format 1, 3 or 4. //Ranges of glyphs with constant metrics can save space by using format 2 or 5, //which keep a single copy of the metrics information in the IndexSubTable rather //than a copy per glyph in the EBDT table. //In some monospaced fonts it makes sense to store extra white space around //some of the glyphs to keep all metrics identical, thus permitting the use of format 2 or 5. IndexSubHeader header = new IndexSubHeader( reader.ReadUInt16(), reader.ReadUInt16(), reader.ReadUInt32() ); switch (header.indexFormat) { case 1: //IndexSubTable1: variable - metrics glyphs with 4 - byte offsets //Type Name Description //IndexSubHeader header Header info. //Offset32 offsetArray[] offsetArray[glyphIndex] + imageDataOffset = glyphData sizeOfArray = (lastGlyph - firstGlyph + 1) + 1 + 1 pad if needed { int nElem = (bmpSizeTable.endGlyphIndex - bmpSizeTable.startGlyphIndex + 1); uint[] offsetArray = Utils.ReadUInt32Array(reader, nElem); //check 16 bit align padd IndexSubTable1 subTable = new IndexSubTable1(); subTable.header = header; subTable.offsetArray = offsetArray; return(subTable); } case 2: //IndexSubTable2: all glyphs have identical metrics //Type Name Description //IndexSubHeader header Header info. //uint32 imageSize All the glyphs are of the same size. //BigGlyphMetrics bigMetrics All glyphs have the same metrics; glyph data may be compressed, byte-aligned, or bit-aligned. { IndexSubTable2 subtable = new IndexSubTable2(); subtable.header = header; subtable.imageSize = reader.ReadUInt32(); BigGlyphMetrics.ReadBigGlyphMetric(reader, ref subtable.BigGlyphMetrics); return(subtable); } case 3: //IndexSubTable3: variable - metrics glyphs with 2 - byte offsets //Type Name Description //IndexSubHeader header Header info. //Offset16 offsetArray[] offsetArray[glyphIndex] + imageDataOffset = glyphData sizeOfArray = (lastGlyph - firstGlyph + 1) + 1 + 1 pad if needed { int nElem = (bmpSizeTable.endGlyphIndex - bmpSizeTable.startGlyphIndex + 1); ushort[] offsetArray = Utils.ReadUInt16Array(reader, nElem); //check 16 bit align padd IndexSubTable3 subTable = new IndexSubTable3(); subTable.header = header; subTable.offsetArray = offsetArray; return(subTable); } case 4: //IndexSubTable4: variable - metrics glyphs with sparse glyph codes //Type Name Description //IndexSubHeader header Header info. //uint32 numGlyphs Array length. //GlyphIdOffsetPair glyphArray[numGlyphs + 1] One per glyph. { IndexSubTable4 subTable = new IndexSubTable4(); subTable.header = header; uint numGlyphs = reader.ReadUInt32(); GlyphIdOffsetPair[] glyphArray = subTable.glyphArray = new GlyphIdOffsetPair[numGlyphs + 1]; for (int i = 0; i <= numGlyphs; ++i) //*** { glyphArray[i] = new GlyphIdOffsetPair(reader.ReadUInt16(), reader.ReadUInt16()); } return(subTable); } case 5: //IndexSubTable5: constant - metrics glyphs with sparse glyph codes //Type Name Description //IndexSubHeader header Header info. //uint32 imageSize All glyphs have the same data size. //BigGlyphMetrics bigMetrics All glyphs have the same metrics. //uint32 numGlyphs Array length. //uint16 glyphIdArray[numGlyphs] One per glyph, sorted by glyph ID. { IndexSubTable5 subTable = new IndexSubTable5(); subTable.header = header; subTable.imageSize = reader.ReadUInt32(); BigGlyphMetrics.ReadBigGlyphMetric(reader, ref subTable.BigGlyphMetrics); subTable.glyphIdArray = Utils.ReadUInt16Array(reader, (int)reader.ReadUInt32()); return(subTable); } } //The size of the EBDT image data can be calculated from the IndexSubTable information. //For the constant-metrics formats(2 and 5) the image data size is constant, //and is given in the imageSize field.For the variable metrics formats(1, 3, and 4) //image data must be stored contiguously and in glyph ID order, //so the image data size may be calculated by subtracting the offset for //the current glyph from the offset of the next glyph. //Because of this, it is necessary to store one extra element in the offsetArray pointing //just past the end of the range’s image data. //This will allow the correct calculation of the image data size for the last glyph in the range. //Contiguous, or nearly contiguous, //ranges of glyph IDs are handled best by formats 1, 2, and 3 which //store an offset for every glyph ID in the range. //Very sparse ranges of glyph IDs should use format 4 or 5 which explicitly //call out the glyph IDs represented in the range. //A small number of missing glyphs can be efficiently represented in formats 1 or 3 by having //the offset for the missing glyph be followed by the same offset for //the next glyph, thus indicating a data size of zero. //The only difference between formats 1 and 3 is //the size of the offsetArray elements: format 1 uses uint32s while format 3 uses uint16s. //Therefore format 1 can cover a greater range(> 64k bytes) //while format 3 saves more space in the EBLC table. //Since the offsetArray elements are added to the imageDataOffset base address in the IndexSubHeader, //a very large set of glyph bitmap data could be addressed by splitting it into multiple ranges, //each less than 64k bytes in size, //allowing the use of the more efficient format 3. //The EBLC table specification requires 16 - bit alignment for all subtables. //This occurs naturally for IndexSubTable formats 1, 2, and 4, //but may not for formats 3 and 5, //since they include arrays of type uint16. //When there is an odd number of elements in these arrays //**it is necessary to add an extra padding element to maintain proper alignment. return(null); }