Implement core PDF capabilities in Go under github.com/lightningrag/pdf-go: file structure parsing, generic objects, page traversal, and (incrementally) writing and transforms.
| Go | Role |
|---|---|
pdf |
Entry types: PdfReader, PdfWriter, constants, errors; page-range parsing |
pdf/generic |
PDF syntax-layer objects and read/write |
pdf/filters |
Stream filters |
(future) pdf/annotations |
Annotation subtypes, etc. |
Integration tests may use PDF fixtures supplied via environment or relative paths (see candidate roots and skip logic in pdf package tests); missing fixtures cause the relevant tests to Skip.
- Buffering: read the whole file into
[]bytefor xref handling andSectionReaderslices. - startxref: scan backward from EOF for
startxrefand its offset. - xref chain: walk from the newest segment via
/Prev; supports:- classic
xreftable +trailerdictionary; - PDF 1.5+ xref stream (
/Type /XRef) with/W,/Index,/Size; - xref stream decompression with
/FlateDecode+ PNG predictor (e.g. 12) in/DecodeParms(important for this stage).
- classic
- Trailer merge: keys are written only when missing (common semantics for incremental updates: existing keys win).
- Object parsing:
generic.ReadObject; indirect refs resolved viageneric.PDFGetObjectcallback. - ObjStm:
/Type /ObjStmdecoded with the samedecodeStreamData, then parseN/Firstindex; prefer the object index inside the stream (third column of/Wtype-2 entries in xref) to locate object bodies instead of scanning every object in the stream (fallback to lookup by number when index and object numbers disagree). - Page flattening: recurse
/Root→/Pages→/Kids, merging inheritable keys (/Resources,/MediaBox,/CropBox,/Rotate,/ArtBox,/TrimBox,/BleedBox,/UserUnit) consistent with common reader page-tree flattening.
- Maintain a linear
objects []generic.Object(1-based numbers = slice index + 1). - Emit
%PDF-1.7, eachn 0 objblock,xref,trailer,startxref,%%EOF; trailer includes/ID(two 16-byte random IDs) by default, optionalOmitTrailerDocumentIDfor tests/deterministic output.Bytes()validates at least one object and that the last object is/Catalog, otherwise returns a clear error. - xref offsets: object offsets start after
%PDF-1.7\n(per spec). AppendPagesFromReader/AppendPagesFromReaderPageRange: deep-clone flat page dicts fromPdfReaderinclone.go(seendedupes indirects). Empty writer creates/Pagesand/Catalog; non-empty writer requires the last object to be/Catalog,/Pagesas indirect or inline dict (inline is promoted withAddObjectand catalog/Pagesupdated), new pages merged into/Kids, catalog moved back to end of object table to satisfy write conventions.PageRangeis turned into index lists viaPageIndices(n)on the same path.
- Resource fixtures: integration tests run when present (relative paths in
reader_test.go); otherwiseSkip. assets/example.pdf:TestAssetsExamplePDFchecks the sample PDF shipped with the repo.- Manifest-driven samples:
TestSampleFilesManifestAgainstReaderaligns with externalfiles.json; exceptions and xref policy indocs/SAMPLE_FILES_TESTING.md, quick referencedocs/TESTING.md. TestWriterMinimalRoundtrip: hand-written minimal page graph, read/write roundtrip checksNumPages()==1.
Not yet implemented: encryption/decryption (password verify + RC4/AES object crypto); incremental writing (write_stream / _write_increment); layout-mode text extraction (CMap-level mapping exists, full layout needs font metrics and text space); RTL text ordering; image pixel extraction (decode compressed image bytes to raster); form appearance stream generation (TextStreamAppearance: full text-field appearance with metrics and wrapping); cross-document outlines resolving remote /D page indices after opening external PDFs; xref rebuild for damaged PDFs (full-file scan for obj keywords, etc.). (Partially supported: /Link and outlines with /URI, /Launch, in-document GoTo/Dest, GoToR/Launch /F paths (Link.uri / OutlineNode.URI/RemotePath; remote page index -1 when external files are not opened).)