From 63b118b141aa0814d9d832f1701e36a18e7de9c5 Mon Sep 17 00:00:00 2001 From: Eliot Jones Date: Tue, 7 Jan 2020 16:49:21 +0000 Subject: [PATCH] handle type1 fonts disguised as truetype if the font descriptor uses the fromsubtype flag the actual type of the font can differ from that specified in the font dictionary. in this case a truetype font actually contains a type1c, compact font format, font. in this case we fall back to using the type1 parser. also handles a closesubpath command appearing without any path construction operators. --- .../PathConstruction/CloseSubpath.cs | 2 +- .../Parser/PdfDocumentFactory.cs | 7 ++- .../Parser/Handlers/TrueTypeFontHandler.cs | 56 ++++++++++++++----- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs index 8abe0429..795eefda 100644 --- a/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs +++ b/src/UglyToad.PdfPig/Graphics/Operations/PathConstruction/CloseSubpath.cs @@ -29,7 +29,7 @@ /// public void Run(IOperationContext operationContext) { - operationContext.CurrentPath.ClosePath(); + operationContext.CurrentPath?.ClosePath(); } /// diff --git a/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs b/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs index 86ed1667..7ee84823 100644 --- a/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs +++ b/src/UglyToad.PdfPig/Parser/PdfDocumentFactory.cs @@ -122,10 +122,13 @@ var cidFontFactory = new CidFontFactory(pdfScanner, fontDescriptorFactory, filterProvider); var encodingReader = new EncodingReader(pdfScanner); + var type1Handler = new Type1FontHandler(pdfScanner, filterProvider, fontDescriptorFactory, encodingReader); + var fontFactory = new FontFactory(log, new Type0FontHandler(cidFontFactory, filterProvider, pdfScanner), - new TrueTypeFontHandler(log, pdfScanner, filterProvider, fontDescriptorFactory, encodingReader, new SystemFontFinder()), - new Type1FontHandler(pdfScanner, filterProvider, fontDescriptorFactory, encodingReader), + new TrueTypeFontHandler(log, pdfScanner, filterProvider, fontDescriptorFactory, encodingReader, new SystemFontFinder(), + type1Handler), + type1Handler, new Type3FontHandler(pdfScanner, filterProvider, encodingReader)); var resourceContainer = new ResourceStore(pdfScanner, fontFactory); diff --git a/src/UglyToad.PdfPig/PdfFonts/Parser/Handlers/TrueTypeFontHandler.cs b/src/UglyToad.PdfPig/PdfFonts/Parser/Handlers/TrueTypeFontHandler.cs index a2efd52c..f36655c8 100644 --- a/src/UglyToad.PdfPig/PdfFonts/Parser/Handlers/TrueTypeFontHandler.cs +++ b/src/UglyToad.PdfPig/PdfFonts/Parser/Handlers/TrueTypeFontHandler.cs @@ -8,11 +8,13 @@ using Filters; using Fonts; using Fonts.AdobeFontMetrics; + using Fonts.CompactFontFormat; using Fonts.Encodings; using Fonts.Standard14Fonts; using Fonts.SystemFonts; using Fonts.TrueType; using Fonts.TrueType.Parser; + using Fonts.Type1; using Logging; using Parts; using PdfPig.Parser.Parts; @@ -29,17 +31,20 @@ private readonly FontDescriptorFactory fontDescriptorFactory; private readonly IEncodingReader encodingReader; private readonly ISystemFontFinder systemFontFinder; + private readonly IFontHandler type1FontHandler; public TrueTypeFontHandler(ILog log, IPdfTokenScanner pdfScanner, IFilterProvider filterProvider, FontDescriptorFactory fontDescriptorFactory, IEncodingReader encodingReader, - ISystemFontFinder systemFontFinder) + ISystemFontFinder systemFontFinder, + IFontHandler type1FontHandler) { this.log = log; this.filterProvider = filterProvider; this.fontDescriptorFactory = fontDescriptorFactory; this.encodingReader = encodingReader; this.systemFontFinder = systemFontFinder; + this.type1FontHandler = type1FontHandler; this.pdfScanner = pdfScanner; } @@ -95,7 +100,12 @@ var descriptor = FontDictionaryAccessHelper.GetFontDescriptor(pdfScanner, fontDescriptorFactory, dictionary, isLenientParsing); - var font = ParseTrueTypeFont(descriptor); + var font = ParseTrueTypeFont(descriptor, out var actualHandler); + + if (font == null && actualHandler != null) + { + return actualHandler.Generate(dictionary, isLenientParsing); + } var name = FontDictionaryAccessHelper.GetName(pdfScanner, dictionary, descriptor, isLenientParsing); @@ -113,7 +123,7 @@ } Encoding encoding = encodingReader.Read(dictionary, isLenientParsing, descriptor); - + if (encoding == null && font?.TableRegister?.CMapTable != null && font.TableRegister.PostScriptTable?.GlyphNames != null) { @@ -145,8 +155,10 @@ return new TrueTypeSimpleFont(name, descriptor, toUnicodeCMap, encoding, font, firstCharacter, widths); } - private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor) + private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor, out IFontHandler actualHandler) { + actualHandler = null; + if (descriptor.FontFile == null) { try @@ -158,23 +170,41 @@ { log.Error($"Failed finding system font by name: {descriptor.FontName}.", ex); } - // TODO: check if this font is present on the host OS. See: FileSystemFontProvider.java - return null; - } - if (descriptor.FontFile.FileType != DescriptorFontFile.FontFileType.TrueType) - { - throw new InvalidFontFormatException( - $"Expected a TrueType font in the TrueType font descriptor, instead it was {descriptor.FontFile.FileType}."); + return null; } try { - var fontFileStream = DirectObjectFinder.Get(descriptor.FontFile.ObjectKey, pdfScanner); - + var fontFile = fontFileStream.Decode(filterProvider); + if (descriptor.FontFile.FileType == DescriptorFontFile.FontFileType.FromSubtype) + { + var shouldThrow = true; + + if (fontFileStream.StreamDictionary.TryGet(NameToken.Subtype, pdfScanner, out NameToken subTypeName)) + { + if (subTypeName == NameToken.Type1C) + { + actualHandler = type1FontHandler; + return null; + } + + if (subTypeName == NameToken.OpenType) + { + shouldThrow = false; + } + } + + if (shouldThrow) + { + throw new InvalidFontFormatException( + $"Expected a TrueType font in the TrueType font descriptor, instead it was {descriptor.FontFile.FileType}."); + } + } + var font = TrueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(fontFile))); return font;