コード例 #1
0
        public void ParseAndadaRegular()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("Andada-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            var name = font.Name;

            Assert.Equal("Andada Regular", name);

            Assert.Equal(1.001999, font.TableRegister.HeaderTable.Revision, new DoubleComparer(5));

            Assert.Equal(11, font.TableRegister.HeaderTable.Flags);

            Assert.Equal(1000, font.TableRegister.HeaderTable.UnitsPerEm);

            Assert.Equal(2011, font.TableRegister.HeaderTable.Created.Year);
            Assert.Equal(9, font.TableRegister.HeaderTable.Created.Month);
            Assert.Equal(30, font.TableRegister.HeaderTable.Created.Day);

            Assert.Equal(2017, font.TableRegister.HeaderTable.Modified.Year);
            Assert.Equal(5, font.TableRegister.HeaderTable.Modified.Month);
            Assert.Equal(4, font.TableRegister.HeaderTable.Modified.Day);
        }
コード例 #2
0
ファイル: Os2TableTests.cs プロジェクト: zyj0021/PdfPig
        public void WritesSameTableAsRead(string fontFile)
        {
            var fontBytes = TrueTypeTestHelper.GetFileBytes(fontFile);

            var parsed = TrueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(fontBytes)));

            var os2       = parsed.TableRegister.Os2Table;
            var os2Header = parsed.TableHeaders.Single(x => x.Value.Tag == TrueTypeHeaderTable.Os2);

            var os2InputBytes = fontBytes.Skip((int)os2Header.Value.Offset).Take((int)os2Header.Value.Length).ToArray();

            using (var stream = new MemoryStream())
            {
                os2.Write(stream);

                var result = stream.ToArray();

                Assert.Equal(os2InputBytes.Length, result.Length);

                for (var i = 0; i < os2InputBytes.Length; i++)
                {
                    var expected = os2InputBytes[i];
                    var actual   = result[i];

                    Assert.Equal(expected, actual);
                }
            }
        }
コード例 #3
0
        public SystemFontFinder(TrueTypeFontParser trueTypeFontParser)
        {
            this.trueTypeFontParser = trueTypeFontParser;

            ISystemFontLister lister;

#if NETSTANDARD2_0
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                lister = new WindowsSystemFontLister();
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                lister = new MacSystemFontLister();
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                lister = new LinuxSystemFontLister();
            }
            else
            {
                throw new NotSupportedException($"Unsupported operating system: {RuntimeInformation.OSDescription}.");
            }
#else
            lister = new WindowsSystemFontLister();
#endif

            availableFonts = new Lazy <IReadOnlyList <SystemFontRecord> >(() => lister.GetAllFonts().ToList());
        }
コード例 #4
0
        private ICidFontProgram ReadDescriptorFile(FontDescriptor descriptor)
        {
            if (descriptor?.FontFile == null)
            {
                return(null);
            }

            var fontFileStream = DirectObjectFinder.Get <StreamToken>(descriptor.FontFile.ObjectKey, pdfScanner);

            if (fontFileStream == null)
            {
                return(null);
            }

            var fontFile = fontFileStream.Decode(filterProvider, pdfScanner);

            switch (descriptor.FontFile.FileType)
            {
            case DescriptorFontFile.FontFileType.TrueType:
            {
                var input = new TrueTypeDataBytes(new ByteArrayInputBytes(fontFile));
                var ttf   = TrueTypeFontParser.Parse(input);
                return(new PdfCidTrueTypeFont(ttf));
            }

            case DescriptorFontFile.FontFileType.FromSubtype:
            {
                if (!DirectObjectFinder.TryGet(descriptor.FontFile.ObjectKey, pdfScanner, out StreamToken str))
                {
                    throw new NotSupportedException("Cannot read CID font from subtype.");
                }

                if (!str.StreamDictionary.TryGet(NameToken.Subtype, out NameToken subtypeName))
                {
                    throw new PdfDocumentFormatException($"The font file stream did not contain a subtype entry: {str.StreamDictionary}.");
                }

                if (subtypeName == NameToken.CidFontType0C ||
                    subtypeName == NameToken.Type1C)
                {
                    var bytes = str.Decode(filterProvider, pdfScanner);
                    var font  = CompactFontFormatParser.Parse(new CompactFontFormatData(bytes));
                    return(new PdfCidCompactFontFormatFont(font));
                }

                if (subtypeName == NameToken.OpenType)
                {
                    var bytes = str.Decode(filterProvider, pdfScanner);
                    var ttf   = TrueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(bytes)));
                    return(new PdfCidTrueTypeFont(ttf));
                }

                throw new PdfDocumentFormatException($"Unexpected subtype for CID font: {subtypeName}.");
            }

            default:
                throw new NotSupportedException("Currently only TrueType fonts are supported.");
            }
        }
コード例 #5
0
ファイル: CidFontFactory.cs プロジェクト: lulzzz/PdfPig
 public CidFontFactory(IPdfTokenScanner pdfScanner, FontDescriptorFactory descriptorFactory, TrueTypeFontParser trueTypeFontParser,
                       IFilterProvider filterProvider)
 {
     this.descriptorFactory  = descriptorFactory;
     this.trueTypeFontParser = trueTypeFontParser;
     this.filterProvider     = filterProvider;
     this.pdfScanner         = pdfScanner;
 }
コード例 #6
0
ファイル: CidFontFactory.cs プロジェクト: AnilAwadh/Pdf
 public CidFontFactory(FontDescriptorFactory descriptorFactory, TrueTypeFontParser trueTypeFontParser,
                       IPdfObjectParser pdfObjectParser,
                       IFilterProvider filterProvider)
 {
     this.descriptorFactory  = descriptorFactory;
     this.trueTypeFontParser = trueTypeFontParser;
     this.pdfObjectParser    = pdfObjectParser;
     this.filterProvider     = filterProvider;
 }
コード例 #7
0
        private bool TryReadFile(string fileName, bool readNameFirst, string fontName, out TrueTypeFont font)
        {
            font = null;

            var bytes = File.ReadAllBytes(fileName);

            var data = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            if (readNameFirst)
            {
                var name = TrueTypeFontParser.GetNameTable(data);

                if (name == null)
                {
                    lock (readFilesLock)
                    {
                        readFiles.Add(fileName);
                    }

                    return(false);
                }

                var fontNameFromFile = name.GetPostscriptName() ?? name.FontName;

                nameToFileNameMap.TryAdd(fontNameFromFile, fileName);

                if (!string.Equals(fontNameFromFile, fontName, StringComparison.OrdinalIgnoreCase))
                {
                    lock (readFilesLock)
                    {
                        readFiles.Add(fileName);
                    }

                    return(false);
                }
            }

            data.Seek(0);
            font = TrueTypeFontParser.Parse(data);
            var psName = font.TableRegister.NameTable?.GetPostscriptName() ?? font.Name;

            lock (CacheLock)
            {
                if (!Cache.ContainsKey(psName))
                {
                    Cache[psName] = font;
                }
            }

            lock (readFilesLock)
            {
                readFiles.Add(fileName);
            }

            return(true);
        }
コード例 #8
0
        public void ParsePMingLiU()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("PMingLiU");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.NotNull(font);
        }
コード例 #9
0
        public void ParseSimpleGoogleDocssGautmi()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("google-simple-doc");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.NotNull(font.TableRegister.HeaderTable);
        }
コード例 #10
0
        public void RobotoHeaderReadCorrectly()
        {
            var data = new[]
            {
                // key, offset, length, checksum
                "DSIG 158596 8 1",
                "GDEF 316 72 408950881",
                "GPOS 388 35744 355098641",
                "GSUB 36132 662 3357985284",
                "OS/2 36796 96 3097700805",
                "cmap 36892 1750 298470964",
                "cvt  156132 38 119085513",
                "fpgm 156172 2341 2494100564",
                "gasp 156124 8 16",
                "glyf 38644 88820 3302131736",
                "head 127464 54 346075833",
                "hhea 127520 36 217516755",
                "hmtx 127556 4148 1859679943",
                "kern 131704 12306 2002873469",
                "loca 144012 2076 77421448",
                "maxp 146088 32 89459325",
                "name 146120 830 44343214",
                "post 146952 9171 3638780613",
                "prep 158516 77 251381919"
            };

            var bytes = TrueTypeTestHelper.GetFileBytes("Roboto-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            foreach (var s in data)
            {
                var parts = s.Split(' ', StringSplitOptions.RemoveEmptyEntries);

                var name = parts[0];

                if (name == "cvt")
                {
                    name = "cvt ";
                }

                var match = font.TableHeaders[name];

                var offset   = long.Parse(parts[1], CultureInfo.InvariantCulture);
                var length   = long.Parse(parts[2], CultureInfo.InvariantCulture);
                var checksum = long.Parse(parts[3], CultureInfo.InvariantCulture);

                Assert.Equal(offset, match.Offset);
                Assert.Equal(length, match.Length);
                Assert.Equal(checksum, match.CheckSum);
            }
        }
コード例 #11
0
ファイル: TrueTypeFontHandler.cs プロジェクト: AnilAwadh/Pdf
 public TrueTypeFontHandler(IPdfObjectParser pdfObjectParser, IFilterProvider filterProvider,
                            CMapCache cMapCache,
                            FontDescriptorFactory fontDescriptorFactory,
                            TrueTypeFontParser trueTypeFontParser)
 {
     this.pdfObjectParser       = pdfObjectParser;
     this.filterProvider        = filterProvider;
     this.cMapCache             = cMapCache;
     this.fontDescriptorFactory = fontDescriptorFactory;
     this.trueTypeFontParser    = trueTypeFontParser;
 }
コード例 #12
0
        public void ParseIssue258CorruptNameTable()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("issue-258-corrupt-name-table");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.NotNull(font);
            Assert.NotNull(font.TableRegister.NameTable);
            Assert.NotEmpty(font.TableRegister.NameTable.NameRecords);
        }
コード例 #13
0
ファイル: TrueTypeFontHandler.cs プロジェクト: Omsaaf/PdfPig
 public TrueTypeFontHandler(ILog log, IPdfTokenScanner pdfScanner, IFilterProvider filterProvider,
                            CMapCache cMapCache,
                            FontDescriptorFactory fontDescriptorFactory,
                            TrueTypeFontParser trueTypeFontParser,
                            IEncodingReader encodingReader)
 {
     this.log                   = log;
     this.filterProvider        = filterProvider;
     this.cMapCache             = cMapCache;
     this.fontDescriptorFactory = fontDescriptorFactory;
     this.trueTypeFontParser    = trueTypeFontParser;
     this.encodingReader        = encodingReader;
     this.pdfScanner            = pdfScanner;
 }
コード例 #14
0
 /// <summary>
 /// Adds a TrueType font to the builder so that pages in this document can use it.
 /// </summary>
 /// <param name="fontFileBytes">The bytes of a TrueType font.</param>
 /// <returns>An identifier which can be passed to <see cref="PdfPageBuilder.AddText"/>.</returns>
 public AddedFont AddTrueTypeFont(IReadOnlyList <byte> fontFileBytes)
 {
     try
     {
         var font  = TrueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(fontFileBytes)));
         var id    = Guid.NewGuid();
         var added = new AddedFont(id, context.ReserveObjectNumber());
         fonts[id] = new FontStored(added, new TrueTypeWritingFont(font, fontFileBytes));
         return(added);
     }
     catch (Exception ex)
     {
         throw new InvalidOperationException("Writing only supports TrueType fonts, please provide a valid TrueType font.", ex);
     }
 }
コード例 #15
0
        public void ParseRegularRoboto()
        {
            var bytes = TrueTypeTestHelper.GetFileBytes("Roboto-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            Assert.Equal(1, font.Version);

            Assert.Equal(1, font.TableRegister.HeaderTable.Version);
            Assert.Equal(1, font.TableRegister.HeaderTable.Revision);

            Assert.Equal(1142661421u, font.TableRegister.HeaderTable.CheckSumAdjustment);
            Assert.Equal(1594834165u, font.TableRegister.HeaderTable.MagicNumber);

            Assert.Equal(9, font.TableRegister.HeaderTable.Flags);

            Assert.Equal(2048, font.TableRegister.HeaderTable.UnitsPerEm);

            Assert.Equal(2008, font.TableRegister.HeaderTable.Created.Year);
            Assert.Equal(09, font.TableRegister.HeaderTable.Created.Month);
            Assert.Equal(12, font.TableRegister.HeaderTable.Created.Day);
            Assert.Equal(12, font.TableRegister.HeaderTable.Created.Hour);
            Assert.Equal(29, font.TableRegister.HeaderTable.Created.Minute);
            Assert.Equal(34, font.TableRegister.HeaderTable.Created.Second);

            Assert.Equal(2011, font.TableRegister.HeaderTable.Modified.Year);
            Assert.Equal(11, font.TableRegister.HeaderTable.Modified.Month);
            Assert.Equal(30, font.TableRegister.HeaderTable.Modified.Day);
            Assert.Equal(5, font.TableRegister.HeaderTable.Modified.Hour);
            Assert.Equal(13, font.TableRegister.HeaderTable.Modified.Minute);
            Assert.Equal(10, font.TableRegister.HeaderTable.Modified.Second);

            Assert.Equal(-980, font.TableRegister.HeaderTable.Bounds.Left);
            Assert.Equal(-555, font.TableRegister.HeaderTable.Bounds.Bottom);

            Assert.Equal(2396, font.TableRegister.HeaderTable.Bounds.Right);
            Assert.Equal(2163, font.TableRegister.HeaderTable.Bounds.Top);

            Assert.Equal(HeaderTable.HeaderMacStyle.None, font.TableRegister.HeaderTable.MacStyle);
            Assert.Equal(9, font.TableRegister.HeaderTable.LowestRecommendedPpem);

            Assert.Equal(HeaderTable.FontDirection.StronglyLeftToRightWithNeutrals, font.TableRegister.HeaderTable.FontDirectionHint);

            Assert.Equal(IndexToLocationTable.EntryFormat.Short, font.TableRegister.HeaderTable.IndexToLocFormat);
            Assert.Equal(0, font.TableRegister.HeaderTable.GlyphDataFormat);
        }
コード例 #16
0
        private void Run(byte[] bytes, bool checkHeaderChecksum, bool checkWholeFileChecksum)
        {
            var inputBytes = new ByteArrayInputBytes(bytes);

            var font = TrueTypeFontParser.Parse(new TrueTypeDataBytes(inputBytes));

            inputBytes = new ByteArrayInputBytes(bytes);

            foreach (var header in font.TableHeaders)
            {
                // Acts as the whole table checksum
                if (header.Key == "head")
                {
                    if (checkHeaderChecksum)
                    {
                        var headerChecksum = TrueTypeChecksumCalculator.Calculate(inputBytes, header.Value);

                        Assert.Equal(header.Value.CheckSum, headerChecksum);
                    }

                    continue;
                }

                var input = bytes.Skip((int)header.Value.Offset).Take((int)header.Value.Length);

                var checksum = TrueTypeChecksumCalculator.Calculate(input);

                Assert.Equal(header.Value.CheckSum, checksum);

                var checksumByTable = TrueTypeChecksumCalculator.Calculate(inputBytes, header.Value);

                Assert.Equal(header.Value.CheckSum, checksumByTable);
            }

            if (checkWholeFileChecksum)
            {
                var headerActual       = font.TableHeaders["head"];
                var wholeFontChecksum  = TrueTypeChecksumCalculator.CalculateWholeFontChecksum(inputBytes, headerActual);
                var adjustment         = 0xB1B0AFBA - wholeFontChecksum;
                var adjustmentRecorded = font.TableRegister.HeaderTable.CheckSumAdjustment;

                Assert.Equal(adjustmentRecorded, adjustment);

                var expectedWholeFontChecksum = 0xB1B0AFBA - adjustmentRecorded;

                Assert.Equal(expectedWholeFontChecksum, wholeFontChecksum);
            }
        }
コード例 #17
0
        /// <summary>
        /// Determines whether the bytes of the TrueType font file provided can be used in a PDF document.
        /// </summary>
        /// <param name="fontFileBytes">The bytes of a TrueType font file.</param>
        /// <param name="reasons">Any reason messages explaining why the file can't be used, if applicable.</param>
        /// <returns><see langword="true"/> if the file can be used, <see langword="false"/> otherwise.</returns>
        public bool CanUseTrueTypeFont(IReadOnlyList <byte> fontFileBytes, out IReadOnlyList <string> reasons)
        {
            var reasonsMutable = new List <string>();

            reasons = reasonsMutable;
            try
            {
                if (fontFileBytes == null)
                {
                    reasonsMutable.Add("Provided bytes were null.");
                    return(false);
                }

                if (fontFileBytes.Count == 0)
                {
                    reasonsMutable.Add("Provided bytes were empty.");
                    return(false);
                }

                var font = TrueTypeFontParser.Parse(new TrueTypeDataBytes(new ByteArrayInputBytes(fontFileBytes)));

                if (font.TableRegister.CMapTable == null)
                {
                    reasonsMutable.Add("The provided font did not contain a cmap table, used to map character codes to glyph codes.");
                    return(false);
                }

                if (font.TableRegister.Os2Table == null)
                {
                    reasonsMutable.Add("The provided font did not contain an OS/2 table, used to fill in the font descriptor dictionary.");
                    return(false);
                }

                if (font.TableRegister.PostScriptTable == null)
                {
                    reasonsMutable.Add("The provided font did not contain a post PostScript table, used to map character codes to glyph codes.");
                    return(false);
                }

                return(true);
            }
            catch (Exception ex)
            {
                reasonsMutable.Add(ex.Message);
                return(false);
            }
        }
コード例 #18
0
        public void ReadsRobotoGlyphSizesCorrectly()
        {
            var regex = new Regex(@"\?: Width (?<width>\d+), Height: (?<height>\d+), Points: (?<points>\d+)");

            var bytes = TrueTypeTestHelper.GetFileBytes("Roboto-Regular");

            var input = new TrueTypeDataBytes(new ByteArrayInputBytes(bytes));

            var font = TrueTypeFontParser.Parse(input);

            var robotoGlyphs = Encoding.ASCII.GetString(TrueTypeTestHelper.GetFileBytes("Roboto-Regular.GlyphData.txt"));
            var lines        = robotoGlyphs.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);

            for (var i = 0; i < lines.Length; i++)
            {
                var match = regex.Match(lines[i]);

                var width  = double.Parse(match.Groups["width"].Value, CultureInfo.InvariantCulture);
                var height = double.Parse(match.Groups["height"].Value, CultureInfo.InvariantCulture);
                var points = int.Parse(match.Groups["points"].Value, CultureInfo.InvariantCulture);

                var glyph = font.TableRegister.GlyphTable.Glyphs[i];

                // Vendor data ignores the empty glyph bounds.
                if (width == 0 && height == 0)
                {
                    continue;
                }

                if (i != 30)
                {
                    Assert.Equal(width, glyph.Bounds.Width);
                }

                Assert.Equal(height, glyph.Bounds.Height);
                Assert.Equal(points, glyph.Points.Length);
            }
        }
コード例 #19
0
        private static PdfDocument OpenDocument(IInputBytes inputBytes, ISeekableTokenScanner scanner, IContainer container, bool isLenientParsing, string password)
        {
            var log            = container.Get <ILog>();
            var filterProvider = container.Get <IFilterProvider>();
            var catalogFactory = new CatalogFactory();
            var cMapCache      = new CMapCache(new CMapParser());

            CrossReferenceTable crossReferenceTable = null;

            var bruteForceSearcher = new BruteForceSearcher(inputBytes);
            var xrefValidator      = new XrefOffsetValidator(log);
            var objectChecker      = new XrefCosOffsetChecker(log, bruteForceSearcher);

            // We're ok with this since our intent is to lazily load the cross reference table.
            // ReSharper disable once AccessToModifiedClosure
            var locationProvider = new ObjectLocationProvider(() => crossReferenceTable, bruteForceSearcher);
            var pdfScanner       = new PdfTokenScanner(inputBytes, locationProvider, filterProvider, NoOpEncryptionHandler.Instance);

            var crossReferenceStreamParser = new CrossReferenceStreamParser(filterProvider);
            var crossReferenceParser       = new CrossReferenceParser(log, xrefValidator, objectChecker, crossReferenceStreamParser, new CrossReferenceTableParser());

            var version = FileHeaderParser.Parse(scanner, isLenientParsing, log);

            var crossReferenceOffset = container.Get <FileTrailerParser>().GetFirstCrossReferenceOffset(inputBytes, scanner, isLenientParsing);

            // TODO: make this use the scanner.
            var validator = new CrossReferenceOffsetValidator(xrefValidator);

            crossReferenceOffset = validator.Validate(crossReferenceOffset, scanner, inputBytes, isLenientParsing);

            crossReferenceTable = crossReferenceParser.Parse(inputBytes, isLenientParsing, crossReferenceOffset, pdfScanner, scanner);

            var trueTypeFontParser           = new TrueTypeFontParser();
            var fontDescriptorFactory        = new FontDescriptorFactory();
            var compactFontFormatIndexReader = new CompactFontFormatIndexReader();
            var compactFontFormatParser      = new CompactFontFormatParser(new CompactFontFormatIndividualFontParser(compactFontFormatIndexReader, new CompactFontFormatTopLevelDictionaryReader(),
                                                                                                                     new CompactFontFormatPrivateDictionaryReader()), compactFontFormatIndexReader);

            var rootDictionary = ParseTrailer(crossReferenceTable, isLenientParsing, pdfScanner, out var encryptionDictionary);

            var encryptionHandler = encryptionDictionary != null ? (IEncryptionHandler) new EncryptionHandler(encryptionDictionary, crossReferenceTable.Trailer, password ?? string.Empty)
                : NoOpEncryptionHandler.Instance;

            pdfScanner.UpdateEncryptionHandler(encryptionHandler);

            var cidFontFactory = new CidFontFactory(pdfScanner, fontDescriptorFactory, trueTypeFontParser, compactFontFormatParser, filterProvider);
            var encodingReader = new EncodingReader(pdfScanner);

            var fontFactory = new FontFactory(log, new Type0FontHandler(cidFontFactory,
                                                                        cMapCache,
                                                                        filterProvider, pdfScanner),
                                              new TrueTypeFontHandler(log, pdfScanner, filterProvider, cMapCache, fontDescriptorFactory, trueTypeFontParser, encodingReader, new SystemFontFinder(new TrueTypeFontParser())),
                                              new Type1FontHandler(pdfScanner, cMapCache, filterProvider, fontDescriptorFactory, encodingReader,
                                                                   new Type1FontParser(new Type1EncryptedPortionParser()), compactFontFormatParser),
                                              new Type3FontHandler(pdfScanner, cMapCache, filterProvider, encodingReader));

            var resourceContainer = new ResourceContainer(pdfScanner, fontFactory);

            var pageFactory = new PageFactory(pdfScanner, resourceContainer, filterProvider,
                                              new PageContentParser(new ReflectionGraphicsStateOperationFactory()),
                                              new XObjectFactory(), log);
            var informationFactory = new DocumentInformationFactory();

            var information = informationFactory.Create(pdfScanner, crossReferenceTable.Trailer);

            var catalog = catalogFactory.Create(pdfScanner, rootDictionary);

            var caching = new ParsingCachingProviders(bruteForceSearcher, resourceContainer);

            var acroFormFactory = new AcroFormFactory(pdfScanner, filterProvider);

            return(new PdfDocument(log, inputBytes, version, crossReferenceTable, isLenientParsing, caching, pageFactory, catalog, information,
                                   encryptionDictionary,
                                   pdfScanner,
                                   filterProvider,
                                   acroFormFactory));
        }
コード例 #20
0
        private TrueTypeFont ParseTrueTypeFont(FontDescriptor descriptor, out IFontHandler actualHandler)
        {
            actualHandler = null;

            if (descriptor.FontFile == null)
            {
                try
                {
                    var ttf = systemFontFinder.GetTrueTypeFont(descriptor.FontName.Data);
                    return(ttf);
                }
                catch (Exception ex)
                {
                    log.Error($"Failed finding system font by name: {descriptor.FontName}.", ex);
                }

                return(null);
            }

            try
            {
                var fontFileStream = DirectObjectFinder.Get <StreamToken>(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);
            }
            catch (Exception ex)
            {
                log.Error("Could not parse the TrueType font.", ex);

                return(null);
            }
        }
コード例 #21
0
ファイル: PdfDocumentFactory.cs プロジェクト: AnilAwadh/Pdf
        private static PdfDocument OpenDocument(IRandomAccessRead reader, IInputBytes inputBytes, ISeekableTokenScanner scanner, IContainer container, bool isLenientParsing)
        {
            var log = container.Get <ILog>();

            var version = container.Get <FileHeaderParser>().Parse(scanner, isLenientParsing);

            var crossReferenceOffset = container.Get <FileTrailerParser>().GetFirstCrossReferenceOffset(inputBytes, scanner, isLenientParsing);

            var pool = new CosObjectPool();

            // TODO: make this use the scanner.
            var validator = new CrossReferenceOffsetValidator(new XrefOffsetValidator(log, reader, container.Get <CosDictionaryParser>(),
                                                                                      container.Get <CosBaseParser>(), pool));

            crossReferenceOffset = validator.Validate(crossReferenceOffset, isLenientParsing);

            var crossReferenceTable = container.Get <CrossReferenceParser>()
                                      .Parse(reader, isLenientParsing, crossReferenceOffset, pool);

            container.Get <CrossReferenceParser>().ParseNew(crossReferenceOffset, scanner, isLenientParsing);

            var filterProvider     = container.Get <IFilterProvider>();
            var bruteForceSearcher = new BruteForceSearcher(reader);
            var pdfObjectParser    = new PdfObjectParser(container.Get <ILog>(), container.Get <CosBaseParser>(),
                                                         container.Get <CosStreamParser>(), crossReferenceTable, bruteForceSearcher, pool, container.Get <ObjectStreamParser>());

            var trueTypeFontParser    = new TrueTypeFontParser();
            var fontDescriptorFactory = new FontDescriptorFactory();

            var cidFontFactory = new CidFontFactory(fontDescriptorFactory, trueTypeFontParser, pdfObjectParser, filterProvider);

            var cMapCache = new CMapCache(new CMapParser());

            var fontFactory = new FontFactory(log, new Type0FontHandler(cidFontFactory,
                                                                        cMapCache,
                                                                        filterProvider,
                                                                        pdfObjectParser),
                                              new TrueTypeFontHandler(pdfObjectParser, filterProvider, cMapCache, fontDescriptorFactory, trueTypeFontParser));

            var dynamicParser     = container.Get <DynamicParser>();
            var resourceContainer = new ResourceContainer(pdfObjectParser, fontFactory);

            var pageFactory        = new PageFactory(resourceContainer, pdfObjectParser, filterProvider, new PageContentParser(new ReflectionGraphicsStateOperationFactory()));
            var informationFactory = new DocumentInformationFactory();
            var catalogFactory     = new CatalogFactory(pdfObjectParser);

            var root = ParseTrailer(reader, crossReferenceTable, dynamicParser, bruteForceSearcher, pool,
                                    isLenientParsing);

            if (!(root is PdfDictionary rootDictionary))
            {
                throw new InvalidOperationException("Expected root dictionary, but got this: " + root);
            }

            // in some pdfs the type value "Catalog" is missing in the root object
            if (isLenientParsing && !rootDictionary.ContainsKey(CosName.TYPE))
            {
                rootDictionary.Set(CosName.TYPE, CosName.CATALOG);
            }

            var information = informationFactory.Create(pdfObjectParser, crossReferenceTable.Dictionary, reader, isLenientParsing);

            var catalog = catalogFactory.Create(rootDictionary, reader, isLenientParsing);

            var caching = new ParsingCachingProviders(pool, bruteForceSearcher, resourceContainer);

            return(new PdfDocument(log, reader, version, crossReferenceTable, isLenientParsing, caching, pageFactory, pdfObjectParser, catalog, information));
        }
コード例 #22
0
ファイル: TrueTypeSubsetter.cs プロジェクト: zyj0021/PdfPig
        /// <summary>
        /// Generate a subset of the input font containing only the data required for the glyphs specified in the encoding.
        /// </summary>
        public static byte[] Subset(byte[] fontBytes, TrueTypeSubsetEncoding newEncoding)
        {
            if (fontBytes == null)
            {
                throw new ArgumentNullException(nameof(fontBytes));
            }

            if (newEncoding == null)
            {
                throw new ArgumentNullException(nameof(newEncoding));
            }

            var font = TrueTypeFontParser.Parse(new TrueTypeDataBytes(fontBytes));

            var indexMapping = GetIndexMapping(font, newEncoding);

            using (var stream = new MemoryStream())
            {
                var copiedTableTags = new SortedSet <string>(StringComparer.Ordinal);

                for (var i = 0; i < RequiredTags.Count; i++)
                {
                    var tag = RequiredTags[i];

                    if (!font.TableHeaders.ContainsKey(tag))
                    {
                        throw new InvalidFontFormatException($"Font does not contain table required for subsetting: {tag}.");
                    }

                    copiedTableTags.Add(tag);
                }

                for (var i = 0; i < OptionalTags.Count; i++)
                {
                    var tag = OptionalTags[i];

                    if (!font.TableHeaders.ContainsKey(tag))
                    {
                        continue;
                    }

                    copiedTableTags.Add(tag);
                }

                var offsetSubtable = new TrueTypeOffsetSubtable((byte)copiedTableTags.Count);
                offsetSubtable.Write(stream);

                // The table directory follows the offset subtable.
                var directoryEntries = new DirectoryEntry[copiedTableTags.Count];

                // Entries in the table directory must be sorted in ascending order by tag (case sensitive).
                // Each table in the font file must have its own table directory entry.
                var index = 0;
                foreach (var tag in copiedTableTags)
                {
                    var entry = new DirectoryEntry(tag, stream.Position, font.TableHeaders[tag]);
                    entry.DummyHeader.Write(stream);
                    directoryEntries[index++] = entry;
                }

                // Generate the glyph subset.
                TrueTypeSubsetGlyphTable trueTypeSubsetGlyphTable = TrueTypeGlyphTableSubsetter.SubsetGlyphTable(font, fontBytes, indexMapping);

                // Write the actual tables.
                for (var i = 0; i < directoryEntries.Length; i++)
                {
                    var entry = directoryEntries[i];

                    entry.OutputTableOffset = stream.Position;

                    if (entry.Tag == TrueTypeHeaderTable.Cmap)
                    {
                        var cmapTable = GetCMapTable(font, entry, indexMapping);
                        cmapTable.Write(stream);
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Glyf)
                    {
                        stream.Write(trueTypeSubsetGlyphTable.Bytes, 0, trueTypeSubsetGlyphTable.Bytes.Length);
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Hmtx)
                    {
                        var hmtx = GetHorizontalMetricsTable(entry, trueTypeSubsetGlyphTable);
                        hmtx.Write(stream);
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Loca)
                    {
                        var table = new IndexToLocationTable(entry.DummyHeader, IndexToLocationTable.EntryFormat.Long,
                                                             trueTypeSubsetGlyphTable.GlyphOffsets);
                        table.Write(stream);
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Head)
                    {
                        // Update indexToLoc format.
                        var headBytes = GetRawInputTableBytes(fontBytes, entry);
                        WriteUShort(headBytes, headBytes.Length - 4, IndexToLocLong);
                        stream.Write(headBytes, 0, headBytes.Length);

                        // TODO: zero out checksum adjustment bytes.
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Hhea)
                    {
                        // Update number of h metrics.
                        var hheaBytes = GetRawInputTableBytes(fontBytes, entry);
                        WriteUShort(hheaBytes, hheaBytes.Length - 2, (ushort)trueTypeSubsetGlyphTable.HorizontalMetrics.Length);
                        stream.Write(hheaBytes, 0, hheaBytes.Length);
                    }
                    else if (entry.Tag == TrueTypeHeaderTable.Maxp)
                    {
                        // Update number of glyphs.
                        var maxpBytes = GetRawInputTableBytes(fontBytes, entry);
                        WriteUShort(maxpBytes, 4, trueTypeSubsetGlyphTable.GlyphCount);
                        stream.Write(maxpBytes, 0, maxpBytes.Length);
                    }
                    else
                    {
                        // Copy table as-is.
                        var buffer = GetRawInputTableBytes(fontBytes, entry);
                        stream.Write(buffer, 0, buffer.Length);
                    }

                    entry.Length = (uint)(stream.Position - entry.OutputTableOffset);

                    // Tables must start on 4 byte boundaries.
                    var remainder = stream.Position % 4;
                    if (remainder > 0)
                    {
                        var toAppend = 4 - remainder;
                        stream.Write(PaddingBytes, 0, (int)toAppend);
                    }
                }

                using (var inputBytes = new StreamInputBytes(stream, false))
                {
                    // Update the table directory.
                    for (var i = 0; i < directoryEntries.Length; i++)
                    {
                        var entry = directoryEntries[i];

                        var actualHeaderExceptChecksum = new TrueTypeHeaderTable(entry.Tag, 0, (uint)entry.OutputTableOffset, entry.Length);

                        var checksum = TrueTypeChecksumCalculator.Calculate(inputBytes, actualHeaderExceptChecksum);

                        var actualHeader = new TrueTypeHeaderTable(entry.Tag, checksum, (uint)entry.OutputTableOffset, entry.Length);

                        stream.Seek(entry.OutputEntryOffset, SeekOrigin.Begin);

                        actualHeader.Write(stream);
                    }
                }

                // TODO: whole font checksum.
                var result = stream.ToArray();
                return(result);
            }
        }