public static TupleVariationHeader Read(BinaryReader reader, int axisCount) { TupleVariationHeader header = new TupleVariationHeader(); header.variableDataSize = reader.ReadUInt16(); ushort tupleIndex = reader.ReadUInt16(); int flags = (tupleIndex >> 12) & 0xF; //The high 4 bits are flags(see below). header.flags = flags; //The high 4 bits are flags(see below). header.indexToSharedTupleRecArray = (ushort)(tupleIndex & 0x0FFF); // The low 12 bits are an index into a shared tuple records array. if ((flags & ((int)TupleIndexFormat.EMBEDDED_PEAK_TUPLE >> 12)) == ((int)TupleIndexFormat.EMBEDDED_PEAK_TUPLE >> 12)) { //TODO:... header.peakTuple = TupleRecord.ReadTupleRecord(reader, axisCount); } if ((flags & ((int)TupleIndexFormat.INTERMEDIATE_REGION >> 12)) == ((int)TupleIndexFormat.INTERMEDIATE_REGION >> 12)) { //TODO:... header.intermediateStartTuple = TupleRecord.ReadTupleRecord(reader, axisCount); header.intermediateEndTuple = TupleRecord.ReadTupleRecord(reader, axisCount); } return(header); }
void ReadGlyphVariationData(BinaryReader reader, uint[] glyphVariationDataOffsets) { //------------ //The glyphVariationData table array //The glyphVariationData table array follows the 'gvar' header and shared tuples array. //Each glyphVariationData table describes the variation data for a single glyph in the font. //GlyphVariationData header: //Type Name Description //uint16 tupleVariationCount A packed field. // The high 4 bits are flags, // and the low 12 bits are the number of tuple variation tables for this glyph. // The number of tuple variation tables can be any number between 1 and 4095. //Offset16 dataOffset Offset from the start of the GlyphVariationData table to the serialized data //TupleVariationHeader tupleVariationHeaders[tupleCount] Array of tuple variation headers. long beginAt = reader.BaseStream.Position; ushort tupleVariationCount = reader.ReadUInt16(); ushort dataOffset = reader.ReadUInt16(); int flags = tupleVariationCount >> 12; //uppper 4 bits int tupleCount = tupleVariationCount & 0xFFF; //low 12 bits are the number of tuple variation tables for this glyph TupleVariationHeader[] headers = new TupleVariationHeader[tupleCount]; for (int i = 0; i < tupleCount; ++i) { TupleVariationHeader header = new TupleVariationHeader(); header.variableDataSize = (short)reader.ReadUInt16(); header.tupleIndex = reader.ReadUInt16(); TupleIndexFormat format = (TupleIndexFormat)(header.tupleIndex >> 8); //The high 4 bits are flags(see below). int indexToSharedTubleRecArrat = header.tupleIndex & 0x0FFF; // The low 12 bits are an index into a shared tuple records array. if ((format & TupleIndexFormat.EMBEDDED_PEAK_TUPLE) != 0) { //read peakTuple } if ((format & TupleIndexFormat.INTERMEDIATE_REGION) != 0) { //read start and end tuple } headers[i] = header; } }
GlyphVariableData ReadGlyphVariationData(BinaryReader reader) { //https://docs.microsoft.com/en-gb/typography/opentype/spec/otvarcommonformats#tuple-records //------------ //The glyphVariationData table array //The glyphVariationData table array follows the 'gvar' header and shared tuples array. //Each glyphVariationData table describes the variation data for a single glyph in the font. //GlyphVariationData header: //Type Name Description //uint16 tupleVariationCount A packed field. // The high 4 bits are flags, // and the low 12 bits are the number of tuple variation tables for this glyph. // The number of tuple variation tables can be any number between 1 and 4095. //Offset16 dataOffset Offset from the start of the GlyphVariationData table to the serialized data //TupleVariationHeader tupleVariationHeaders[tupleCount] Array of tuple variation headers. GlyphVariableData glyphVarData = new GlyphVariableData(); long beginAt = reader.BaseStream.Position; ushort tupleVariationCount = reader.ReadUInt16(); ushort dataOffset = reader.ReadUInt16(); //The tupleVariationCount field contains a packed value that includes flags and the number of //logical tuple variation tables — which is also the number of physical tuple variation headers. //The format of the tupleVariationCount value is as follows: //Table 4 //Mask Name Description //0x8000 SHARED_POINT_NUMBERS Flag indicating that some or all tuple variation tables reference a shared set of “point” numbers. // These shared numbers are represented as packed point number data at the start of the serialized data.*** //0x7000 Reserved Reserved for future use — set to 0. //0x0FFF COUNT_MASK Mask for the low bits to give the number of tuple variation tables. int tupleCount = tupleVariationCount & 0xFFF;//low 12 bits are the number of tuple variation tables for this glyph TupleVariationHeader[] tupleHaders = new TupleVariationHeader[tupleCount]; glyphVarData.tupleHeaders = tupleHaders; for (int i = 0; i < tupleCount; ++i) { tupleHaders[i] = TupleVariationHeader.Read(reader, axisCount); } //read glyph serialized data (https://docs.microsoft.com/en-gb/typography/opentype/spec/otvarcommonformats#serialized-data) reader.BaseStream.Position = beginAt + dataOffset; // //If the sharedPointNumbers flag is set, //then the serialized data following the header begins with packed “point” number data. //In the context of a GlyphVariationData table within the 'gvar' table, //these identify outline point numbers for which deltas are explicitly provided. //In the context of the 'cvar' table, these are interpreted as CVT indices rather than point indices. //The format of packed point number data is described below. //.... int flags = tupleVariationCount >> 12; //The high 4 bits are flags, if ((flags & 0x8) == 0x8) //check the flags has SHARED_POINT_NUMBERS or not { //The serialized data block begins with shared “point” number data, //followed by the variation data for the tuple variation tables. //The shared point number data is optional: //it is present if the corresponding flag is set in the tupleVariationCount field of the header. //If present, the shared number data is represented as packed point numbers, described below. //https://docs.microsoft.com/en-gb/typography/opentype/spec/otvarcommonformats#packed-point-numbers //... //Packed point numbers are stored as a count followed by one or more runs of point number data. //The count may be stored in one or two bytes. //After reading the first byte, the need for a second byte can be determined. //The count bytes are processed as follows: glyphVarData._sharedPoints = new List <ushort>(); ReadPackedPoints(reader, glyphVarData._sharedPoints); } for (int i = 0; i < tupleCount; ++i) { TupleVariationHeader header = tupleHaders[i]; ushort dataSize = header.variableDataSize; long expect_endAt = reader.BaseStream.Position + dataSize; #if DEBUG if (expect_endAt > reader.BaseStream.Length) { } #endif //The variationDataSize value indicates the size of serialized data for the given tuple variation table that is contained in the serialized data. //It does not include the size of the TupleVariationHeader. if ((header.flags & ((int)TupleIndexFormat.PRIVATE_POINT_NUMBERS >> 12)) == ((int)TupleIndexFormat.PRIVATE_POINT_NUMBERS) >> 12) { List <ushort> privatePoints = new List <ushort>(); ReadPackedPoints(reader, privatePoints); header.PrivatePoints = privatePoints.ToArray(); } else if (header.flags != 0) { } //Packed Deltas //Packed deltas are stored as a series of runs. Each delta run consists of a control byte followed by the actual delta values of that run. //The control byte is a packed value with flags in the high two bits and a count in the low six bits. //The flags specify the data size of the delta values in the run. The format of the control byte is as follows: //Packed Deltas //Mask Name Description //0x80 DELTAS_ARE_ZERO Flag indicating that this run contains no data (no explicit delta values are stored), and that all of the deltas for this run are zero. //0x40 DELTAS_ARE_WORDS Flag indicating the data type for delta values in the run. If set, the run contains 16-bit signed deltas (int16); if clear, the run contains 8-bit signed deltas (int8). //0x3F DELTA_RUN_COUNT_MASK Mask for the low 6 bits to provide the number of delta values in the run, minus one. List <short> packedDeltasXY = new List <short>(); while (reader.BaseStream.Position < expect_endAt) { byte controlByte = reader.ReadByte(); int number_in_run = (controlByte & 0x3F) + 1; int flags01 = (controlByte >> 6) << 6; if (flags01 == 0x80) { for (int nn = 0; nn < number_in_run; ++nn) { packedDeltasXY.Add(0); } } else if (flags01 == 0x40) { //DELTAS_ARE_WORDS Flag indicating the data type for delta values in the run.If set, //the run contains 16 - bit signed deltas(int16); //if clear, the run contains 8 - bit signed deltas(int8). for (int nn = 0; nn < number_in_run; ++nn) { packedDeltasXY.Add(reader.ReadInt16()); } } else if (flags01 == 0) { for (int nn = 0; nn < number_in_run; ++nn) { packedDeltasXY.Add(reader.ReadByte()); } } else { } } //--- header.PackedDeltasXY = packedDeltasXY.ToArray(); #if DEBUG //ensure! if ((packedDeltasXY.Count % 2) != 0) { System.Diagnostics.Debugger.Break(); } //ensure! if (reader.BaseStream.Position != expect_endAt) { System.Diagnostics.Debugger.Break(); } #endif } return(glyphVarData); }