public static FontModel Load(FontSource source) { var font = new FontModel(); var offsetTable = OffsetTable.Load(source); if (offsetTable.SfntVersion == 0x10000) { font.Type = FontType.TrueType; } else if (offsetTable.SfntVersion == 0x4f54544f) { font.Type = FontType.OpenType; } else { throw new FontException($"Unknown sfntVersion: {offsetTable.SfntVersion:X4}"); } var tableOffsets = new Dictionary <string, uint>(offsetTable.NumTables); for (var i = 0; i < offsetTable.NumTables; i++) { var table = TableRecord.Load(source); tableOffsets[table.Tag] = table.Offset; } LoadFontHeader(source, tableOffsets["head"], out var indexToLocFormat, out var unitsPerEm); font.BaseScale = 1f / unitsPerEm; font.UnitsPerEm = unitsPerEm; var glyphCount = LoadGlyphCount(source, tableOffsets["maxp"]); font._glyphs = new GlyphInfo[glyphCount]; var numberOfHMetrics = LoadNumberOfHMetrics(source, tableOffsets["hhea"]); LoadHorizontalMetrics(font, source, tableOffsets["hmtx"], numberOfHMetrics, glyphCount); font._glyphIndexMap = LoadCharacterToGlyphIndexMappingTable(source, tableOffsets["cmap"]); if (tableOffsets.ContainsKey("loca")) { font._localOffsets = LoadIndexToLocation(source, tableOffsets["loca"], glyphCount, indexToLocFormat); } if (tableOffsets.ContainsKey("glyf")) { font._glyph = new GlyphTable(tableOffsets["glyf"]); } if (tableOffsets.ContainsKey("CFF")) { font._cff = CompactFontFormatTable.Load(tableOffsets["CFF"], source, font); } return(font); }
public static GlyphContourInfoV2 ToVector2(this GlyphContourInfo g, FontModel model, FontSource source) { switch (model.Type) { case FontModel.FontType.TrueType: return(FromTtfGlyph(g, model, source)); case FontModel.FontType.OpenType: return(FromOtfGlyph(g, model, source)); default: throw new InvalidEnumArgumentException(model.Type.ToString()); } }
private static void LoadHorizontalMetrics(FontModel font, FontSource p, uint tableOffset, int numberOfHMetrics, int numGlyphs) { ushort advancedWidth = 0; short leftSideBearing = 0; p.Offset = tableOffset; for (var i = 0; i < numGlyphs; i++) { if (i < numberOfHMetrics) { advancedWidth = p.ReadUShort(); leftSideBearing = p.ReadShort(); } font._glyphs[i] = new GlyphInfo(advancedWidth, leftSideBearing); } }
private static GlyphContourInfoV2 FromOtfGlyph(GlyphContourInfo g, FontModel model, FontSource source) { var advancedWidth = g.BaseInfo.AdvancedWidth * model.BaseScale; var leftSideBearing = g.BaseInfo.LeftSideBearing * model.BaseScale; var contours = new List <List <ContourPoint> >(); List <ContourPoint> contour = null; foreach (var cp in g.Path.Points) { if (cp.isContour) { contour = new List <ContourPoint>(); contours.Add(contour); } if (cp.isCurve) { contour.Add(new ContourPoint((short)cp.x, (short)cp.y, false)); } else { contour.Add(new ContourPoint((short)cp.x, (short)cp.y, true)); } } foreach (var c in contours) { var first = c[0]; var last = c[c.Count - 1]; if (first.X == last.X && first.Y == last.Y) { c.RemoveAt(c.Count - 1); } } return(new GlyphContourInfoV2(advancedWidth, leftSideBearing, ContourToVector(contours, model.BaseScale, false))); }
private static GlyphContourInfoV2 FromTtfGlyph(GlyphContourInfo g, FontModel model, FontSource source) { var advancedWidth = g.BaseInfo.AdvancedWidth * model.BaseScale; var leftSideBearing = g.BaseInfo.LeftSideBearing * model.BaseScale; if (g.Header.NumberOfContours > 0) { var con = new List <List <ContourPoint> >(); var points = g.Header.GetGlyphPoints(source); if (points == null || points.Length == 0) { throw new FontException("Cannot get points"); } var list = new List <ContourPoint>(); con.Add(list); for (var i = 0; i < points.Length; i++) { var point = points[i]; var contourPoint = new ContourPoint(point.X, point.Y, point.OnCurve); list.Add(contourPoint); if (point.IsEndPoint && i != points.Length - 1) { list = new List <ContourPoint>(); con.Add(list); } } return(new GlyphContourInfoV2(advancedWidth, leftSideBearing, ContourToVector(con, model.BaseScale, true))); } else { // Composite Glyph var components = g.Header.GetGlyphComponents(source); var con = new List <List <ContourPoint> >(); foreach (var component in components) { var cg = model.GetGlyphFromGid(component.GlyphId, source); if (cg.Header.NumberOfContours > 0) { var points = cg.Header.GetGlyphPoints(source); if (points == null || points.Length == 0) { throw new FontException("Cannot get points"); } if (component.MatchedPoints == null) { GlyphTable.GlyphHeader.GlyphComponent.TransformPoints(points, component); } else { // MatchedPoints are not supported. break; } var list = new List <ContourPoint>(); con.Add(list); for (var i = 0; i < points.Length; i++) { var point = points[i]; var contourPoint = new ContourPoint(point.X, point.Y, point.OnCurve); list.Add(contourPoint); if (point.IsEndPoint && i != points.Length - 1) { list = new List <ContourPoint>(); con.Add(list); } } } } return(new GlyphContourInfoV2(advancedWidth, leftSideBearing, ContourToVector(con, model.BaseScale, true))); } }