pdf0

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: MIT Imports: 38 Imported by: 0

README

pdf0

A PDF parser, serializer, and conformance validator written in Go. The object model is ISO 32000-2 (PDF 2.0); files of any version are read into it, and most of the standards below are defined against PDF 1.x — PDF/A-1, -2 and -3 require a 1.x header, PDF/X-1a and -3 require 1.3/1.4. Its only dependencies are the author's own pure-Go modules (formalis for EN 16931 invoice rules, golittlecms for ICC profiles, gopenjpeg for JPEG 2000).

go get github.com/mgilbir/pdf0

What it does

  • Parse a PDF into a typed object model (Read), preserving dictionary key order for faithful round-tripping.

  • Serialize the object model back to PDF bytes (Document.Write), regenerating cross-reference streams and object streams where the source used them.

  • Validate against ten conformance standards:

    Standard Entry point Findings satisfy Violation
    PDF/A 1a/1b, 2a/2b, 3a/3b, 4 ValidatePDFA / ValidatePDFABytes yes
    PDF/UA-1, PDF/UA-2 ValidatePDFUA / ValidatePDFUA2 yes
    PDF/X-1a/3/4/4p/6 ValidatePDFX yes
    PDF/VT-1, PDF/VT-2 ValidatePDFVT / ValidatePDFVT2 yes
    PDF/R ValidatePDFR yes
    DPart hierarchy ValidateDParts yes
    Factur-X, Order-X containers ValidateFacturX / ValidateOrderX yes — in a result struct, see below

    The six PDF-standard validators are free functions taking the *Document first and returning findings that satisfy the shared Violation interface, so results combine across validators. Factur-X and Order-X return a result struct rather than a slice, because they also carry the extracted invoice XML, the conformance level the container declared, and what the invoice rule engine did not evaluate — but res.Violations holds FacturXViolation / OrderXViolation, which satisfy Violation like every other finding type.

  • Encrypt / decrypt with the standard security handler — RC4, AES-128, and AES-256, via ReadWithPassword, SetEncryption, and RemoveEncryption (Document.Locked reports a file that could not be decrypted).

  • Sign and verify digital signatures (WriteSigned / VerifySignatures, CMS/PKCS#7), including PAdES B-B through B-LTA (ValidatePAdES), RFC 3161 timestamps, and CRL/OCSP revocation. Read the verdict with SignatureResult.DocumentUnmodified(), not Valid alone — Valid accepts a document altered by a post-signing incremental update. VerifySignatures performs no trust-chain check; use VerifySignaturesWithRoots for that.

  • Extract text (ExtractText) and images (ExtractImages, or the lazy Images iterator for bounded memory on large scan files; decoding DCTDecode, CCITTFax, JBIG2 and JPXDecode), repair common conformance failures (Repair), and manipulate pages (ExtractPages, AppendPages).

  • Write incrementally (WriteIncremental) and build a minimal conformant PDF/A document (NewPDFADocument).

Quick start

Read, inspect, and re-serialize a PDF:

package main

import (
	"bytes"
	"fmt"
	"os"

	"github.com/mgilbir/pdf0"
)

func main() {
	data, _ := os.ReadFile("input.pdf")
	doc, err := pdf0.Read(bytes.NewReader(data), int64(len(data)))
	if err != nil {
		panic(err)
	}
	fmt.Printf("version=%s objects=%d\n", doc.Version, len(doc.Objects))

	var out bytes.Buffer
	if err := doc.Write(&out); err != nil {
		panic(err)
	}
}

Validate against a PDF/A level:

errs := pdf0.ValidatePDFA(doc, pdf0.PDFA4)
for _, e := range errs {
	fmt.Println(e) // e.g. [PDF/A-4 6.2.10] object 12: font ... must be embedded
}

ValidatePDFA returns nil when none of the implemented checks fire. Note that the validator does not yet implement every PDF/A rule (see Status below), so an empty result means "nothing I check flagged this," not a guarantee of full conformance. Use ValidatePDFABytes when you have the raw file bytes and want the additional byte-level checks (e.g. no data after %%EOF).

For untrusted input, every unbounded loop and every file-sized allocation is already capped, and eleven of those caps are settable per document as options on Read:

doc, err := pdf0.Read(r, size,
	pdf0.WithMaxDecodedStreamBytes(8<<20),   // stricter decompression-bomb ceiling
	pdf0.WithMaxDecodedContentBytes(64<<20), // stricter whole-run content budget
)

They resolve once and are stored on the Document, so every later validation and extraction inherits them. When a cap does stop a check, the trip is reported as a finding under the rule "limit" rather than guessed at — IsCheckerFinding separates that from a real non-conformance, and it means unknown, never failed. See docs/limits.md and docs/architecture.md.

Under a deadline, use the …Context variants — ReadContext, Document.WriteContext, ValidatePDFAContext, ValidatePDFUAContext, Document.ExtractTextContext and the rest:

ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
errs := pdf0.ValidatePDFAContext(ctx, doc, pdf0.PDFA4)

A cancelled validation returns the findings it had gathered plus one under the rule "limit", so it can never be mistaken for a clean result; Read, Write and the extractors return an error wrapping ctx.Err() instead. Every original signature is unchanged. See docs/architecture.md for which entry points have a variant, why, and the measured cancellation latency.

See examples/ for runnable programs (simple_pdf, simple_pdf17, simple_pdfa); run one with go run ./examples/simple_pdfa.

Build and test

go build ./...
go test ./...          # unit + spec-example tests; the corpus test skips if absent
go vet ./...
gofmt -l .             # should print nothing

The default go test ./... runs the parser/serializer/validator unit tests and the PDF 1.7 / 2.0 spec-example tests (the spec examples are committed as JSON under testdata/). The round-trip tests need reference PDFs that are not committed; fetch them with make refpdfs (they self-skip when absent).

docs/ is the documentation index: architecture, the validator family, signing, images, fonts, XMP, encryption, troubleshooting, and the test data a fresh clone does not have. For the corpus-ratchet workflow and how to add a rule, see CONTRIBUTING.md.

cmd/pdf0 is a small command-line front end used mainly for poking at files during development — go run ./cmd/pdf0 -h. pdf0 is a library first, and the tool reaches only a fraction of the API; it is documented in docs/cli.md but is not the supported surface.

PDF/A conformance corpus

TestCorpus runs the validator over the veraPDF corpus. The corpus is not committed; fetch it and run the test with:

make corpus        # git clone the corpus into testdata/verapdf-corpus
make test-corpus   # run TestCorpus against it

TestCorpus is a ratcheting baseline: it measures aggregate outcomes (false positives, missed violations, parse errors) and fails only if any gets worse than the recorded baseline in pdfa_test.go. It skips when the corpus is absent, so a fresh clone's go test ./... stays green.

Status and limitations

This is a young library. What works:

  • Object streams (/Type /ObjStm) and cross-reference streams, including the PNG/TIFF /Predictor filters, are read.
  • The reader recovers from common malformations — wrong stream /Length, offset-shifted xref, a startxref pointing into the table, broken object streams, and a cross-reference section so damaged that the table is rebuilt by scanning the file for object headers — and converts any panic into an error rather than crashing on adversarial input. See the recovery ladder for what is actually fatal.

Known limitations:

  • A file that could not be decrypted cannot be modified. Files using the standard security handler are decrypted on Read for RC4 (V1/V2), AES-128 (V4/AESV2), and AES-256 (V5/AESV3, R6); their strings and streams are then available in the clear, and such a document round-trips — Write re-encrypts with the retained key and re-emits the preserved /Encrypt. Read uses the empty password; ReadWithPassword accepts a user or owner password. But a wrong password, or a scheme pdf0 does not implement, leaves the file encrypted (Document.Locked): its structure parses, its strings and streams stay ciphertext, and Write passes the original bytes through verbatim rather than producing a corrupt file.
  • Write regenerates, rather than preserves, the file layout. A file read from a cross-reference stream is written back as one, with compressible objects repacked into an object stream (/ObjStm); a traditional-table file is written with a table. The object model round-trips, but the exact byte layout (object order, which objects share a stream) is regenerated, not preserved.
  • The PDF/A validator implements a subset of the ISO 19005 rules. Against the veraPDF corpus it currently reports no false positives, no missed violations, and no parse errors (tracked by TestCorpus), with one known missed violation in the Isartor PDF/A-1b fail suite (corpusMaxIsartorMissed, tracked separately by TestCorpusIsartor). Coverage beyond the corpus is not guaranteed — an empty validation result is not a conformance guarantee.
  • No release tags yet. The API is not frozen; go get resolves a pseudo-version, and exported names may change until a v1 is tagged.

See docs/audits/ for the audit history (point-in-time findings, not a description of how the code works — for that start at docs/).

Layout

pdf0 is one flat Go package. The subsystems, and the doc that maps each:

Subsystem Files Map
Core object model, parser, serializer object.go, lexer.go, parser.go, serializer.go, compare.go, xref.go, objstm.go, objstm_write.go, filters.go, document.go, incremental.go architecture.md
PDF/A validation pdfa.go, pdfa_levela.go, final_rules.go, content_operators.go, filestructure.go, pdfa_create.go, preflight.go pdfa.md
The other validators pdfua*.go, pdfx*.go, pdfvt.go, pdfr.go, dpart.go, facturx*.go, order_x.go, violations.go validators.md, pdfua.md
Fonts fonts.go, fontprog.go, font_encodings.go, cff_strings.go fonts.md
XMP metadata xmp.go, xmp_schemas.go xmp.md
Signatures and PAdES cms.go, signatures.go, sign.go, pades.go, timestamp.go, doctimestamp.go, revocation.go signing.md
Encryption (standard security handler) crypt.go, crypt_encrypt.go encryption.md
Images and codecs imageextract.go, imagejpeg.go, imagecolor.go, imagemask.go, ccitt.go, mq.go, jbig2*.go, function.go, function_ps.go images.md
Text and pages text.go, pages.go architecture.md
Command-line front end (dev aid, not the supported surface) cmd/pdf0 cli.md

Every file carries a header comment saying what it owns and which spec clause it implements; start there.

License

See LICENSE.

Documentation

Overview

Package pdf0 is a PDF 2.0 parser, serializer, and PDF/A validator. Its only dependencies are the author's own pure-Go modules (formalis for EN 16931 invoice rules, golittlecms for ICC profiles, gopenjpeg for JPEG 2000).

The core is four entry points:

  • Read parses PDF bytes into a typed object model (see Document), recovering from common malformations rather than crashing on hostile input.
  • Document.Write serializes the object model back to conformant PDF bytes.
  • ValidatePDFA and ValidatePDFABytes check a document against PDF/A conformance levels: PDF/A-1a, -1b, -2a, -2b, -3a, -3b, and -4. The Level A levels are Level B plus the accessibility requirements.
  • NewPDFADocument (and NewPDFADocumentWithInfo) build a minimal PDF/A document.

Built on those: encryption (ReadWithPassword, Document.SetEncryption, Document.RemoveEncryption), digital signatures (Document.WriteSigned, Document.VerifySignatures, Document.ValidatePAdES), extraction (Document.ExtractText, Document.ExtractImages, Document.Images), page operations (Document.ExtractPages, Document.AppendPages), conformance repair (Document.Repair), incremental writing (Document.WriteIncremental), and nine conformance validators besides PDF/A.

Reading and writing

doc, err := pdf0.Read(bytes.NewReader(data), int64(len(data)))
if err != nil { /* malformed beyond recovery */ }
var out bytes.Buffer
err = doc.Write(&out)

Resource limits

pdf0 parses untrusted input, so every unbounded loop and every allocation sized by a number the file supplies is capped. The defaults are safe for hostile input and no real file measured across the veraPDF corpus or a 978-file Common Crawl sample comes within 2x of any of them, so a caller who configures nothing needs to do nothing.

Eleven of those caps are settable per document, as variadic Option values on Read, ReadWithPassword, their Context variants and ParseXRefStream (see WithMaxDecodedStreamBytes and the other With* functions). They resolve once and are stored on the Document, so validation and extraction inherit whatever Read was given, and two documents read with different limits never interfere:

doc, err := pdf0.Read(r, size,
	pdf0.WithMaxDecodedStreamBytes(8<<20),
	pdf0.WithMaxDecodedContentBytes(64<<20),
)

When a cap does stop a check, the validators say so rather than guess: the trip is reported as a finding under the rule identifier "limit", which IsCheckerFinding separates from a real non-conformance. A caller asking "is this file conformant?" should read such a finding as "unknown", never as a failure.

Cancellation

The work a document can cost is set by the document, not by the caller: a 71 MB, 1256-page file takes about ten seconds to validate. The long-running entry points therefore have Context variants — ReadContext, ReadWithPasswordContext, Document.WriteContext, ValidatePDFAContext, ValidatePDFABytesContext, ValidatePDFUAContext, ValidatePDFUA2Context, ValidatePDFXContext, ValidatePDFVTContext, ValidatePDFVT2Context, ValidatePDFRContext, ValidateDPartsContext, ValidateFacturXContext, ValidateOrderXContext, Document.ExtractTextContext and Document.ExtractImagesContext:

ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
for _, e := range pdf0.ValidatePDFAContext(ctx, doc, pdf0.PDFA4) { ... }

A context is a first parameter rather than a With* Option deliberately. An Option is stored on the Document and inherited by every later call, which is the wrong lifetime for a context and would make cancellation invisible at the call site; limits describe what a document may cost, contexts describe how long an operation may take. Every original signature is unchanged, and an entry point whose cost is bounded rather than document-scale — ExtractPageText (one page), Images (an iterator the caller can break out of), Document.VerifySignatures — deliberately has no variant. ValidateFacturX and ValidateOrderX had none until formalis v0.2.0, for reasons that have both lapsed: their findings were formalis.Violation values, which IsCheckerFinding could not classify, and the invoice half of the work was a rule engine that took no context. The findings are now this package's own types and the engine takes a context, so both halves of a Factur-X validation are cancellable and a cancelled run reports the reserved "limit" rule like every other. See docs/architecture.md#cancellation for the full table.

A cancelled validation returns the findings it had gathered plus one under the rule "limit", the same channel a tripped resource cap uses, so a cancelled run can never be mistaken for a clean bill of health. Read, Write and the extractors have no finding channel, so they return an error wrapping ctx.Err() instead. Cancellation is checked at coarse boundaries — per check, per page, per content stream, per megabyte scanned or decompressed — which on that 71 MB file takes effect within about 60 ms.

Encrypted files using the standard security handler are decrypted on Read when the (empty or supplied) user or owner password is correct: RC4 and AES-128 at revisions 2-4, and AES-256 at revision 6. Revision 5 is a deprecated draft and is rejected. Document.Encrypted reports the presence of an /Encrypt dictionary; a decrypted document retains its file key and re-encrypts on Write, so the object model round-trips — though the bytes do not, because AES draws a fresh random initialisation vector per object on every write. Document.RemoveEncryption drops the encryption so Write emits plaintext. A document whose scheme or password could not be handled stays encrypted (Document.Locked reports this) and is written back unchanged as a lossless passthrough. Write regenerates the on-disk layout, emitting a cross-reference stream when the source used one and a traditional cross-reference table otherwise.

Validating

for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA4) {
    fmt.Println(e) // e.g. [PDF/A-4 6.2.10] object 12: font ... must be embedded
}

An empty result means no implemented check fired, not a guarantee of full conformance: the validator covers a subset of ISO 19005. Validation does not mutate its Document and is safe to run concurrently on the same Document. Use ValidatePDFABytes when you have the raw file bytes and want the byte-level file-structure checks (e.g. no data after %%EOF) as well.

The other PDF standards follow the same shape: each validator is a free function taking the *Document as its first parameter (ValidatePDFUA, ValidatePDFUA2, ValidatePDFX, ValidatePDFVT, ValidatePDFVT2, ValidatePDFR, ValidateDParts), and every finding type satisfies the Violation interface, so findings from different validators can be collected together. ValidateFacturX and ValidateOrderX differ only in shape: they return a result struct, because they also carry the extracted invoice XML, the conformance level and what the invoice rule engine did not evaluate, but the findings inside it are FacturXViolation and OrderXViolation values and satisfy Violation like the rest. See the Violation documentation.

Every validator returns its findings in a deterministic order (by rule, then object, then message) and runs its checks under a recover boundary: a check that panics on hostile input is reported as a finding whose rule is "internal" rather than crashing the caller. A stack overflow from unbounded recursion is fatal and is not recoverable; those are prevented at the source.

Signatures

Document.VerifySignatures reports one SignatureResult per signature. Read the verdict with SignatureResult.DocumentUnmodified, which is Valid AND CoversWholeDocument: Valid alone accepts a document whose content was changed by a post-signing incremental update. VerifySignatures performs no trust-chain check at all — use Document.VerifySignaturesWithRoots to populate TrustedChain.

See docs/architecture.md for how bytes flow through Read and Write, docs/validators.md for the validator family, and docs/signing.md for signing and verification.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultSRGBProfile

func DefaultSRGBProfile() []byte

DefaultSRGBProfile returns a real sRGB ICC profile (ICC v2.1, valid at every PDF/A level) generated by golittlecms, a pure-Go Little CMS port. It is exported for callers that assemble their own OutputIntent; NewPDFADocument uses sRGBProfile to select a level-appropriate profile version.

func DocumentEqual

func DocumentEqual(a, b *Document) bool

DocumentEqual compares two Documents for semantic equality.

func EmbedFacturX

func EmbedFacturX(doc *Document, invoiceXML []byte, profile formalis.Profile, title string) error

EmbedFacturX embeds the CII invoice XML into doc as the associated file factur-x.xml and writes the Factur-X metadata for the given profile. doc must be a valid PDF/A-3 document (for example from NewPDFADocument(PDFA3b)); the result is a Factur-X container that ValidateFacturX accepts after a round trip. title, when non-empty, is recorded as the document title in the XMP.

func Equal

func Equal(a, b Object) bool

Equal reports whether two PDF objects are semantically equal. It compares values deeply. IndirectRef values are compared by their object/generation numbers only; Equal does not resolve references (it has no document to resolve against), so an IndirectRef is never equal to the object it points to.

func GenerateXMPMetadata

func GenerateXMPMetadata(level PDFALevel, title, author string) []byte

GenerateXMPMetadata creates XMP metadata bytes for the given PDF/A level.

func IsCheckerFinding

func IsCheckerFinding(v Violation) bool

IsCheckerFinding reports whether a finding describes a problem in the checker rather than a non-conformance of the document. Two rule identifiers are reserved for this: "internal" (a check panicked and was recovered) and "limit" (a resource guard tripped, so a check could not be completed). A caller that wants "is this file conformant?" should treat a checker finding as "unknown", not as a failure:

var real []pdf0.Violation
for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA2b) {
	if !pdf0.IsCheckerFinding(e) {
		real = append(real, e)
	}
}

Neither kind fires on any file in the veraPDF corpus; both mean the input is adversarial or the checker has a bug.

Types

type Array

type Array []Object

Array represents a PDF array object.

type Boolean

type Boolean bool

Boolean represents a PDF boolean value.

func (Boolean) String

func (b Boolean) String() string

String returns a human-readable representation for debugging.

type DPartViolation

type DPartViolation struct {
	Rule    string // ISO 32000-2 subclause, e.g. "14.12.2"
	Message string
	Object  int // object number the violation is anchored to, 0 if N/A
}

DPartViolation reports a way in which a document's DPart hierarchy departs from ISO 32000-2 clause 14.12.

func ValidateDParts

func ValidateDParts(doc *Document) []DPartViolation

ValidateDParts checks a document's DPart hierarchy against ISO 32000-2 clause 14.12. A document without a /DPartRoot in its catalog has no hierarchy and is reported as valid (nil), since the structure is optional. The checks cover: the DPartRoot and DPartRootNode wiring (Table 408), each node's /Type, required /Parent up-link and its target (14.12.2), the exclusive /DParts vs /Start+/End roles (Table 409), the leaf page ranges partitioning every page exactly once in page-tree order (14.12.2/14.12.3), page /DPart back-references (14.12.3), /NodeNameList depth (Table 408), and DPM key/value constraints (14.12.4.2).

func ValidateDPartsContext

func ValidateDPartsContext(ctx context.Context, doc *Document) []DPartViolation

ValidateDPartsContext is ValidateDParts with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).

func (DPartViolation) Error

func (v DPartViolation) Error() string

func (DPartViolation) ObjectNum

func (v DPartViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (DPartViolation) RuleID

func (v DPartViolation) RuleID() string

RuleID returns the ISO 32000-2 DPart subclause.

type Dictionary

type Dictionary struct {
	Keys   []Name
	Values []Object
	// contains filtered or unexported fields
}

Dictionary represents a PDF dictionary object. Uses parallel slices to preserve key insertion order for round-tripping.

func (*Dictionary) Clone

func (d *Dictionary) Clone() *Dictionary

Clone returns a copy of the dictionary whose Keys and Values live in fresh backing arrays, so that Set/Delete on the copy do not mutate the original. Value objects are shared, not deep-copied.

func (*Dictionary) Delete

func (d *Dictionary) Delete(key Name) bool

Delete removes the key-value pair for the given key. Returns true if the key was found and removed.

func (*Dictionary) Get

func (d *Dictionary) Get(key Name) Object

Get returns the value associated with the given key, or nil if not found.

func (*Dictionary) Len

func (d *Dictionary) Len() int

Len returns the number of key-value pairs.

func (*Dictionary) Set

func (d *Dictionary) Set(key Name, value Object)

Set sets the value for the given key. If the key already exists, it updates the value in place (its slot is unchanged, so the lookup index stays valid). Otherwise it appends a new key-value pair and drops the index, which the next lookup rebuilds lazily.

Set deliberately scans linearly rather than consulting the index: building the index here would make append-heavy construction O(n^2) (each Set would rebuild an O(n) map). The index accelerates the read-heavy Get path, which is where the super-linear validator traversals live; the parser, the one producer of very large dictionaries, populates Keys/Values directly and never routes through Set.

type Document

type Document struct {
	Version string                  // e.g., "2.0"
	Objects map[int]*IndirectObject // object number → object
	Trailer Dictionary
	// Encrypted reports whether the file carried an /Encrypt dictionary.
	// Standard-security-handler files with the empty user password are decrypted
	// on Read (RC4, AES-128, and AES-256); their strings and streams are then in
	// the clear but this flag stays set. Schemes decryption does not handle
	// (non-empty passwords) keep their contents encrypted. Write re-encrypts a
	// decrypted document (reproducing the original /Encrypt) but refuses one whose
	// content is still encrypted.
	Encrypted bool

	// Offsets records the absolute byte offset of each uncompressed indirect
	// object, for the byte-level file-structure checks. Objects materialised
	// from object streams are absent.
	Offsets map[int]int64
	// contains filtered or unexported fields
}

Document represents a parsed PDF file.

func NewPDFADocument

func NewPDFADocument(level PDFALevel) *Document

NewPDFADocument creates a minimal valid PDF/A document for the given level. The document has an empty page tree and passes ValidatePDFA.

func NewPDFADocumentWithInfo

func NewPDFADocumentWithInfo(level PDFALevel, title, author string) *Document

NewPDFADocumentWithInfo is NewPDFADocument with the document title and author embedded in the generated XMP metadata.

func Read

func Read(r io.ReaderAt, size int64, opts ...Option) (*Document, error)

Read parses a PDF document from the given data.

A malformed or adversarial file always yields an error, never a panic: any panic escaping the parse is recovered and returned as an error.

Encrypted files (standard security handler) are decrypted with the empty password; use ReadWithPassword to supply a user or owner password. A file that cannot be decrypted is still parsed structurally, with its strings and streams left encrypted (see Document.Encrypted). Resource limits default to values safe for untrusted input; pass With* options to change them. The resolved limits are stored on the returned Document, so every validator and extractor that runs on it inherits the same configuration.

func ReadContext

func ReadContext(ctx context.Context, r io.ReaderAt, size int64, opts ...Option) (*Document, error)

ReadContext is Read with cancellation. Parsing is not usually the expensive half — a 71 MB file parses in about 100 ms — but its cost is set by the file: a small file can carry half a gigabyte of object streams to decompress, and a cross-reference section too broken to use is rebuilt by scanning the whole file. Those are the cases a caller with a deadline needs to be able to stop.

A cancelled read returns a nil Document and an error wrapping ctx.Err(), so errors.Is(err, context.Canceled) and errors.Is(err, context.DeadlineExceeded) both work. It never returns a partial Document: a document missing an arbitrary subset of its objects is indistinguishable from one whose file genuinely lacks them, and every validator would then report the absence as a conformance failure. See cancel.go.

func ReadWithPassword

func ReadWithPassword(r io.ReaderAt, size int64, password string, opts ...Option) (*Document, error)

ReadWithPassword is Read with a user or owner password for an encrypted file.

func ReadWithPasswordContext

func ReadWithPasswordContext(ctx context.Context, r io.ReaderAt, size int64, password string, opts ...Option) (*Document, error)

ReadWithPasswordContext is ReadWithPassword with cancellation; see ReadContext.

func (*Document) AppendPages

func (d *Document) AppendPages(other *Document)

AppendPages copies every page of other onto the end of this document.

func (*Document) DSSCerts

func (d *Document) DSSCerts() []*x509.Certificate

DSSCerts returns the certificates stored in the document's DSS /Certs (the chain material a long-term signature carries).

func (*Document) DSSRevocationMaterial

func (d *Document) DSSRevocationMaterial() (crls, ocsps [][]byte)

DSSRevocationMaterial returns the CRLs and OCSP responses (DER) stored in the document's DSS (Document Security Store), decoded through their stream filters.

func (*Document) ExtractImages

func (d *Document) ExtractImages() []ExtractedImage

ExtractImages returns every image XObject drawn from the document's pages, each decoded when the codec is one this package handles. Form XObjects are followed into their own resources, so images nested inside forms are found too.

Every decoded image is held in the returned slice at once; on a large scan document that is unbounded memory. Use Images to iterate lazily with at most one decoded image live at a time.

func (*Document) ExtractImagesContext

func (d *Document) ExtractImagesContext(ctx context.Context) ([]ExtractedImage, error)

ExtractImagesContext is ExtractImages with cancellation.

It returns the images extracted before the cancellation and an error wrapping ctx.Err(), for the reason ExtractTextContext does: extraction has no finding channel, so a short slice returned bare would be indistinguishable from a document with fewer images. The error is nil exactly when every image was reached.

Cancellation is checked between images, so it takes effect after at most one image decode. A single very large image is therefore not interruptible; that residual is bounded by the codec budgets rather than by the context. See cancel.go.

There is deliberately no context variant of Images: an iterator is already cancellable by breaking out of the range loop, and because each image is decoded only as it is yielded, breaking after image N skips exactly the work a context checked between images would have skipped.

func (*Document) ExtractPageText

func (d *Document) ExtractPageText(page *Dictionary) string

ExtractPageText returns the visible text of a single page dictionary. It resolves the page's /Resources through the page-tree inheritance chain and recurses into invoked form XObjects, so text drawn via inherited fonts or inside a form is not dropped.

There is deliberately no ExtractPageTextContext: one page is the unit of work, and a caller extracting several pages already has a loop of its own to check a context in. Adding a variant here would move that check inside a call that does one page's work either way.

func (*Document) ExtractPages

func (d *Document) ExtractPages(indices []int) (*Document, error)

ExtractPages returns a new document containing only the given pages (0-based, in the order given). The source is not modified.

func (*Document) ExtractText

func (d *Document) ExtractText() string

ExtractText returns the visible text of every page in reading order, pages separated by a form feed. Text is decoded through each font's ToUnicode CMap; glyphs without a ToUnicode mapping are dropped. Layout is approximate: line breaks follow the text-positioning operators and wide inter-glyph gaps become spaces.

func (*Document) ExtractTextContext

func (d *Document) ExtractTextContext(ctx context.Context) (string, error)

ExtractTextContext is ExtractText with cancellation.

It returns the text extracted before the cancellation *and* an error wrapping ctx.Err(). Both, because either alone would be a lie: discarding the text throws away work the caller paid for, and returning it bare would present a truncated document as a whole one. Extraction has no finding channel — the mechanism the validators use to say "this result is incomplete" (see cancel.go and docs/limits.md) — so the error is the only place that fact can live, and a caller who ignores it gets a silently short document.

The error is nil exactly when the extraction ran to completion.

func (*Document) Images

func (d *Document) Images() iter.Seq[ExtractedImage]

Images returns an iterator over the image XObjects drawn from the document's pages, in the same order ExtractImages reports them. Each image is decoded only as it is yielded, so — unlike ExtractImages, which materializes every decoded image at once — iteration keeps at most one decoded image live at a time (unless the caller retains them), and breaking out of the loop skips the remaining decode work entirely.

func (*Document) Locked

func (d *Document) Locked() bool

Locked reports whether the document carried encryption that could not be removed: it has an /Encrypt dictionary but no usable security handler, because the supplied password was wrong or the scheme is unsupported. Its strings and streams are still ciphertext.

Encrypted alone does not distinguish this from a successfully decrypted file (both keep Encrypted true). Callers that intend to read content, validate, extract, or re-encrypt should check Locked first: on a locked document RemoveEncryption is a no-op, ExtractText and the validators see ciphertext, and SetEncryption/Write refuse.

func (*Document) PageCount

func (d *Document) PageCount() int

PageCount returns the number of pages.

func (*Document) PageList

func (d *Document) PageList() []*Dictionary

PageList returns the document's page dictionaries in reading order.

func (*Document) RemoveEncryption

func (d *Document) RemoveEncryption()

RemoveEncryption drops encryption from a document that was decrypted on Read, so a subsequent Write emits it in the clear. It clears the security handler and removes /Encrypt from the trailer (and the object graph). It has no effect on a document whose content could not be decrypted (see Locked).

func (*Document) Repair

func (d *Document) Repair(level PDFALevel) []RepairAction

Repair applies a set of safe, well-defined fixes that remove common PDF/A conformance failures, and reports what it changed. It mutates the document in place; a subsequent Write emits the repaired file. Repair never touches page content or fonts — it only removes forbidden document-level constructs — so it cannot make a conformant document non-conformant.

It is not a substitute for validation: run ValidatePDFA afterwards to see what remains (missing embedded fonts, device colour without an output intent, and the like need information Repair does not have).

func (*Document) Resolve

func (d *Document) Resolve(obj Object) Object

Resolve follows an IndirectRef to its value, iterating through chains of references (a legal indirect object whose value is itself a reference). Returns the object unchanged if it is not an IndirectRef, and nil if any target in the chain does not exist or the chain cycles.

func (*Document) ResolveDict

func (d *Document) ResolveDict(obj Object) *Dictionary

ResolveDict resolves obj and type-asserts to *Dictionary.

func (*Document) SetEncryption

func (d *Document) SetEncryption(userPassword, ownerPassword string) error

SetEncryption configures the document to be encrypted on the next Write using the standard security handler with AES-256 (V5/R6, ISO 32000-2 §7.6.4). The user password opens the file for reading; the owner password additionally carries full permissions. Either may be empty.

It installs a fresh /Encrypt dictionary and a random file key, replacing any existing encryption. Write then enciphers every string and stream; the in-memory document stays in the clear, so it remains usable afterwards.

func (*Document) ValidatePAdES

func (d *Document) ValidatePAdES(raw []byte) []PAdESResult

ValidatePAdES assesses every signature in the document for PAdES conformance against the original file bytes. Results are ordered by the object number of the signature dictionary, the same deterministic order VerifySignatures uses.

func (*Document) VerifySignatures

func (d *Document) VerifySignatures(raw []byte) []SignatureResult

VerifySignatures verifies every signature in the document against the original file bytes. For each it recomputes the digest over the signed /ByteRange, checks it against the signature's messageDigest attribute, and verifies the signature over the signed attributes with the embedded certificate. It does not build a trust chain (no root store): a Valid result means the bytes inside the signed /ByteRange are intact and were signed by the holder of the embedded certificate's private key. It does NOT by itself mean the document was not modified after signing — an incremental update can change the rendered content while leaving the signed range intact. Combine Valid with CoversWholeDocument (see SignatureResult.DocumentUnmodified).

func (*Document) VerifySignaturesWithRoots

func (d *Document) VerifySignaturesWithRoots(raw []byte, roots *x509.CertPool) []SignatureResult

VerifySignaturesWithRoots verifies every signature as VerifySignatures does and, when roots is non-nil, additionally builds the signer's certificate chain to one of those trust anchors (using the certificates embedded in the CMS as intermediates), validating at the current time. The chain outcome is reported in TrustedChain / ChainErr and does not affect Valid, which remains a statement about the cryptographic integrity of the signed content.

Results are ordered by the object number of the signature dictionary, which is stable across runs (the objects are held in a map, whose iteration order is not) and meaningful: in a document signed by successive incremental updates the later signature is the later object.

func (*Document) Write

func (d *Document) Write(w io.Writer) error

Write serializes the document to the writer in PDF format.

A document decrypted on Read is re-encrypted with its retained key so it round-trips. A document that could not be decrypted (Document.Locked) is written back verbatim as a lossless passthrough under its preserved /Encrypt. Write regenerates the cross-reference section, emitting a cross-reference stream when the source used one and a traditional table otherwise.

func (*Document) WriteArchivalTimestamp

func (d *Document) WriteArchivalTimestamp(w io.Writer, original []byte, certs []*x509.Certificate, tsaCert *x509.Certificate, tsaKey crypto.Signer) error

WriteArchivalTimestamp adds a DSS (holding certs as validation material) and a document time-stamp over the whole file, as an incremental update. original must be the bytes the document was read from. The document should already carry a B-T signature for the result to reach B-LTA.

func (*Document) WriteContext

func (d *Document) WriteContext(ctx context.Context, w io.Writer) error

WriteContext is Write with cancellation.

Writing is usually fast, but its cost is the document's, not the caller's: a malformed cross-reference table can make one large stream reachable from thousands of object numbers, and the resulting output is legitimately enormous. cmd/corpusprobe streams exactly that case to io.Discard.

A cancelled write returns an error wrapping ctx.Err(). Whatever had already been written stays written — an io.Writer cannot be rewound — so the output is a truncated file, and the returned error is the only thing that says so. A caller that must not leave a partial file behind should write to a temporary and rename on success. See cancel.go.

func (*Document) WriteIncremental

func (d *Document) WriteIncremental(w io.Writer, original []byte, changed []int) error

WriteIncremental writes an incremental update: the original file bytes verbatim followed by only the objects listed in changed, a new cross-reference section whose /Prev chains back to the original, and a new trailer. The original bytes are preserved exactly, so any signature over them stays valid and the update can be undone by truncation.

changed lists the object numbers whose current value in d.Objects should be (re)written; numbers absent from d.Objects are recorded as free (deleted). Encrypted documents are not supported.

func (*Document) WriteSigned

func (d *Document) WriteSigned(w io.Writer, cert *x509.Certificate, key crypto.Signer) error

WriteSigned writes the document with an appended digital signature over its whole content: it adds a signature field, serializes with placeholders, computes the /ByteRange, signs the covered bytes with key (certificate cert embedded, adbe.pkcs7.detached, SHA-256), and fills /Contents. The in-memory document is not modified.

The document must not be encrypted (sign a plaintext document, or encrypt a signed one afterwards).

func (*Document) WriteSignedIncremental

func (d *Document) WriteSignedIncremental(w io.Writer, original []byte, cert *x509.Certificate, key crypto.Signer) error

WriteSignedIncremental signs the document as an incremental update: the original bytes are preserved verbatim and only the signature objects are appended. This is the correct way to add a signature without invalidating any signature already present. original must be the bytes the document was read from.

func (*Document) WriteSignedTimestamped

func (d *Document) WriteSignedTimestamped(w io.Writer, cert *x509.Certificate, key crypto.Signer, tsaCert *x509.Certificate, tsaKey crypto.Signer) error

WriteSignedTimestamped signs the document like WriteSigned and additionally embeds an RFC 3161 signature time-stamp over the signature value, produced by the supplied time-stamp authority certificate and key, yielding a PAdES-B-T signature.

type ExtractedImage

type ExtractedImage struct {
	ObjNum           int         // object number of the image XObject
	Width, Height    int         // pixel dimensions
	BitsPerComponent int         // bits per colour component
	ColorSpace       string      // colour space name (best effort)
	Filter           string      // the image codec (the last filter in the chain)
	Image            image.Image // decoded pixels, or nil if the codec was not decoded
	Encoded          []byte      // the encoded stream bytes when Image is nil
	Decoded          bool        // whether Image holds decoded pixels
	Note             string      // why the image was not decoded, when applicable
}

ExtractedImage is one image XObject: its geometry, its codec, and its decoded pixels when available.

type FacturXResult

type FacturXResult struct {
	// Violations is every non-conformance: pdf0's container findings, the PDF/A-3
	// base's, and the invoice rule engine's fatal ones — the findings whose
	// authority rejects a document for breaking them, plus that engine's
	// statements about its own run. An empty slice is the clean answer, as it is
	// for every other validator in this package.
	Violations []FacturXViolation

	// InvoiceWarnings is the advisory findings of the invoice rule engine: rules
	// their authority reports without rejecting the document, above all the CEN
	// syntax-binding rules (CII-SR-*, CII-DT-*) that hold an invoice to the
	// EN 16931 core subset of CII. A conforming Factur-X EXTENDED invoice trips
	// those by design — carrying more than the core is what EXTENDED is for — so
	// they are reported beside the verdict rather than inside it. See
	// adoptInvoiceFindings for why they are neither dropped nor merged.
	InvoiceWarnings []FacturXViolation

	Profile formalis.Profile // "" if not identifiable
	// CIUS is the Core Invoice Usage Specification the XMP names, when the
	// fx:ConformanceLevel names one instead of a data-richness profile —
	// "XRECHNUNG" is the level a ZUGFeRD 2.x producer really writes. The two
	// questions are separate and the metadata answers exactly one of them, so
	// pdf0 asks both (formalis.ProfileFor and formalis.CIUSFor) and reports what
	// it was told; a level that answers neither is a metadata finding.
	//
	// When the level named a CIUS, the embedded XML is validated by the rule set
	// the *invoice* declares in BT-24 rather than by the EN 16931 core at a
	// guessed profile, which formalis documents as the more reliable of the two
	// claims.
	CIUS    formalis.CIUS
	XMLName string // embedded invoice filename, "" if not found
	XML     []byte // decoded invoice XML bytes, nil if not found

	// InvoiceNotEvaluated names the EN 16931 rule families the invoice rule
	// engine publishes and does not evaluate, as that engine reported them for
	// this run (formalis.Report.NotEvaluated). It is what lets a caller tell "no
	// findings" from "no findings, and here is what nobody looked at".
	//
	// It is not turned into findings, deliberately. Every rule set has gaps, so a
	// finding per unevaluated family would fire on every conforming invoice ever
	// validated and would say nothing about this one. It is also not a limit
	// trip: nothing stopped, and running the same invoice again with a larger
	// budget would not close a gap that is a static property of the rule set.
	//
	// It is nil when the rule engine was never reached — no embedded XML — which
	// is the case InvoiceComplete's false zero value already covers.
	InvoiceNotEvaluated []formalis.RuleFamily

	// InvoiceComplete reports that the invoice rule engine evaluated every rule
	// that can be evaluated (formalis.Report.Complete): the run was not cut
	// short, and no evaluable family went unchecked. It is false when no invoice
	// XML was found and false when the XML could not be read, so it is never a
	// claim about a document nobody validated.
	//
	// It describes the invoice half only. pdf0's own container half — the PDF/A-3
	// base above all — implements a subset of ISO 19005 and publishes no
	// equivalent coverage table, so there is no honest whole-result version of
	// this question to answer, and a field called Complete would have claimed
	// one.
	InvoiceComplete bool
}

FacturXResult is the outcome of validating a Factur-X invoice: the container and EN 16931 violations found and, when identifiable, the declared conformance profile and the embedded invoice XML (returned for CIUS-layer validation).

func ValidateFacturX

func ValidateFacturX(doc *Document, rawData []byte) FacturXResult

ValidateFacturX checks whether doc is a conforming Factur-X invoice container. rawData is the original file bytes, needed for the PDF/A-3 byte-level checks.

It is ValidateFacturXContext with a background context.

func ValidateFacturXContext

func ValidateFacturXContext(ctx context.Context, doc *Document, rawData []byte) (res FacturXResult)

ValidateFacturXContext is ValidateFacturX with cancellation.

Both halves of the work honour ctx: the PDF/A-3 container validation, which is the larger of the two on every file in this repository's Factur-X corpus, and the EN 16931 rule engine, which threads the context through its own parse and rule loops.

A cancelled run reports itself the way every other pdf0 validator does — a finding under the reserved rule "limit", which IsCheckerFinding recognises — and keeps the findings gathered before it stopped. The rule engine uses that same identifier for the same event, so a caller draining Violations has one name to look for across container and invoice findings alike. What cannot happen is an empty result: a cancelled validation never looks clean.

type FacturXViolation

type FacturXViolation struct {
	// Rule is the identifier of the rule that was broken. pdf0's own container
	// rules are "structure", "attachment", "metadata" and "invoice-xml"; the
	// PDF/A-3 base's are ISO 19005 clauses under a "pdfa-3/" prefix; the invoice
	// engine's are adopted verbatim (EN 16931's BR-*, and formalis's reserved
	// "limit", "profile" and "root"). The reserved checker identifiers "limit"
	// and "internal" keep their bare names whichever half reports them, so
	// IsCheckerFinding recognises them — see adoptPDFAFindings.
	Rule string
	// Message describes what is wrong.
	Message string
	// Object is the PDF object number the finding anchors to, and 0 when it does
	// not anchor to one: a document-wide container finding, or any finding about
	// the invoice XML, which is a document inside the PDF and not an object of
	// it. Every finding adopted from the rule engine is of the second kind.
	Object int
	// Source names the authority that defines Rule, for a finding adopted from
	// the invoice rule engine: formalis.SourceEN16931 for a business rule,
	// formalis.SourceChecker for that engine's statements about its own run. It
	// is the zero Source on pdf0's own container findings, including the PDF/A-3
	// ones, because those rules are not formalis's to attribute — and
	// formalis.SourceNone is documented as the absent authority rather than as a
	// value any formalis finding carries, so the zero value cannot be mistaken
	// for a real attribution.
	Source formalis.Source
}

FacturXViolation is one finding of the Factur-X container validator: either a departure from a container rule pdf0 checks itself, or one adopted from the EN 16931 rule engine the embedded invoice XML is run through.

It exists because this validator composes two rule engines and the caller gets one report. pdf0's findings anchor to a PDF object; the invoice engine's anchor to a business term in an XML document and name the authority that wrote the rule. Until formalis v0.2.0 this validator carried formalis.Violation values directly, borrowing that type's Object field for PDF object numbers, which made Factur-X and Order-X the only findings in this package that could not satisfy Violation — the exception the package documentation had to keep explaining. Both halves now arrive in a type pdf0 owns, so they combine with every other validator's findings and IsCheckerFinding applies to them.

func (FacturXViolation) Error

func (v FacturXViolation) Error() string

Error renders the finding, naming the authority when the finding was adopted from the invoice rule engine. The authority is in the string and not only in the field for the reason formalis gives for putting it in its own: a rule identifier is unique within its authority and not outside it, so a logged finding that omits the authority is not identified.

func (FacturXViolation) ObjectNum

func (v FacturXViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (FacturXViolation) RuleID

func (v FacturXViolation) RuleID() string

RuleID returns the Factur-X container rule identifier, or the identifier the invoice rule engine minted for an adopted finding. It is unique only within FacturXViolation.Source, which names the authority.

type IndirectObject

type IndirectObject struct {
	Number     int
	Generation int
	Value      Object
}

IndirectObject represents a PDF indirect object definition (N G obj ... endobj).

func (IndirectObject) String

func (obj IndirectObject) String() string

type IndirectRef

type IndirectRef struct {
	Number     int
	Generation int
}

IndirectRef represents a PDF indirect object reference (N G R).

func (IndirectRef) String

func (ref IndirectRef) String() string

type Integer

type Integer int64

Integer represents a PDF integer value.

func (Integer) String

func (i Integer) String() string

type Lexer

type Lexer struct {
	// contains filtered or unexported fields
}

Lexer is a PDF tokenizer that reads from an io.ReaderAt.

func NewLexer

func NewLexer(data []byte) *Lexer

NewLexer creates a new Lexer reading from the given data.

func NewLexerFromReaderAt

func NewLexerFromReaderAt(r io.ReaderAt, size int64) (*Lexer, error)

NewLexerFromReaderAt creates a Lexer from an io.ReaderAt by reading all data. A reader that yields fewer than size bytes is an error: the zero padding a short read would leave behind counts as PDF whitespace, silently masking truncated input.

func (*Lexer) Data

func (l *Lexer) Data() []byte

Data returns the underlying data slice.

func (*Lexer) NextToken

func (l *Lexer) NextToken() (Token, error)

NextToken returns the next token from the input.

func (*Lexer) Position

func (l *Lexer) Position() int64

Position returns the current byte offset.

func (*Lexer) SetPosition

func (l *Lexer) SetPosition(offset int64)

SetPosition sets the current byte offset for random access.

type Name

type Name string

Name represents a PDF name object.

func (Name) String

func (n Name) String() string

type Null

type Null struct{}

Null represents the PDF null object.

func (Null) String

func (n Null) String() string

type Object

type Object interface {
	// contains filtered or unexported methods
}

Object is the interface all PDF objects implement.

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option configures a resource limit. Callers do not construct one directly; they call a With* function. Options are accepted by Read, ReadWithPassword, ReadContext, ReadWithPasswordContext and ParseXRefStream, and the resolved values are inherited by every validator and extractor that runs on the resulting Document.

func WithMaxCIDRangeSpan

func WithMaxCIDRangeSpan(n int) Option

WithMaxCIDRangeSpan caps the number of CIDs a single /W range entry may span (default 65536, the size of the CID space). Without it a range such as [0 2000000000 500] would ask for two billion map insertions.

func WithMaxCmapWork

func WithMaxCmapWork(n int) Option

WithMaxCmapWork caps the work spent expanding one TrueType cmap subtable of an expanding format — 4 or 12 — (default 1<<18). A hostile subtable can declare segments or groups whose combined character ranges cover the whole code space many times over.

A subtable the budget stops is returned as a *prefix* of the font's real coverage, marked partial, and the checks that would otherwise read a missing mapping as "this code has no glyph" decline instead and report the trip (see limits_report.go). Lowering this therefore costs coverage of the glyph-presence rules on large fonts; it never turns them into false positives.

func WithMaxContentStreamBytes

func WithMaxContentStreamBytes(n int) Option

WithMaxContentStreamBytes caps the decoded size of a single content stream or image sample buffer that will be scanned (default 64 MB). Larger streams are skipped. The largest real content stream measured is 29 MB.

func WithMaxDecodedContentBytes

func WithMaxDecodedContentBytes(n int64) Option

WithMaxDecodedContentBytes caps the total decoded content one validation run will materialize (default 512 MB). The per-stream cap stops a single stream exploding; this is the only bound on a whole run, and so the knob for "one upload must not exhaust my process". The heaviest real document measured needs 218 MB.

func WithMaxDecodedStreamBytes

func WithMaxDecodedStreamBytes(n int) Option

WithMaxDecodedStreamBytes caps the decompressed size of any single stream (default 100 MB). This is the decompression-bomb ceiling and applies to every FlateDecode and LZWDecode stream in the file; lowering it is the main lever for a service accepting untrusted uploads. The largest legitimate stream measured across the veraPDF corpus and a 978-file Common Crawl sample is 29 MB, so values below about 32 MB will start rejecting real documents.

The write-side object-stream cap derives from this value, so lowering it also makes Write emit smaller object-stream containers that the same configuration can read back.

func WithMaxICCProfileBytes

func WithMaxICCProfileBytes(n int) Option

WithMaxICCProfileBytes caps the decoded size of an ICC profile (default 8 MiB). The largest real profile measured is 1.8 MB.

func WithMaxObjectStreamBytes

func WithMaxObjectStreamBytes(n int64) Option

WithMaxObjectStreamBytes caps the aggregate decompressed size of all object streams in one document (default 512 MB). Object streams are the other compression-amplification path into a document: a small file can carry many containers that each inflate near the per-stream cap. The heaviest real document measured needs 9 MB.

func WithMaxPostScriptSteps

func WithMaxPostScriptSteps(n int) Option

WithMaxPostScriptSteps caps the total operators one type-4 (PostScript calculator) function evaluation may execute (default 1<<20), bounding a function whose loops would otherwise not terminate usefully.

func WithMaxRoleMapSteps

func WithMaxRoleMapSteps(n int) Option

WithMaxRoleMapSteps caps the total /RoleMap chain-follow steps across one PDF/UA structure-type check (default 1<<20), bounding a quadratic blowup on a large hostile role map.

func WithMaxTableGridFills

func WithMaxTableGridFills(n int64) Option

WithMaxTableGridFills caps the number of grid slots the PDF/UA table checks will fill for one table (default 1<<24), bounding a cell whose /RowSpan and /ColSpan claim a multi-million-slot area.

func WithMaxXMPPacketBytes

func WithMaxXMPPacketBytes(n int) Option

WithMaxXMPPacketBytes caps the size of an XMP packet that the property checks will build a node tree for (default 4 MiB). Larger packets are still checked for well-formedness, which streams; only the property-value rules are skipped.

Raising this is more expensive than it looks: tree construction is O(n²), so the worst case grows quadratically — roughly 3 s at the 4 MiB default and 12 s at 8 MiB. The largest real packet measured is 1.6 MB.

type OrderXProfile

type OrderXProfile string

OrderXProfile is an Order-X conformance profile, in increasing richness.

const (
	OrderXBasic    OrderXProfile = "BASIC"
	OrderXComfort  OrderXProfile = "COMFORT"
	OrderXExtended OrderXProfile = "EXTENDED"
)

type OrderXResult

type OrderXResult struct {
	Violations []OrderXViolation
	Profile    OrderXProfile // "" if not identifiable
	XMLName    string        // embedded order filename, "" if not found
	XML        []byte        // decoded order XML, nil if not found

	// OrderWarnings is the advisory findings of the order rule engine, kept out
	// of the verdict for the reason FacturXResult.InvoiceWarnings gives. It is
	// empty today and would stay empty if this field did not exist: no authority
	// has flagged an Order-X rule advisory, and formalis's five ORDER-* rules are
	// all fatal by its own decision. It exists so that the split at the adoption
	// seam is total — a warning that arrived tomorrow would otherwise be counted
	// as a non-conformance by every caller, silently, which is exactly how the
	// EN 16931 syntax bindings turned every conforming EXTENDED invoice into a
	// forty-finding failure the first time this bump was compiled.
	OrderWarnings []OrderXViolation

	// OrderNotEvaluated and OrderComplete report what the order rule engine did
	// and did not evaluate, exactly as FacturXResult's invoice pair does; that
	// documentation applies unchanged.
	//
	// OrderComplete is false for every order, and will stay false until the rule
	// engine implements more than the five mandatory head terms: formalis
	// publishes that gap as a fatal family under Coverage(SourceOrderX), so
	// OrderNotEvaluated is never empty for a run that reached the engine. That is
	// precisely the state this pair exists to make visible — a clean report from
	// a rule set that checks five things — and not a defect in any order.
	OrderNotEvaluated []formalis.RuleFamily
	OrderComplete     bool
}

OrderXResult is the outcome of validating an Order-X container.

func ValidateOrderX

func ValidateOrderX(doc *Document, rawData []byte) OrderXResult

ValidateOrderX checks whether doc is a conforming Order-X order container.

It is ValidateOrderXContext with a background context.

func ValidateOrderXContext

func ValidateOrderXContext(ctx context.Context, doc *Document, rawData []byte) (res OrderXResult)

ValidateOrderXContext is ValidateOrderX with cancellation. Both halves of the work honour ctx — the PDF/A-3 container validation and the order rules — and a cancelled run reports a "limit" finding rather than an empty result, exactly as ValidateFacturXContext does and for the same reasons.

type OrderXViolation

type OrderXViolation struct {
	Rule    string
	Message string
	Object  int
	Source  formalis.Source
}

OrderXViolation is one finding of the Order-X container validator: either a departure from a container rule pdf0 checks itself, or one adopted from the order rule engine the embedded order XML is run through. Its fields mean what FacturXViolation's mean, which documents them.

It is a type of its own rather than a shared invoice-container finding, for the reason every other validator in this package has one: an Order-X is a different standard judged by a different rule set, and Error has to say so — a caller holding one mixed report must be able to read "ORDER-03" and know it is the order type code and not something an invoice rule engine said. The two namespaces really do overlap, and have already collided once inside formalis itself, which renamed its Order-X rules out of CEN's BR-O-* numbering after a caller aggregating by identifier merged two unrelated defects. Sharing one type here would put that collision back one level up, in the type a caller switches on.

func (OrderXViolation) Error

func (v OrderXViolation) Error() string

Error renders the finding; see FacturXViolation.Error.

func (OrderXViolation) ObjectNum

func (v OrderXViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (OrderXViolation) RuleID

func (v OrderXViolation) RuleID() string

RuleID returns the Order-X container rule identifier, or the identifier the order rule engine minted for an adopted finding.

type PAdESLevel

type PAdESLevel string

PAdESLevel is a PAdES baseline conformance level.

const (
	PAdESNone PAdESLevel = ""      // not a PAdES signature (e.g. legacy adbe.*)
	PAdESBB   PAdESLevel = "B-B"   // basic: conformant CAdES-BES
	PAdESBT   PAdESLevel = "B-T"   // + a signature timestamp
	PAdESBLT  PAdESLevel = "B-LT"  // + long-term validation material (DSS)
	PAdESBLTA PAdESLevel = "B-LTA" // + a document timestamp over the DSS
)

type PAdESResult

type PAdESResult struct {
	// Field is the fully qualified name of the signature field whose /V
	// references this signature, exactly as SignatureResult.Field: the /T
	// partial names of the field and its ancestors joined with "." (ISO 32000-2
	// §12.7.4.2). It is empty when no field references the signature, or when no
	// field in the chain carries a /T.
	Field            string
	SubFilter        string     // the signature /SubFilter
	IsPAdES          bool       // uses a PAdES sub-filter
	Level            PAdESLevel // baseline level reached (PAdESNone if not PAdES)
	Conformant       bool       // meets the PAdES B-B baseline requirements
	Valid            bool       // the CMS signature cryptographically verifies
	CoversDocument   bool       // the /ByteRange reaches the end of the file
	SignerCommonName string
	TimestampValid   bool      // the signature time-stamp verifies (imprint + TSA signature)
	TimestampTime    time.Time // the time asserted by a verified signature time-stamp
	Issues           []string  // PAdES conformance problems
}

PAdESResult reports the PAdES assessment of one signature.

type PDFALevel

type PDFALevel int

PDFALevel represents a PDF/A conformance level.

const (
	PDFA1b PDFALevel = iota
	PDFA2b
	PDFA3b
	PDFA4
	// Level A (accessible) conformance: Level B plus tagged logical structure,
	// natural-language specification and Unicode character mapping. PDF/A-4 has
	// no Level A — accessibility there is expressed via PDF/UA-2.
	PDFA1a
	PDFA2a
	PDFA3a
)

func (PDFALevel) String

func (l PDFALevel) String() string

type PDFRViolation

type PDFRViolation struct {
	Rule    string
	Message string
	Object  int
}

PDFRViolation reports a departure from the PDF/R structural profile.

func ValidatePDFR

func ValidatePDFR(d *Document) []PDFRViolation

ValidatePDFR checks a document against the PDF/R structural profile.

func ValidatePDFRContext

func ValidatePDFRContext(ctx context.Context, d *Document) []PDFRViolation

ValidatePDFRContext is ValidatePDFR with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).

func (PDFRViolation) Error

func (v PDFRViolation) Error() string

func (PDFRViolation) ObjectNum

func (v PDFRViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (PDFRViolation) RuleID

func (v PDFRViolation) RuleID() string

RuleID returns the PDF/R rule identifier.

type PDFVTViolation

type PDFVTViolation struct {
	Rule    string // short rule identifier, base-profile violations prefixed "pdfx-4/" or "dpart/"
	Message string
	Object  int // object number the violation anchors to, 0 if N/A
}

PDFVTViolation reports a way in which a document departs from PDF/VT-1.

func ValidatePDFVT

func ValidatePDFVT(doc *Document) []PDFVTViolation

ValidatePDFVT checks whether doc conforms to PDF/VT-1 (ISO 16612-2). It requires conformance to the PDF/X-4 base profile, a valid document part hierarchy, and PDF/VT-1 identification in XMP. An empty result means no violations were found.

func ValidatePDFVT2

func ValidatePDFVT2(doc *Document) []PDFVTViolation

ValidatePDFVT2 checks whether doc conforms to PDF/VT-2 (ISO 16612-2). PDF/VT-2 is based on PDF/X-5 rather than PDF/X-4, so it additionally permits externally referenced content (reference XObjects); it is otherwise validated like PDF/VT-1. pdf0 has no PDF/X-5 validator, so the PDF/X-4 base is used with the reference-XObject prohibition relaxed — the PDF/X-5-specific external-reference rules are not asserted.

func ValidatePDFVT2Context

func ValidatePDFVT2Context(ctx context.Context, doc *Document) []PDFVTViolation

ValidatePDFVT2Context is ValidatePDFVT2 with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).

func ValidatePDFVTContext

func ValidatePDFVTContext(ctx context.Context, doc *Document) []PDFVTViolation

ValidatePDFVTContext is ValidatePDFVT with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).

func (PDFVTViolation) Error

func (v PDFVTViolation) Error() string

func (PDFVTViolation) ObjectNum

func (v PDFVTViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (PDFVTViolation) RuleID

func (v PDFVTViolation) RuleID() string

RuleID returns the PDF/VT rule identifier.

type PDFXLevel

type PDFXLevel int

PDFXLevel identifies a PDF/X conformance level.

const (
	// PDFX4 is PDF/X-4 with an embedded ICC destination profile (ISO 15930-7).
	PDFX4 PDFXLevel = iota
	// PDFX4p is PDF/X-4p, which permits an externally referenced destination
	// profile instead of an embedded one.
	PDFX4p
	// PDFX1a is PDF/X-1a (ISO 15930-1/4): CMYK, grayscale and spot colour only,
	// no transparency, defined against PDF 1.3/1.4.
	PDFX1a
	// PDFX3 is PDF/X-3 (ISO 15930-3/6): PDF/X-1a plus ICC-managed colour, still
	// no transparency, PDF 1.3/1.4.
	PDFX3
	// PDFX6 is PDF/X-6 (ISO 15930-9): the PDF 2.0-based successor to PDF/X-4.
	PDFX6
)

func (PDFXLevel) String

func (l PDFXLevel) String() string

type PDFXViolation

type PDFXViolation struct {
	Rule    string // short rule identifier, e.g. "output-intent"
	Message string
	Object  int // object number the violation anchors to, 0 if N/A
}

PDFXViolation reports a way in which a document departs from a PDF/X level.

func ValidatePDFX

func ValidatePDFX(doc *Document, level PDFXLevel) []PDFXViolation

ValidatePDFX checks whether doc conforms to the given PDF/X level. An empty result means no violations were found.

func ValidatePDFXContext

func ValidatePDFXContext(ctx context.Context, doc *Document, level PDFXLevel) []PDFXViolation

ValidatePDFXContext is ValidatePDFX with cancellation; a cancelled run reports itself under the rule "limit" (see cancel.go).

func (PDFXViolation) Error

func (v PDFXViolation) Error() string

func (PDFXViolation) ObjectNum

func (v PDFXViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (PDFXViolation) RuleID

func (v PDFXViolation) RuleID() string

RuleID returns the PDF/X rule identifier.

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

Parser builds PDF Object values from a token stream.

func NewParser

func NewParser(data []byte) *Parser

NewParser creates a new Parser for the given data.

func NewParserFromLexer

func NewParserFromLexer(lexer *Lexer) *Parser

NewParserFromLexer creates a new Parser using the given lexer.

func (*Parser) Lexer

func (p *Parser) Lexer() *Lexer

Lexer returns the underlying lexer (for position access, etc).

func (*Parser) ParseIndirectObject

func (p *Parser) ParseIndirectObject() (*IndirectObject, error)

ParseIndirectObject parses an indirect object definition: N G obj ... endobj

func (*Parser) ParseObject

func (p *Parser) ParseObject() (Object, error)

ParseObject parses any PDF object from the token stream.

type Real

type Real float64

Real represents a PDF real (floating-point) value.

func (Real) String

func (r Real) String() string

type RepairAction

type RepairAction struct {
	Description string
}

RepairAction records one fix applied by Repair.

type RevocationInfo

type RevocationInfo struct {
	Status    RevocationStatus
	Source    string    // "OCSP", "CRL" or "" when unknown
	RevokedAt time.Time // when the certificate was revoked, if revoked
}

RevocationInfo reports a certificate's revocation status and where it came from.

func CheckCertRevocation

func CheckCertRevocation(cert, issuer *x509.Certificate, crls, ocsps [][]byte) RevocationInfo

CheckCertRevocation determines the revocation status of cert (issued by issuer) from the supplied CRLs and OCSP responses (DER). Each source must be signed by issuer to be trusted. OCSP is consulted first; a definite verdict (good or revoked) is returned as soon as one source gives it.

type RevocationStatus

type RevocationStatus int

RevocationStatus is the outcome of a revocation check.

const (
	RevocationUnknown RevocationStatus = iota // no usable material said either way
	RevocationGood                            // asserted not revoked
	RevocationRevoked                         // asserted revoked
)

func (RevocationStatus) String

func (s RevocationStatus) String() string

type Serializer

type Serializer struct {
	// contains filtered or unexported fields
}

Serializer writes PDF objects to an io.Writer.

func NewSerializer

func NewSerializer(w io.Writer) *Serializer

NewSerializer creates a new Serializer writing to w.

func (*Serializer) Offset

func (s *Serializer) Offset() int64

Offset returns the current byte offset (total bytes written).

func (*Serializer) WriteIndirectObject

func (s *Serializer) WriteIndirectObject(obj *IndirectObject) error

WriteIndirectObject writes an indirect object definition to the output.

func (*Serializer) WriteObject

func (s *Serializer) WriteObject(obj Object) error

WriteObject writes any PDF object to the output.

type SignatureResult

type SignatureResult struct {
	// Field is the FULLY QUALIFIED name of the signature field whose /V
	// references this signature dictionary: the field's own /T partial name
	// prefixed by the /T of every ancestor field, joined with "." (ISO 32000-2
	// §12.7.4.2). The qualified name is what identifies a field uniquely in a
	// document — a partial name is only unique among its siblings — so it is
	// what a caller can display, log, or look the field up by. For the common
	// flat form (a top-level field, as pdf0's own signing produces) it is just
	// the partial name, e.g. "Signature1".
	//
	// It is empty when nothing names the signature: a bare signature dictionary
	// that no field's /V points at, or a field chain in which neither the field
	// nor any of its ancestors carries a /T.
	Field               string
	SignerCommonName    string         // Subject CN of the signing certificate
	CoversWholeDocument bool           // the /ByteRange covers the whole file except the /Contents window
	Valid               bool           // the signed bytes are intact and the signature verifies
	SigningTime         time.Time      // signing-time signed attribute, if present (self-asserted, untrusted)
	TrustedChain        bool           // the certificate chains to a supplied trust root
	ChainErr            error          // why the chain did not build (when roots were given)
	Revocation          RevocationInfo // revocation status from the document's DSS material
	Err                 error          // why signature verification failed, if it did
}

SignatureResult reports the outcome of verifying one signature field.

Valid and CoversWholeDocument are independent and must both be consulted: Valid says the bytes inside the signed /ByteRange are intact and were signed by the embedded certificate's key, but it says nothing about bytes OUTSIDE that range. A signed document can be modified after signing by an incremental update — the original signed range stays intact (Valid == true) while the rendered content changes (CoversWholeDocument == false). Use DocumentUnmodified for the combined "signed and nothing was changed" verdict.

func (SignatureResult) DocumentUnmodified

func (r SignatureResult) DocumentUnmodified() bool

DocumentUnmodified reports the safe combined verdict: the signature cryptographically verifies AND it covers the whole document, so nothing was changed after signing. Callers that read only Valid accept a document whose content was altered by a post-signing incremental update; prefer this.

type Stream

type Stream struct {
	Dict Dictionary
	Data []byte // raw (encoded) stream data
}

Stream represents a PDF stream object.

type String

type String struct {
	Value []byte
	IsHex bool // preserve literal vs hex for round-tripping
}

String represents a PDF string value (literal or hexadecimal).

func (String) String

func (s String) String() string

type Token

type Token struct {
	Type   TokenType
	Value  []byte // raw bytes of the token
	Offset int64  // byte offset in input
}

Token represents a single lexer token.

func (Token) String

func (t Token) String() string

type TokenType

type TokenType int

TokenType identifies the type of a lexer token.

const (
	TokenBoolean    TokenType = iota // true, false
	TokenInteger                     // 123, -98
	TokenReal                        // 3.14, -.002
	TokenString                      // (literal) or <hex>
	TokenName                        // /SomeName
	TokenArrayStart                  // [
	TokenArrayEnd                    // ]
	TokenDictStart                   // <<
	TokenDictEnd                     // >>
	TokenStream                      // stream keyword
	TokenEndStream                   // endstream keyword
	TokenObj                         // obj keyword
	TokenEndObj                      // endobj keyword
	TokenRef                         // R keyword
	TokenXref                        // xref keyword
	TokenTrailer                     // trailer keyword
	TokenStartXref                   // startxref keyword
	TokenNull                        // null keyword
	TokenEOF
)

func (TokenType) String

func (t TokenType) String() string

type UAViolation

type UAViolation struct {
	Clause  string // ISO 14289-1 clause
	Message string
	Object  int
}

UAViolation is a PDF/UA-1 (ISO 14289-1) accessibility conformance failure.

func ValidatePDFUA

func ValidatePDFUA(doc *Document) []UAViolation

ValidatePDFUA checks a document against the foundational PDF/UA-1 (ISO 14289-1) requirements: the document must be tagged, carry a structure tree and a default language, be configured to display its title, and give every figure alternate text. It is a partial validator — a clean result means the implemented checks passed, not full PDF/UA conformance.

func ValidatePDFUA2

func ValidatePDFUA2(d *Document) []UAViolation

ValidatePDFUA2 checks a document against PDF/UA-2. Findings reuse the UAViolation type; clause identifiers follow ISO 14289-2.

func ValidatePDFUA2Context

func ValidatePDFUA2Context(ctx context.Context, d *Document) []UAViolation

ValidatePDFUA2Context is ValidatePDFUA2 with cancellation; see ValidatePDFUAContext for how a cancelled run reports itself.

func ValidatePDFUAContext

func ValidatePDFUAContext(ctx context.Context, doc *Document) []UAViolation

ValidatePDFUAContext is ValidatePDFUA with cancellation. When ctx ends the run stops and returns the findings gathered so far plus one under the clause "limit" recording the cancellation, which IsCheckerFinding reports as a checker finding — so a cancelled run cannot be mistaken for a clean one. See cancel.go.

func (UAViolation) Error

func (v UAViolation) Error() string

func (UAViolation) ObjectNum

func (v UAViolation) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (UAViolation) RuleID

func (v UAViolation) RuleID() string

RuleID returns the ISO 14289 clause identifier.

type ValidationError

type ValidationError struct {
	Rule    string    // e.g., "6.1.3" (ISO 19005 clause)
	Level   PDFALevel // the level that requires this rule
	Message string
	Object  int // object number, 0 if N/A
}

ValidationError describes a single PDF/A conformance violation.

func ValidatePDFA

func ValidatePDFA(doc *Document, level PDFALevel) []ValidationError

ValidatePDFA checks doc against the implemented rules for the given PDF/A level and returns the violations found. An empty result means "none of the implemented checks fired", not a guarantee of full conformance: the validator covers a subset of ISO 19005 (see the package README). Because it takes no raw bytes, it also skips every byte-level file-structure rule — use ValidatePDFABytes when you have the file bytes and want those too.

func ValidatePDFABytes

func ValidatePDFABytes(doc *Document, level PDFALevel, rawData []byte) []ValidationError

ValidatePDFABytes checks doc against the implemented rules for the given PDF/A level and returns the violations found. If rawData is non-nil, the byte-level file-structure rules run too (e.g. no data after %%EOF). An empty result means no implemented check fired, not a guarantee of full conformance (the validator covers a subset of ISO 19005).

func ValidatePDFABytesContext

func ValidatePDFABytesContext(ctx context.Context, doc *Document, level PDFALevel, rawData []byte) []ValidationError

ValidatePDFABytesContext is ValidatePDFABytes with cancellation; see ValidatePDFAContext for how a cancelled run reports itself.

func ValidatePDFAContext

func ValidatePDFAContext(ctx context.Context, doc *Document, level PDFALevel) []ValidationError

ValidatePDFAContext is ValidatePDFA with cancellation. Validating a large document is the package's longest-running operation, so this is the variant a caller under a deadline should use.

When ctx ends the run stops and returns the findings gathered so far plus one under the rule "limit" recording the cancellation, which IsCheckerFinding reports as a checker finding. A cancelled run therefore never looks like a clean bill of health: an empty result is impossible, and the caller can tell "no violations found" apart from "pdf0 did not get to look". See cancel.go.

func (ValidationError) Error

func (e ValidationError) Error() string

func (ValidationError) ObjectNum

func (e ValidationError) ObjectNum() int

ObjectNum returns the anchoring object number, 0 if N/A.

func (ValidationError) RuleID

func (e ValidationError) RuleID() string

RuleID returns the ISO 19005 clause identifier.

type Violation

type Violation interface {
	error
	// RuleID returns the identifier of the violated rule — an ISO clause like
	// "6.1.3" or a short rule name like "output-intent" — as carried in the
	// concrete type's Rule (or Clause) field.
	RuleID() string
	// ObjectNum returns the object number the finding anchors to, 0 if the
	// finding is not tied to a specific object.
	ObjectNum() int
}

Violation is the common face of every validator finding. Each validator keeps its own concrete type — ValidationError (PDF/A), UAViolation (PDF/UA), PDFXViolation, PDFVTViolation, PDFRViolation, DPartViolation, FacturXViolation, OrderXViolation — with the fields and Error formatting of its standard, but all of them satisfy this interface, so findings from different validators can be collected, filtered and reported together:

var all []pdf0.Violation
for _, e := range pdf0.ValidatePDFA(doc, pdf0.PDFA2b) {
	all = append(all, e)
}
for _, e := range pdf0.ValidatePDFUA(doc) {
	all = append(all, e)
}

There is no longer an exception. The Factur-X and Order-X validators return a result struct rather than a slice, because they carry the extracted invoice XML and its coverage alongside the findings, but the findings themselves are FacturXViolation and OrderXViolation values and satisfy this interface like any other. They used to hold formalis.Violation, an external type this package could not extend, which also put them outside IsCheckerFinding — so a cancelled or panicking run had no way to say "pdf0 stopped early" that a caller could tell apart from a conformance failure. That is why those two validators had no Context variant, and why they have one now.

type XRefEntry

type XRefEntry struct {
	Offset        int64
	Generation    int
	Free          bool
	Compressed    bool
	StreamObjNum  int // object stream containing this object
	IndexInStream int // index within object stream
}

XRefEntry represents a single cross-reference table entry.

type XRefTable

type XRefTable struct {
	Entries map[int]XRefEntry
}

XRefTable holds all cross-reference entries indexed by object number.

func ParseXRefStream

func ParseXRefStream(stream *Stream, opts ...Option) (*XRefTable, error)

ParseXRefStream parses a cross-reference stream.

Resource limits default to values safe for untrusted input; pass With* options to change them. (*Document) supplies its own resolved limits when it calls this during Read, so a document read with options keeps them here.

func ParseXRefTable

func ParseXRefTable(data []byte, pos int64) (*XRefTable, error)

ParseXRefTable parses a traditional xref table starting at the given position. The position should be right after the "xref" keyword.

Directories

Path Synopsis
cmd
corpusprobe command
Command corpusprobe stress-tests the parser against a directory of (untrusted) PDFs, recording parse outcomes and — most importantly — any panics or hangs, which represent robustness bugs: the parser must return an error, never crash or loop, on malformed input.
Command corpusprobe stress-tests the parser against a directory of (untrusted) PDFs, recording parse outcomes and — most importantly — any panics or hangs, which represent robustness bugs: the parser must return an error, never crash or loop, on malformed input.
corpustime command
Command corpustime times each parse stage of one PDF with a generous budget, to distinguish a truly-hanging stage from a merely-slow huge file.
Command corpustime times each parse stage of one PDF with a generous budget, to distinguish a truly-hanging stage from a merely-slow huge file.
pdf0 command
Command pdf0 is a small command-line front end to the pdf0 library: inspect, validate, decrypt, and encrypt PDF files.
Command pdf0 is a small command-line front end to the pdf0 library: inspect, validate, decrypt, and encrypt PDF files.
rulecoverage command
Command rulecoverage reports how the pdf0 PDF/A validator's rule coverage compares to the veraPDF validation profiles — the machine-readable inventory of every PDF/A rule the reference validator checks.
Command rulecoverage reports how the pdf0 PDF/A validator's rule coverage compares to the veraPDF validation profiles — the machine-readable inventory of every PDF/A rule the reference validator checks.
examples
extract_images command
Command extract_images builds a small PDF holding two image XObjects, writes it, reads it back, and walks the images with the lazy Images iterator.
Command extract_images builds a small PDF holding two image XObjects, writes it, reads it back, and walks the images with the lazy Images iterator.
sign_verify command
Command sign_verify signs a one-page document with a self-signed certificate generated in-process and verifies it, showing the verdict a caller must actually read: DocumentUnmodified (Valid AND CoversWholeDocument) plus TrustedChain from VerifySignaturesWithRoots.
Command sign_verify signs a one-page document with a self-signed certificate generated in-process and verifies it, showing the verdict a caller must actually read: DocumentUnmodified (Valid AND CoversWholeDocument) plus TrustedChain from VerifySignaturesWithRoots.
simple_pdf command
simple_pdf17 command
simple_pdfa command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL