Skip to content
Analysis

Analysis

A PDF file is a set of numbered objects plus a cross reference table mapping each number to a byte offset. Everything else - pages, fonts, images, annotations - is a dictionary somewhere in that set, referring to other objects by number. The guides in this section are about reading that structure rather than the document it describes, which is what you do when a file renders wrong, when you want to know whether a document is worth running extraction on, or when you are auditing a corpus.

Two layers are available, and picking the wrong one is the usual source of frustration.

LayerWhat you getUse it for
model.PdfReaderPages, fonts, annotations and outlines as Go structs, plus Inspect, PrintPdfObject and PrintPdfObjects for debugging.Almost everything. Start here.
core primitivesThe raw object graph: PdfObjectDictionary, PdfObjectArray, PdfObjectStream, PdfIndirectObject, PdfObjectReference.Keys the model does not expose, malformed files, and anything you need to read byte for byte.

Reach for core when the model has no accessor for what you want. A page dictionary entry that UniPDF does not model is still reachable through page.GetPageDict().Get("SomeKey"), and the reader hands you any numbered object with GetIndirectObjectByNumber.

Working with core objects

Every core object satisfies the PdfObject interface:

type PdfObject interface {
    String() string              // debugging representation
    Write() []byte               // the object as written to file
    Direct() PdfObject           // dereferences references and indirect objects
    Equals(other PdfObject) bool // deep comparison
}

Direct() and Equals() are new in v5 and are equivalent to the free functions core.TraceToDirectObject(obj) and core.EqualObjects(obj, other), which still work. Write() returns the serialized bytes; in v4 the method was WriteString() and returned a string. See the v5 migration guide if you implement PdfObject yourself.

Reading a value out of the graph means resolving a reference and then type asserting. The core.Get* helpers do both:

dict := page.GetPageDict()

if name, ok := core.GetNameVal(dict.Get("Type")); ok {
    fmt.Println(name) // Page
}
if arr, ok := core.GetArray(dict.Get("MediaBox")); ok {
    fmt.Println(arr.Len()) // 4
}

GetBool, GetInt, GetFloat, GetString, GetName, GetArray and GetDict all trace through indirect objects before asserting, and each has a *Val variant that returns the Go value instead of the wrapper. GetStream and GetIndirect are the exceptions: they resolve a reference but do not trace deeper, because a stream or an indirect object is the thing you asked for rather than something to unwrap.

Stream contents are compressed on disk. core.DecodeStream(stream) applies the stream’s filters and hands back the decoded bytes.

Lazy loading and encryption

The two reader constructors used across these examples differ in a way that matters for large files. model.NewPdfReaderFromFile(path, nil) loads lazily, resolving objects from disk on demand. model.NewPdfReader(f) loads the whole object graph into memory up front.

They also differ on encrypted documents. NewPdfReaderFromFile tries the password from ReaderOpts, empty by default, and returns an error if it does not authenticate, so a password protected file never yields a reader. NewPdfReader does not attempt decryption at all: it returns a reader whose structure is not loaded, and the following GetNumPages fails with “file need to be decrypted first” until you call Decrypt. Get PDF info works through that case.

Where to look

GuideCovers
Get PDF infoPage count and encryption status, and handling documents that need a password.
Inspect PDF objectsCounting object types, and screening for JavaScript and rich media.
Detect scanned PDF documentDeciding whether a document has a text layer before extracting from it.
Get all PDF objectsDumping every object in the file, decoded streams included.
Get PDF objectPrinting one object by number, or the trailer.
Print content streamsReading a page’s content stream and its operator list.
Summarize imagesBuilding an inventory of image filters, colorspaces and sizes across many files.

For reading the document rather than its structure, see extraction. For title, author and the rest of the document information dictionary, see metadata.

Last updated on