static SimpleGlyphFlag[] ReadFlags(BinaryReader input, int flagCount) { var result = new SimpleGlyphFlag[flagCount]; int i = 0; int repeatCount = 0; var flag = (SimpleGlyphFlag)0; while (i < flagCount) { if (repeatCount > 0) { repeatCount--; } else { flag = (SimpleGlyphFlag)input.ReadByte(); if (HasFlag(flag, SimpleGlyphFlag.Repeat)) { repeatCount = input.ReadByte(); } } result[i++] = flag; } return(result); }
static bool HasFlag(SimpleGlyphFlag target, SimpleGlyphFlag test) { return((target & test) == test); }
static short[] ReadCoordinates(BinaryReader input, int pointCount, SimpleGlyphFlag[] flags, SimpleGlyphFlag isByte, SimpleGlyphFlag signOrSame) { //https://www.microsoft.com/typography/OTSPEC/glyf.htm //Note: In the glyf table, the position of a point is not stored in absolute terms but as a vector relative to the previous point. //The delta-x and delta-y vectors represent these (often small) changes in position. //Each flag is a single bit. Their meanings are shown below. //Bit Flags Description //0 On Curve If set, the point is on the curve; otherwise, it is off the curve. //1 x-Short Vector If set, the corresponding x-coordinate is 1 byte long. If not set, 2 bytes. //2 y-Short Vector If set, the corresponding y-coordinate is 1 byte long. If not set, 2 bytes. //3 Repeat If set, the next byte specifies the number of additional times this set of flags is to be repeated. // In this way, the number of flags listed can be smaller than the number of points in a character. //4 This x is same(Positive x-Short Vector) This flag has two meanings, depending on how the x-Short Vector flag is set. // If x-Short Vector is set, this bit describes the sign of the value, // with 1 equalling positive and 0 negative. // If the x-Short Vector bit is not set and this bit is set, then the current x-coordinate is the same as the previous x-coordinate. // If the x-Short Vector bit is not set and this bit is also not set, the current x-coordinate is a signed 16-bit delta vector. //5 This y is same (Positive y-Short Vector) This flag has two meanings, // depending on how the y-Short Vector flag is set. // If y-Short Vector is set, this bit describes the sign of the value, // with 1 equalling positive and 0 negative. // If the y-Short Vector bit is not set and this bit is set, then the current y-coordinate is the same as the previous y-coordinate. // If the y-Short Vector bit is not set and this bit is also not set, // the current y-coordinate is a signed 16-bit delta vector. //6 Reserved This bit is reserved. Set it to zero. //7 Reserved This bit is reserved. Set it to zero. var xs = new short[pointCount]; int x = 0; for (int i = 0; i < pointCount; i++) { int dx; if (HasFlag(flags[i], isByte)) { byte b = input.ReadByte(); dx = HasFlag(flags[i], signOrSame) ? b : -b; } else { if (HasFlag(flags[i], signOrSame)) { dx = 0; } else { dx = input.ReadInt16(); } } x += dx; xs[i] = (short)x; // TODO: overflow? } return(xs); }
static SimpleGlyphFlag[] ReadFlags(BinaryReader input, int flagCount) { var result = new SimpleGlyphFlag[flagCount]; int i = 0; int repeatCount = 0; var flag = (SimpleGlyphFlag)0; while (i < flagCount) { if (repeatCount > 0) { repeatCount--; } else { flag = (SimpleGlyphFlag)input.ReadByte(); if (HasFlag(flag, SimpleGlyphFlag.Repeat)) { repeatCount = input.ReadByte(); } } result[i++] = flag; } return result; }
static bool HasFlag(SimpleGlyphFlag target, SimpleGlyphFlag test) { return (target & test) == test; }
static short[] ReadCoordinates(BinaryReader input, int pointCount, SimpleGlyphFlag[] flags, SimpleGlyphFlag isByte, SimpleGlyphFlag signOrSame) { //https://www.microsoft.com/typography/OTSPEC/glyf.htm //Note: In the glyf table, the position of a point is not stored in absolute terms but as a vector relative to the previous point. //The delta-x and delta-y vectors represent these (often small) changes in position. //Each flag is a single bit. Their meanings are shown below. //Bit Flags Description //0 On Curve If set, the point is on the curve; otherwise, it is off the curve. //1 x-Short Vector If set, the corresponding x-coordinate is 1 byte long. If not set, 2 bytes. //2 y-Short Vector If set, the corresponding y-coordinate is 1 byte long. If not set, 2 bytes. //3 Repeat If set, the next byte specifies the number of additional times this set of flags is to be repeated. // In this way, the number of flags listed can be smaller than the number of points in a character. //4 This x is same(Positive x-Short Vector) This flag has two meanings, depending on how the x-Short Vector flag is set. // If x-Short Vector is set, this bit describes the sign of the value, // with 1 equalling positive and 0 negative. // If the x-Short Vector bit is not set and this bit is set, then the current x-coordinate is the same as the previous x-coordinate. // If the x-Short Vector bit is not set and this bit is also not set, the current x-coordinate is a signed 16-bit delta vector. //5 This y is same (Positive y-Short Vector) This flag has two meanings, // depending on how the y-Short Vector flag is set. // If y-Short Vector is set, this bit describes the sign of the value, // with 1 equalling positive and 0 negative. // If the y-Short Vector bit is not set and this bit is set, then the current y-coordinate is the same as the previous y-coordinate. // If the y-Short Vector bit is not set and this bit is also not set, // the current y-coordinate is a signed 16-bit delta vector. //6 Reserved This bit is reserved. Set it to zero. //7 Reserved This bit is reserved. Set it to zero. var xs = new short[pointCount]; int x = 0; for (int i = 0; i < pointCount; i++) { int dx; if (HasFlag(flags[i], isByte)) { byte b = input.ReadByte(); dx = HasFlag(flags[i], signOrSame) ? b : -b; } else { if (HasFlag(flags[i], signOrSame)) { dx = 0; } else { dx = input.ReadInt16(); } } x += dx; xs[i] = (short)x; // TODO: overflow? } return xs; }