diff --git a/src/UglyToad.PdfPig.Fonts/TrueType/Parser/TrueTypeFontParser.cs b/src/UglyToad.PdfPig.Fonts/TrueType/Parser/TrueTypeFontParser.cs index d2e11b344..8f57a032e 100644 --- a/src/UglyToad.PdfPig.Fonts/TrueType/Parser/TrueTypeFontParser.cs +++ b/src/UglyToad.PdfPig.Fonts/TrueType/Parser/TrueTypeFontParser.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Tables; + using UglyToad.PdfPig.Fonts.CompactFontFormat; /// /// Parses TrueType fonts. @@ -59,7 +60,36 @@ public static TrueTypeFont Parse(TrueTypeDataBytes data) private static TrueTypeFont ParseTables(float version, IReadOnlyDictionary tables, TrueTypeDataBytes data) { - var isPostScript = tables.ContainsKey(TrueTypeHeaderTable.Cff); + bool isPostScript = false; + CompactFontFormatFontCollection? cffFontCollection = null; + + if (tables.TryGetValue(TrueTypeHeaderTable.Cff, out var cffTable)) + { + isPostScript = true; + try + { + /* + * The presence of a CFF (Compact Font Format) table in a TrueType font creates a hybrid situation where the font + * container uses TrueType structure but contains PostScript-based glyph descriptions. According to the OpenType + * specification, when a TrueType font contains a CFF table instead of a traditional glyf table, it indicates + * "an OpenType font with PostScript outlines". This creates what's known as an OpenType CFF font, which uses + * PostScript Type 2 charstrings for glyph descriptions rather than TrueType quadratic curves. + * + * This is to fix P2P-33713919.pdf + * See https://github.com/BobLd/PdfPig.Rendering.Skia/issues/46 + * TODO - Add test coverage and need to review if the logic belongs here + */ + + data.Seek(cffTable.Offset); + var buffer = data.ReadByteArray((int)cffTable.Length); + cffFontCollection = CompactFontFormatParser.Parse(new CompactFontFormatData(buffer)); + } + catch (Exception e) + { + System.Diagnostics.Debug.WriteLine(e); + // Ignore + } + } var builder = new TableRegister.Builder(); @@ -102,7 +132,7 @@ private static TrueTypeFont ParseTables(float version, IReadOnlyDictionary(os2Table, data, builder); } - + if (!isPostScript) { if (!tables.TryGetValue(TrueTypeHeaderTable.Loca, out var indexToLocationHeaderTable)) @@ -125,7 +155,7 @@ private static TrueTypeFont ParseTables(float version, IReadOnlyDictionary /// A TrueType font. @@ -54,17 +55,33 @@ public sealed class TrueTypeFont /// public int NumberOfTables { get; } + // TODO - It would be better to use 'PdfCidCompactFontFormatFont' but the class is not accessible from here. + private readonly CompactFontFormatFontCollection? cffFontCollection; + /// /// Create a new . /// - internal TrueTypeFont(float version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister) + internal TrueTypeFont(float version, IReadOnlyDictionary tableHeaders, TableRegister tableRegister, CompactFontFormatFontCollection? cffFontCollection) { Version = version; TableHeaders = tableHeaders ?? throw new ArgumentNullException(nameof(tableHeaders)); TableRegister = tableRegister ?? throw new ArgumentNullException(nameof(tableRegister)); NumberOfTables = tableHeaders.Count; - if (TableRegister.CMapTable != null) + /* + * The presence of a CFF (Compact Font Format) table in a TrueType font creates a hybrid situation where the font + * container uses TrueType structure but contains PostScript-based glyph descriptions. According to the OpenType + * specification, when a TrueType font contains a CFF table instead of a traditional glyf table, it indicates + * "an OpenType font with PostScript outlines". This creates what's known as an OpenType CFF font, which uses + * PostScript Type 2 charstrings for glyph descriptions rather than TrueType quadratic curves. + * + * This is to fix P2P-33713919.pdf + * See https://github.com/BobLd/PdfPig.Rendering.Skia/issues/46 + * TODO - Add test coverage and need to review if the logic belongs here + */ + this.cffFontCollection = cffFontCollection; + + if (TableRegister.CMapTable is not null) { const int encodingSymbol = 0; const int encodingUnicode = 1; @@ -72,19 +89,19 @@ internal TrueTypeFont(float version, IReadOnlyDictionary characterCodeTo { boundingBox = default(PdfRectangle); - if (TableRegister.GlyphTable == null) + if (TableRegister.GlyphTable is null) { + if (cffFontCollection is not null) + { + /* + * The presence of a CFF (Compact Font Format) table in a TrueType font creates a hybrid situation where the font + * container uses TrueType structure but contains PostScript-based glyph descriptions. According to the OpenType + * specification, when a TrueType font contains a CFF table instead of a traditional glyf table, it indicates + * "an OpenType font with PostScript outlines". This creates what's known as an OpenType CFF font, which uses + * PostScript Type 2 charstrings for glyph descriptions rather than TrueType quadratic curves. + * + * This is to fix P2P-33713919.pdf + * See https://github.com/BobLd/PdfPig.Rendering.Skia/issues/46 + * TODO - Add test coverage and need to review if the logic belongs here + */ + + var name = cffFontCollection.FirstFont.GetCharacterName(characterCode, true); // TODO cid? + if (string.IsNullOrEmpty(name)) + { + return false; + } + + var bbox = cffFontCollection.FirstFont.GetCharacterBoundingBox(name); + if (bbox.HasValue) + { + boundingBox = bbox.Value; + return true; + } + } + return false; } @@ -143,8 +188,30 @@ public bool TryGetPath(int characterCode, Func characterCodeToGlyphId { path = null; - if (TableRegister.GlyphTable == null) + if (TableRegister.GlyphTable is null) { + if (cffFontCollection is not null) + { + /* + * The presence of a CFF (Compact Font Format) table in a TrueType font creates a hybrid situation where the font + * container uses TrueType structure but contains PostScript-based glyph descriptions. According to the OpenType + * specification, when a TrueType font contains a CFF table instead of a traditional glyf table, it indicates + * "an OpenType font with PostScript outlines". This creates what's known as an OpenType CFF font, which uses + * PostScript Type 2 charstrings for glyph descriptions rather than TrueType quadratic curves. + * + * This is to fix P2P-33713919.pdf + * See https://github.com/BobLd/PdfPig.Rendering.Skia/issues/46 + * TODO - Add test coverage and need to review if the logic belongs here + */ + + var name = cffFontCollection.FirstFont.GetCharacterName(characterCode, true); + if (string.IsNullOrEmpty(name)) + { + return false; + } + return cffFontCollection.FirstFont.TryGetPath(name, out path); + } + return false; } @@ -188,7 +255,7 @@ private bool TryGetBoundingAdvancedWidthByIndex(int index, out double width) { width = 0; - if (TableRegister.HorizontalMetricsTable == null) + if (TableRegister.HorizontalMetricsTable is null) { return false; } @@ -210,7 +277,7 @@ private bool TryGetGlyphIndex(int characterIdentifier, Func character return true; } - if (TableRegister.CMapTable == null) + if (TableRegister.CMapTable is null) { return false; }