private static TrueTypeFont ParseTables(decimal version, IReadOnlyDictionary <string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data) { var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff); var tableRegister = new TableRegister(); if (!tables.TryGetValue(TrueTypeHeaderTable.Head, out var table)) { throw new InvalidOperationException($"The {TrueTypeHeaderTable.Head} table is required."); } // head tableRegister.HeaderTable = HeaderTable.Load(data, table); if (!tables.TryGetValue(TrueTypeHeaderTable.Hhea, out var hHead)) { throw new InvalidOperationException("The horizontal header table is required."); } // hhea tableRegister.HorizontalHeaderTable = HorizontalHeaderTable.Load(data, hHead); if (!tables.TryGetValue(TrueTypeHeaderTable.Maxp, out var maxHeaderTable)) { throw new InvalidOperationException("The maximum profile table is required."); } // maxp tableRegister.MaximumProfileTable = BasicMaximumProfileTable.Load(data, maxHeaderTable); // post if (tables.TryGetValue(TrueTypeHeaderTable.Post, out var postscriptHeaderTable)) { tableRegister.PostScriptTable = PostScriptTable.Load(data, table, tableRegister.MaximumProfileTable); } if (!isPostScript) { if (!tables.TryGetValue(TrueTypeHeaderTable.Loca, out var indexToLocationHeaderTable)) { throw new InvalidOperationException("The location to index table is required for non-PostScript fonts."); } // loca tableRegister.IndexToLocationTable = IndexToLocationTable.Load(data, indexToLocationHeaderTable, tableRegister); if (!tables.TryGetValue(TrueTypeHeaderTable.Glyf, out var glyphHeaderTable)) { throw new InvalidOperationException("The glpyh table is required for non-PostScript fonts."); } // glyf tableRegister.GlyphDataTable = GlyphDataTable.Load(data, glyphHeaderTable, tableRegister); OptionallyParseTables(tables, data, tableRegister); } return(new TrueTypeFont(version, tables, tableRegister)); }
protected override Encoding ReadEncodingFromFont() { if (!IsEmbedded && Standard14AFM != null) { // read from AFM return(new Type1Encoding(Standard14AFM)); } else { // non-symbolic fonts don't have a built-in encoding per se, but there encoding is // assumed to be StandardEncoding by the PDF spec unless an explicit Encoding is present // which will override this anyway if (!(SymbolicFlag ?? true)) { return(StandardEncoding.Instance); } // normalise the standard 14 name, e.g "Symbol,Italic" -> "Symbol" string standard14Name = Standard14Fonts.GetMappedFontName(Name); // likewise, if the font is standard 14 then we know it's Standard Encoding if (IsStandard14 && !standard14Name.Equals("Symbol", StringComparison.Ordinal) && !standard14Name.Equals("ZapfDingbats", StringComparison.Ordinal)) { return(StandardEncoding.Instance); } // synthesize an encoding, so that getEncoding() is always usable PostScriptTable post = ttf.PostScript; Dictionary <int, string> codeToName = new Dictionary <int, string>(); for (int code = 0; code <= 256; code++) { int gid = CodeToGID(code); if (gid > 0) { string name = null; if (post != null) { name = post.GetName(gid); } if (name == null) { // GID pseudo-name name = gid.ToString(); } codeToName[code] = name; } } return(new BuiltInEncoding(codeToName)); } }
public static Font ReadFromStream(Stream stream) { var font = new Font(); var reader = new BinaryReader(stream); // Offset Table font.OffsetTable = OffsetTable.Read(reader); // Head var headTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HeadTable.Tag); stream.Seek(headTableRecord.Offset, SeekOrigin.Begin); font.HeadTable = HeadTable.Read(reader); // Horizontal Header var horizontalHeaderTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HorizontalHeaderTable.Tag); stream.Seek(horizontalHeaderTableRecord.Offset, SeekOrigin.Begin); font.HorizontalHeaderTable = HorizontalHeaderTable.Read(reader); // Maximum Profile var maximumProfileTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == MaximumProfileTableBase.Tag); stream.Seek(maximumProfileTableRecord.Offset, SeekOrigin.Begin); var maximumProfileTableVersion = Math.Round(reader.ReadFixedPointNumber(), 2); if (maximumProfileTableVersion == 0.5m) { font.MaximumProfileTable = MaximumProfileTableV0_5.Read(reader, maximumProfileTableVersion); } else if (maximumProfileTableVersion == 1.0m) { font.MaximumProfileTable = MaximumProfileTableV1.Read(reader, maximumProfileTableVersion); } // Horizontal Metrics var horizontalMetricsTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == HorizontalMetricsTable.Tag); stream.Seek(horizontalMetricsTableRecord.Offset, SeekOrigin.Begin); font.HorizontalMetricsTable = HorizontalMetricsTable.Read(reader, font.HorizontalHeaderTable.NumberOfHMetrics, font.MaximumProfileTable.NumGlyphs); // Glyph var glyphTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == GlyphTable.Tag); font.GlyphTable = new GlyphTable(reader, glyphTableRecord.Offset); // IndexLocation var indexLocationTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == IndexLocationTableBase.Tag); stream.Seek(indexLocationTableRecord.Offset, SeekOrigin.Begin); if (font.HeadTable.IndexToLocFormat == 0) { font.IndexLocationTable = IndexLocationShortFormatTable.Read(reader, font.MaximumProfileTable.NumGlyphs); } else { font.IndexLocationTable = IndexLocationLongFormatTable.Read(reader, font.MaximumProfileTable.NumGlyphs); } // PostScript var postScriptTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == PostScriptTable.Tag); stream.Seek(postScriptTableRecord.Offset, SeekOrigin.Begin); font.PostScriptTable = PostScriptTable.Read(reader); // OS/2 and Windows var os2TableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == Os2Table.Tag); stream.Seek(os2TableRecord.Offset, SeekOrigin.Begin); font.Os2Table = Os2Table.Read(reader); // CharacterMap var characterMapTableRecord = font.OffsetTable.TableRecords.Single(x => x.TableTag == CharacterMapTable.Tag); stream.Seek(characterMapTableRecord.Offset, SeekOrigin.Begin); font.CharacterMapTable = CharacterMapTable.Read(reader); return(font); }
private static TrueTypeFont ParseTables(float version, IReadOnlyDictionary <string, TrueTypeHeaderTable> tables, TrueTypeDataBytes data) { var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff); var builder = new TableRegister.Builder(); if (!tables.TryGetValue(TrueTypeHeaderTable.Head, out var table)) { throw new InvalidFontFormatException($"The {TrueTypeHeaderTable.Head} table is required."); } // head builder.HeaderTable = HeaderTable.Load(data, table); if (!tables.TryGetValue(TrueTypeHeaderTable.Hhea, out var hHead)) { throw new InvalidFontFormatException("The horizontal header table is required."); } // hhea builder.HorizontalHeaderTable = TableParser.Parse <HorizontalHeaderTable>(hHead, data, builder); if (!tables.TryGetValue(TrueTypeHeaderTable.Maxp, out var maxHeaderTable)) { throw new InvalidFontFormatException("The maximum profile table is required."); } // maxp builder.MaximumProfileTable = BasicMaximumProfileTable.Load(data, maxHeaderTable); // post if (tables.TryGetValue(TrueTypeHeaderTable.Post, out var postscriptHeaderTable)) { builder.PostScriptTable = PostScriptTable.Load(data, postscriptHeaderTable, builder.MaximumProfileTable); } if (tables.TryGetValue(TrueTypeHeaderTable.Name, out var nameTable)) { builder.NameTable = TableParser.Parse <NameTable>(nameTable, data, builder); } if (tables.TryGetValue(TrueTypeHeaderTable.Os2, out var os2Table)) { builder.Os2Table = TableParser.Parse <Os2Table>(os2Table, data, builder); } if (!isPostScript) { if (!tables.TryGetValue(TrueTypeHeaderTable.Loca, out var indexToLocationHeaderTable)) { throw new InvalidFontFormatException("The location to index table is required for non-PostScript fonts."); } // loca builder.IndexToLocationTable = IndexToLocationTable.Load(data, indexToLocationHeaderTable, builder); if (!tables.TryGetValue(TrueTypeHeaderTable.Glyf, out var glyphHeaderTable)) { throw new InvalidFontFormatException("The glyph table is required for non-PostScript fonts."); } // glyf builder.GlyphDataTable = GlyphDataTable.Load(data, glyphHeaderTable, builder); OptionallyParseTables(tables, data, builder); } return(new TrueTypeFont(version, tables, builder.Build())); }
/** * Creates a new font descriptor dictionary for the given TTF. */ private FontDescriptor CreateFontDescriptor(TrueTypeFont ttf) { FontDescriptor fd = new FontDescriptor(document, new PdfDictionary()); fd.FontName = ttf.Name; OS2WindowsMetricsTable os2 = ttf.OS2Windows; PostScriptTable post = ttf.PostScript; // Flags var flags = (FlagsEnum)0; flags |= (post.IsFixedPitch > 0 || ttf.HorizontalHeader.NumberOfHMetrics == 1) ? FlagsEnum.FixedPitch : 0; int fsSelection = os2.FsSelection; flags |= ((fsSelection & (ITALIC | OBLIQUE)) != 0) ? FlagsEnum.Italic : 0; switch (os2.FamilyClass) { case OS2WindowsMetricsTable.FAMILY_CLASS_CLAREDON_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_FREEFORM_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_MODERN_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_OLDSTYLE_SERIFS: case OS2WindowsMetricsTable.FAMILY_CLASS_SLAB_SERIFS: flags |= FlagsEnum.Serif; break; case OS2WindowsMetricsTable.FAMILY_CLASS_SCRIPTS: flags |= FlagsEnum.Script; break; default: break; } fd.FontWeight = os2.WeightClass; flags |= FlagsEnum.Symbolic; flags &= ~FlagsEnum.Nonsymbolic; fd.Flags = flags; // ItalicAngle fd.ItalicAngle = post.ItalicAngle; // FontBBox HeaderTable header = ttf.Header; float scaling = 1000f / header.UnitsPerEm; var skRect = new SKRect( header.XMin * scaling, header.YMin * scaling, header.XMax * scaling, header.YMax * scaling ); Rectangle rect = new Rectangle(skRect); fd.FontBBox = rect; // Ascent, Descent HorizontalHeaderTable hHeader = ttf.HorizontalHeader; fd.Ascent = hHeader.Ascender * scaling; fd.Descent = hHeader.Descender * scaling; // CapHeight, XHeight if (os2.Version >= 1.2) { fd.CapHeight = os2.CapHeight * scaling; fd.XHeight = os2.Height * scaling; } else { var capHPath = ttf.GetPath("H"); if (capHPath != null) { fd.CapHeight = (float)Math.Round(capHPath.Bounds.Bottom * scaling); } else { // estimate by summing the typographical +ve ascender and -ve descender fd.CapHeight = os2.TypoAscender + (os2.TypoDescender * scaling); } var xPath = ttf.GetPath("x"); if (xPath != null) { fd.XHeight = (float)Math.Round(xPath.Bounds.Bottom * scaling); } else { // estimate by halving the typographical ascender fd.XHeight = os2.TypoAscender / (2.0f * scaling); } } // StemV - there's no true TTF equivalent of this, so we estimate it fd.StemV = skRect.Width * .13f; return(fd); }