private static uint[] LoadIndexToLocation(FontSource p, uint tableOffset, ushort glyphCount, short indexToLocFormat) { p.Offset = tableOffset; var isLong = indexToLocFormat == 1; var n = glyphCount + 1; var localOffsets = new uint[n]; if (isLong) { for (var i = 0; i < n; i++) { localOffsets[i] = p.ReadUInt(); } } else { for (var i = 0; i < n; i++) { localOffsets[i] = (uint)p.ReadUShort() * 2; } } return(localOffsets); }
private static Dictionary <uint, uint> LoadSegmentedCoverage(FontSource p) { var dic = new Dictionary <uint, uint>(); // Skip format p.ReadUShort(); // Skip reserved p.ReadUShort(); var length = p.ReadUInt(); var language = p.ReadUInt(); var numGroups = p.ReadUInt(); for (var i = 0; i < numGroups; i++) { var startCharCode = p.ReadUInt(); var endCharCode = p.ReadUInt(); var startGlyphId = p.ReadUInt(); for (var c = startCharCode; c <= endCharCode; c++) { dic[c] = startGlyphId; startGlyphId++; } } return(dic); }
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); }
private static Dictionary <uint, uint> LoadSegmentMappingToDeltaValues(FontSource p) { var dic = new Dictionary <uint, uint>(); var offset = p.Offset; // Skip format p.ReadUShort(); var length = p.ReadUShort(); var language = p.ReadUShort(); var segCount = p.ReadUShort() >> 1; var searchRange = p.ReadUShort(); var entrySelector = p.ReadUShort(); var rangeShift = p.ReadUShort(); var endCodeParser = new FontSource(p.Bytes, offset + 14); var startCodeParser = new FontSource(p.Bytes, (uint)(offset + 16 + segCount * 2)); var idDeltaParser = new FontSource(p.Bytes, (uint)(offset + 16 + segCount * 4)); var idRangeOffsetParser = new FontSource(p.Bytes, (uint)(offset + 16 + segCount * 6)); for (var i = 0; i < segCount - 1; i++) { var endCode = endCodeParser.ReadUShort(); var startCode = startCodeParser.ReadUShort(); var idDelta = idDeltaParser.ReadShort(); var idRangeOffset = idRangeOffsetParser.ReadUShort(); for (var c = startCode; c <= endCode; c++) { uint glyphIndex; if (idRangeOffset != 0) { var glyphIndexOffset = idRangeOffsetParser.Offset - 2; glyphIndexOffset += idRangeOffset; glyphIndexOffset += (uint)(c - startCode) * 2; p.Offset = glyphIndexOffset; glyphIndex = p.ReadUShort(); if (glyphIndex != 0) { glyphIndex = (uint)(glyphIndex + idDelta) & 0xFFFF; } } else { glyphIndex = (uint)(c + idDelta) & 0xFFFF; } dic[c] = glyphIndex; } } return(dic); }
public static GlyphComponent Load(FontSource p) { var gc = new GlyphComponent(); var flags = p.ReadUShort(); gc.GlyphId = p.ReadUShort(); if ((flags & 1) > 0) { if ((flags & 2) > 0) { gc.DX = p.ReadShort(); gc.DY = p.ReadShort(); } else { gc.MatchedPoints = new[] { p.ReadUShort(), p.ReadUShort() }; } } else { if ((flags & 2) > 0) { gc.DX = p.ReadSByte(); gc.DY = p.ReadSByte(); } else { gc.MatchedPoints = new[] { p.ReadUShort(), p.ReadUShort() }; } } if ((flags & 8) > 0) { gc.XScale = gc.YScale = p.ReadF2Dot14(); } else if ((flags & 64) > 0) { gc.XScale = p.ReadF2Dot14(); gc.YScale = p.ReadF2Dot14(); } else if ((flags & 128) > 0) { gc.XScale = p.ReadF2Dot14(); gc.Scale01 = p.ReadF2Dot14(); gc.Scale10 = p.ReadF2Dot14(); gc.YScale = p.ReadF2Dot14(); } gc.MoreComponents = (flags & 32) > 0; return(gc); }
public GlyphHeader LoadHeader(uint localOffset, FontSource source) { source.Offset = _offset + localOffset; return(new GlyphHeader( source.ReadShort(), source.ReadShort(), source.ReadShort(), source.ReadShort(), source.ReadShort(), source.Offset )); }
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); } }
public GlyphContourInfo GetGlyph(uint code, FontSource fontSource) { if (UnicodeUtility.IsControl(code)) { throw new FontException($"Cannot get control characters: U+{code:X2}"); } if (!_glyphIndexMap.ContainsKey(code)) { throw new FontException($"Glyph not found: U+{code:X4}"); } var gid = _glyphIndexMap[code]; return(GetGlyphFromGid(gid, fontSource)); }
private static Dictionary <uint, uint> LoadCharacterToGlyphIndexMappingTable(FontSource p, uint tableOffset) { p.Offset = tableOffset; var version = p.ReadUShort(); var numTables = p.ReadUShort(); var encodingRecords = new EncodingRecord[numTables]; for (var i = 0; i < numTables; i++) { encodingRecords[i] = EncodingRecord.Load(p, tableOffset); } var targetRecordId = -1; for (var i = numTables - 1; i >= 0; i--) { var r = encodingRecords[i]; if (r.PlatformID == 3 && (r.EncodingID == 0 || r.EncodingID == 1 || r.EncodingID == 10) || r.PlatformID == 0 && (r.EncodingID == 0 || r.EncodingID == 1 || r.EncodingID == 2 || r.EncodingID == 3 || r.EncodingID == 4)) { targetRecordId = i; break; } } if (targetRecordId < 0) { throw new FontException("Encoding record not found."); } var targetRecord = encodingRecords[targetRecordId]; if (targetRecord.SubTableFormat == 12) { p.Offset = tableOffset + targetRecord.Offset; return(LoadSegmentedCoverage(p)); } if (targetRecord.SubTableFormat == 4) { p.Offset = tableOffset + targetRecord.Offset; return(LoadSegmentMappingToDeltaValues(p)); } throw new FontException($"Unsupported format: {targetRecord.SubTableFormat}"); }
public GlyphComponent[] GetGlyphComponents(FontSource source) { source.Offset = Offset; var list = new List <GlyphComponent>(); var limit = 10; while (limit-- > 0) { var component = GlyphComponent.Load(source); list.Add(component); if (!component.MoreComponents) { break; } } return(list.ToArray()); }
public GlyphContourInfo GetGlyphFromGid(uint gid, FontSource fontSource) { if (Type == FontType.TrueType) { var gcd = new GlyphContourInfo(_glyphs[gid]); if (HasLocalOffset(gid)) { gcd.Header = _glyph.LoadHeader(_localOffsets[gid], fontSource); } return(gcd); } if (Type == FontType.OpenType) { var gcd = new GlyphContourInfo(_glyphs[gid]); gcd.Path = CffCharString.Load(gid, this, fontSource.Bytes); return(gcd); } return(null); }
private static void LoadFontHeader(FontSource p, uint tableOffset, out short indexToLocFormat, out ushort unitsPerEm) { p.Offset = tableOffset; p.ReadUShort(); p.ReadUShort(); p.ReadFixed(); p.ReadUInt(); p.ReadUInt(); p.ReadUShort(); unitsPerEm = p.ReadUShort(); p.Offset += 8 * 2; p.ReadShort(); p.ReadShort(); p.ReadShort(); p.ReadShort(); p.ReadUShort(); p.ReadUShort(); p.ReadShort(); indexToLocFormat = p.ReadShort(); p.ReadShort(); }
public GlyphPoint[] GetGlyphPoints(FontSource source) { source.Offset = Offset; var endPtsOfContours = new ushort[NumberOfContours]; for (var i = 0; i < NumberOfContours; i++) { endPtsOfContours[i] = source.ReadUShort(); } //instructionLength = data.ReadUShort(); //instructions = new byte[instructionLength]; //for (var i = 0; i < instructionLength; i++) instructions[i] = data.ReadByte(); // Ignore instructions. var instructionLength = source.ReadUShort(); source.Offset += instructionLength; var numberOfCoordinates = endPtsOfContours[endPtsOfContours.Length - 1] + 1; var points = new List <GlyphPoint>(numberOfCoordinates); for (var i = 0; i < numberOfCoordinates; i++) { var flag = source.ReadByte(); var glyphPoint = new GlyphPoint(flag); points.Add(glyphPoint); if (glyphPoint.IsRepeat) { var count = source.ReadByte(); for (var k = 0; k < count; k++) { points.Add(new GlyphPoint(flag)); i++; } } } foreach (var ep in endPtsOfContours) { points[ep].IsEndPoint = true; } short xSum = 0; short ySum = 0; // Read X foreach (var point in points) { var flag = point.Flag; var isShortX = GetFlag(flag, 1); var isSameX = GetFlag(flag, 4); if (isShortX) { if (isSameX) { xSum += source.ReadByte(); } else { xSum += (short)-source.ReadByte(); } } else { if (!isSameX) { xSum += source.ReadShort(); } } point.X = xSum; } // Read Y foreach (var point in points) { var flag = point.Flag; var isShortY = GetFlag(flag, 2); var isSameY = GetFlag(flag, 5); if (isShortY) { if (isSameY) { ySum += source.ReadByte(); } else { ySum += (short)-source.ReadByte(); } } else { if (!isSameY) { ySum += source.ReadShort(); } } point.Y = ySum; } return(points.ToArray()); }
private static ushort LoadGlyphCount(FontSource p, uint tableOffset) { p.Offset = tableOffset + 4; return(p.ReadUShort()); }
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 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))); } }
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))); }
public GlyphContourInfo GetNotDefGlyph(FontSource fontSource) { return(GetGlyphFromGid(0, fontSource)); }
private static ushort LoadNumberOfHMetrics(FontSource p, uint tableOffset) { p.Offset = tableOffset + 34; return(p.ReadUShort()); }