public static CmapTable Read(FontStreamReader reader, OffsetTable.Entry entry) { reader.Seek(entry); var version = reader.ReadUInt16(); if (version != 0) { throw new FormatException($"Unexpected version number in cmap table: {version}, expecting 0"); } var numberOfSubtables = reader.ReadUInt16(); var subtables = new Dictionary <Tuple <ushort, ushort>, CmapFormat>(); for (var i = 0; i < numberOfSubtables; i++) { var platformId = reader.ReadUInt16(); var platformSpecificId = reader.ReadUInt16(); var relOffset = reader.ReadUInt32(); var offset = entry.Offset + relOffset; var subtable = ReadSubtable(reader, platformId, platformSpecificId, offset); subtables.Add(Tuple.Create(platformId, platformSpecificId), subtable); } return(new CmapTable(version, subtables)); }
public static FpgmTable Read(FontStreamReader reader, OffsetTable.Entry entry) { reader.Seek(entry); var instructions = reader.ReadArray <byte>(entry.Length, r => r.ReadUInt8); return(new FpgmTable(instructions)); }
public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId) { var length = reader.ReadUInt16(); var language = reader.ReadUInt16(); var glyphIndexArray = reader.ReadArray <byte>(256, r => r.ReadUInt8); return(new CmapFormat0(language, glyphIndexArray)); }
private static Glyph ReadGlyph(FontStreamReader reader) { var numberOfContours = reader.ReadInt16(); var isCompound = numberOfContours < 0; var xMin = reader.ReadFWord(); var yMin = reader.ReadFWord(); var xMax = reader.ReadFWord(); var yMax = reader.ReadFWord(); if (isCompound) { return(ReadCompoundGlyph(reader, xMin, yMin, xMax, yMax)); } return(ReadSimpleGlyph(reader, numberOfContours, xMin, yMin, xMax, yMax)); }
public static LocaTable Read(Font font, FontStreamReader reader, OffsetTable.Entry entry) { reader.Seek(entry); var length = entry.Length; var format = font.HeadTable.IndexToLocFormat; switch (format) { case IndexToLocFormat.Short: return(new LocaTable(reader.ReadArray <uint>(length / sizeof(ushort), r => (() => r.ReadUInt16())))); case IndexToLocFormat.Long: return(new LocaTable(reader.ReadArray <uint>(length / sizeof(uint), r => r.ReadUInt32))); default: throw new FormatException($"Invalid IndexToLocFormat: {format}"); } }
public static HeadTable Read(FontStreamReader reader, OffsetTable.Entry entry) { reader.Seek(entry); var version = reader.ReadFixed(); var fontRevision = reader.ReadFixed(); //TODO var checkSumAdjustment = reader.ReadUInt32(); var magicNumber = reader.ReadUInt32(); // 0x5F0F3CF5 if (magicNumber != 0x5F0F3CF5) { throw new FormatException($"Invalid magic number in header: 0x{magicNumber:X}, expecting 0x5F0F3CF5"); } var flags = reader.ReadUInt16(); // bitflags var unitsPerEm = reader.ReadUInt16(); // 64-16384 if (unitsPerEm < 64 || unitsPerEm > 16384) { throw new FormatException($"Invalid units per em in header: {unitsPerEm:X}, expecting a value between 64 and 16384"); } var created = reader.ReadLongDateTime(); var modified = reader.ReadLongDateTime(); var xMin = reader.ReadFWord(); var yMin = reader.ReadFWord(); var xMax = reader.ReadFWord(); var yMax = reader.ReadFWord(); var macStyle = (MacStyle)reader.ReadUInt16(); // bitflags var lowestRecPPEM = reader.ReadUInt16(); var fontDirectionHint = reader.ReadUInt16(); var indexToLocFormat = (IndexToLocFormat)reader.ReadUInt16(); // 0 = short, 1 = long var glyphDataFormat = (GlyphDataFormat)reader.ReadUInt16(); // 0 = current return(new HeadTable(version, fontRevision, flags, unitsPerEm, created, modified, xMin, yMin, xMax, yMax, macStyle, lowestRecPPEM, fontDirectionHint, indexToLocFormat, glyphDataFormat)); }
public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId) { uint length = reader.ReadUInt16(); var language = reader.ReadUInt16(); length -= 3 * sizeof(ushort); var segCount = (ushort)(reader.ReadUInt16() / 2); // stored as 2 * segCount var searchRange = reader.ReadUInt16(); var entrySelector = reader.ReadUInt16(); var rangeShift = reader.ReadUInt16(); length -= 4 * sizeof(ushort); var endCode = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16); if (endCode[endCode.Length - 1] != 0xffff) { throw new FormatException($"Unexpected last endCode: 0x{endCode[endCode.Length - 1]:X}, expecting 0xffff"); } var reservedPad = reader.ReadUInt16(); // 0 if (reservedPad != 0) { throw new FormatException($"Unexpected value for reservedPad: {reservedPad}, expecting 0"); } length -= (ushort)(segCount * sizeof(ushort) + 1); var startCode = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16); var idDelta = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16); var idRangeOffset = reader.ReadArray <ushort>(segCount, r => r.ReadUInt16); length -= (ushort)(3 * segCount * sizeof(ushort)); var glyphIndexArray = reader.ReadArray <ushort>(length / sizeof(ushort), r => r.ReadUInt16); return(new CmapFormat4(language, startCode, endCode, idDelta, idRangeOffset, glyphIndexArray)); }
public static GlyfTable Read(FontStreamReader reader, OffsetTable.Entry entry) { reader.Seek(entry); var glyphs = new List <Glyph>(); while (reader.Position < entry.Offset + entry.Length) { glyphs.Add(ReadGlyph(reader)); while ((reader.Position & 1) != 0) { reader.ReadUInt8(); } } if (reader.Position > entry.Offset + entry.Length) { throw new Exception("Overflow?"); } return(new GlyfTable(glyphs)); }
private static CmapFormat ReadSubtable(FontStreamReader reader, ushort platformId, ushort platformSpecificId, uint offset) { reader.Push(); reader.Seek(offset, SeekOrigin.Begin); var format = reader.ReadUInt16(); CmapFormat result; switch (format) { case 0: result = CmapFormat0.Read(reader, platformId, platformSpecificId); break; case 2: result = CmapFormat2.Read(reader, platformId, platformSpecificId); break; case 4: result = CmapFormat4.Read(reader, platformId, platformSpecificId); break; case 6: result = CmapFormat6.Read(reader, platformId, platformSpecificId); break; case 8: result = CmapFormat8.Read(reader, platformId, platformSpecificId); break; case 10: result = CmapFormat10.Read(reader, platformId, platformSpecificId); break; case 12: result = CmapFormat12.Read(reader, platformId, platformSpecificId); break; case 13: result = CmapFormat13.Read(reader, platformId, platformSpecificId); break; case 14: result = CmapFormat14.Read(reader, platformId, platformSpecificId); break; default: throw new FormatException($"Unexpected cmap subtable format: {format}"); } reader.Pop(); return(result); }
public static CmapFormat Read(FontStreamReader reader, ushort platformId, ushort platformSpecificId) { throw new NotImplementedException(); }
private static Glyph ReadCompoundGlyph(FontStreamReader reader, ushort xMin, ushort yMin, ushort xMax, ushort yMax) { var components = new List <CompoundGlyph.Component>(); var flags = GlyphComponentFlags.MoreComponents; while (flags.HasFlag(GlyphComponentFlags.MoreComponents)) { flags = (GlyphComponentFlags)reader.ReadUInt16(); var glyphIndex = reader.ReadInt16(); if (flags.HasFlag(GlyphComponentFlags.WeHaveInstructions) && flags.HasFlag(GlyphComponentFlags.MoreComponents)) { throw new NotImplementedException(); } var arg1 = flags.HasFlag(GlyphComponentFlags.Arg12AreWords) ? reader.ReadInt16() : reader.ReadUInt8(); var arg2 = flags.HasFlag(GlyphComponentFlags.Arg12AreWords) ? reader.ReadInt16() : reader.ReadUInt8(); var matrix = new decimal[] { 1, 0, 0, 1, 0, 0 }; short?destPointIndex = null; short?srcPointIndex = null; if (flags.HasFlag(GlyphComponentFlags.ArgsAreXYValues)) { matrix[4] = arg1; matrix[5] = arg2; } else { destPointIndex = arg1; srcPointIndex = arg1; } if (flags.HasFlag(GlyphComponentFlags.WeHaveAScale)) { matrix[0] = matrix[3] = reader.ReadF2Dot14(); } else if (flags.HasFlag(GlyphComponentFlags.WeHaveAnXYScale)) { matrix[0] = reader.ReadF2Dot14(); matrix[3] = reader.ReadF2Dot14(); } else if (flags.HasFlag(GlyphComponentFlags.WeHave2By2)) { matrix[0] = reader.ReadF2Dot14(); matrix[1] = reader.ReadF2Dot14(); matrix[2] = reader.ReadF2Dot14(); matrix[3] = reader.ReadF2Dot14(); } components.Add(new CompoundGlyph.Component(glyphIndex, matrix, destPointIndex, srcPointIndex)); } var instructions = new byte[0]; if (flags.HasFlag(GlyphComponentFlags.WeHaveInstructions)) { var instructionLength = reader.ReadUInt16(); instructions = reader.ReadArray <byte>(instructionLength, r => r.ReadUInt8); } return(new CompoundGlyph(components, instructions)); }
private static Glyph ReadSimpleGlyph(FontStreamReader reader, short numberOfContours, ushort xMin, ushort yMin, ushort xMax, ushort yMax) { var endPoints = reader.ReadArray <ushort>((ushort)numberOfContours, r => r.ReadUInt16); var instructionLength = reader.ReadUInt16(); var instructions = reader.ReadArray <byte>(instructionLength, r => r.ReadUInt8); if (numberOfContours == 0) { return(new SimpleGlyph(xMin, yMin, xMax, yMax, endPoints, instructions, new Point[0])); } var numberOfPoints = endPoints.Max() + 1; var flags = new SimpleGlyphFlags[numberOfPoints]; var points = new Point[numberOfPoints]; for (var i = 0; i < numberOfPoints; i++) { var flag = (SimpleGlyphFlags)reader.ReadUInt8(); flags[i] = flag; points[i] = new Point { OnCurve = flag.HasFlag(SimpleGlyphFlags.OnCurve) }; if (flag.HasFlag(SimpleGlyphFlags.Repeat)) { var count = reader.ReadUInt8(); while (count-- > 0) { flags[++i] = flag; points[i] = new Point { OnCurve = flag.HasFlag(SimpleGlyphFlags.OnCurve) }; } } } // read X short value = 0; for (var i = 0; i < numberOfPoints; i++) { var flag = flags[i]; if (flag.HasFlag(SimpleGlyphFlags.XShort)) { if (flag.HasFlag(SimpleGlyphFlags.XSame)) { value += reader.ReadUInt8(); } else { value -= reader.ReadUInt8(); } } else if (!flag.HasFlag(SimpleGlyphFlags.XSame)) { value += reader.ReadInt16(); } points[i].X = value; } // read Y value = 0; for (var i = 0; i < numberOfPoints; i++) { var flag = flags[i]; if (flag.HasFlag(SimpleGlyphFlags.YShort)) { if (flag.HasFlag(SimpleGlyphFlags.YSame)) { value += reader.ReadUInt8(); } else { value -= reader.ReadUInt8(); } } else if (!flag.HasFlag(SimpleGlyphFlags.YSame)) { value += reader.ReadInt16(); } points[i].Y = value; } return(new SimpleGlyph(xMin, yMin, xMax, yMax, endPoints, instructions, points)); }