The object model

edit

A PDF file is a graph of objects: dictionaries, arrays, streams, names, strings, numbers and references between them. The high-level members (Pages, Information, Annotations...) read and write these objects; anything they do not cover can be done with the objects themselves. The types are in the Meziantou.Framework.Pdf.Objects namespace.

Read objects

var document = PdfDocument.Open(file);

// The fonts of the resources of the pages: the /BaseFont of each font dictionary
var fonts = new SortedSet<string>(StringComparer.Ordinal);
foreach (var page in document.Pages)
{
    if (page.Resources?.GetResolved("Font") is not PdfDictionary pageFonts)
        continue;

    foreach (var name in pageFonts.Keys)
    {
        if (pageFonts.GetResolved(name) is PdfDictionary font && font.GetName("BaseFont") is { } baseFont)
        {
            fonts.Add(baseFont.Value);
        }
    }
}

Change objects

var document = new PdfDocument();
document.Pages.Add(PdfSize.Letter);

// The catalog is a dictionary of the object model: entries the API has no member for can be set directly
document.Catalog[PdfName.Create("PageLayout")] = PdfName.Create("TwoColumnLeft");
var viewerPreferences = new PdfDictionary
{
    [PdfName.Create("DisplayDocTitle")] = PdfBoolean.True,
};
document.Catalog[PdfName.Create("ViewerPreferences")] = document.Objects.Add(viewerPreferences);
  • Set an entry of a dictionary with its indexer, or with SetName, SetText and SetNumber; remove it with Remove.
  • PdfDocument.Objects.Add makes an object indirect and returns its reference, which other objects can point to. Remove removes an indirect object: the references to it then point to the null object.
  • A document can only refer to its own objects: a save throws InvalidOperationException for a reference that belongs to another document. Names cannot contain the null character: PdfName.Create throws ArgumentException. A name read from a file with #00 is kept, and written as it was read.
  • PdfStream.SetData replaces the data of a stream with data without filter, which the save compresses (CompressStreams); SetEncodedData sets data that is already encoded, with its filter.
  • The high-level members read and write the same objects: a change made through either is visible through both, and an incremental save writes the objects that changed.

The types

TypePDF object
PdfDictionaryA dictionary, whose entries keep their order
PdfArrayAn array; FromNumbers creates an array of numbers, such as a rectangle
PdfStreamA dictionary with data, such as a content stream, an image or a font file
PdfNameA name, such as /Type
PdfStringA string: FromText and ToText convert text, FromBytes and Bytes raw bytes
PdfInteger, PdfRealNumbers, which derive from PdfNumber
PdfBoolean, PdfNulltrue and false, and the null object
PdfReferenceA reference to an indirect object; Resolve returns the object

PdfRectangle.ToArray and PdfRectangle.TryRead convert rectangles from and to arrays.