namespace UglyToad.PdfPig { using System; using System.IO; using Content; using CrossReference; using IO; using Logging; using Parser; using Tokenization.Scanner; using Util.JetBrains.Annotations; /// /// /// Provides access to document level information for this PDF document as well as access to the s contained in the document. /// public class PdfDocument : IDisposable { private bool isDisposed; private readonly bool isLenientParsing; [NotNull] private readonly HeaderVersion version; private readonly ILog log; private readonly IInputBytes inputBytes; [NotNull] private readonly ParsingCachingProviders cachingProviders; private readonly IPdfTokenScanner pdfScanner; [NotNull] private readonly Pages pages; /// /// The metadata associated with this document. /// [NotNull] public DocumentInformation Information { get; } /// /// Access to the underlying raw structure of the document. /// [NotNull] public Structure Structure { get; } /// /// The version number of the PDF specification which this file conforms to, for example 1.4. /// public decimal Version => version.Version; /// /// Get the number of pages in this document. /// public int NumberOfPages => pages.Count; internal PdfDocument(ILog log, IInputBytes inputBytes, HeaderVersion version, CrossReferenceTable crossReferenceTable, bool isLenientParsing, ParsingCachingProviders cachingProviders, IPageFactory pageFactory, Catalog catalog, DocumentInformation information, IPdfTokenScanner pdfScanner) { this.log = log; this.inputBytes = inputBytes; this.version = version ?? throw new ArgumentNullException(nameof(version)); this.isLenientParsing = isLenientParsing; this.cachingProviders = cachingProviders ?? throw new ArgumentNullException(nameof(cachingProviders)); this.pdfScanner = pdfScanner ?? throw new ArgumentNullException(nameof(pdfScanner)); Information = information ?? throw new ArgumentNullException(nameof(information)); pages = new Pages(log, catalog, pageFactory, isLenientParsing, pdfScanner); Structure = new Structure(catalog, crossReferenceTable, pdfScanner); } /// /// Creates a for reading from the provided file bytes. /// /// The bytes of the PDF file. /// Optional parameters controlling parsing. /// A providing access to the file contents. public static PdfDocument Open(byte[] fileBytes, ParsingOptions options = null) => PdfDocumentFactory.Open(fileBytes, options); /// /// Opens a file and creates a for reading from the provided file path. /// /// The full path to the file location of the PDF file. /// Optional parameters controlling parsing. /// A providing access to the file contents. public static PdfDocument Open(string filePath, ParsingOptions options = null) => PdfDocumentFactory.Open(filePath, options); /// /// Creates a for reading from the provided stream. /// The caller must manage disposing the stream. The created PdfDocument will not dispose the stream. /// /// /// A stream of the file contents, this must support reading and seeking. /// The PdfDocument will not dispose of the provided stream. /// /// Optional parameters controlling parsing. /// A providing access to the file contents. public static PdfDocument Open(Stream stream, ParsingOptions options = null) => PdfDocumentFactory.Open(stream, options); /// /// Get the page with the specified page number (1 indexed). /// /// The number of the page to return, this starts from 1. /// The page. public Page GetPage(int pageNumber) { if (isDisposed) { throw new ObjectDisposedException("Cannot access page after the document is disposed."); } log.Debug($"Accessing page {pageNumber}."); return pages.GetPage(pageNumber); } /// /// /// Dispose the and close any unmanaged resources. /// public void Dispose() { try { inputBytes.Dispose(); } catch (Exception ex) { log.Error("Failed disposing the PdfDocument due to an error.", ex); } finally { isDisposed = true; } } } }