Help us shape the future of Go! Take the 2026 Go Developer Survey

pdf

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 13 Imported by: 4

README

pdf

Go Reference CI

Robust PDF text extraction in pure Go — with glyph positions, hardened against real-world (and hostile) files.

Zero dependencies. Built entirely on Go's standard library.

import "github.com/giraffesyo/pdf"

doc, err := pdf.Extract(ctx, readerAt, size)
if err != nil { ... }

text := doc.Text()             // whole document, plain text
page := doc.Pages[0]
line := page.Text()            // per-page reconstruction
glyphs := page.Glyphs          // []Glyph{Text, X, Y, Advance, Size}

Page.Text reconstructs reading order from glyph positions: lines are clustered by baseline, and word boundaries are recovered from glyph gaps and font metrics — so PDFs that encode no space characters at all still come out readable.

Why another PDF text extractor

This package grew out of converting large corpora of real-world documents with ledongthuc/pdf, whose built-in text extraction breaks on files that are common in the wild:

Real-world file ledongthuc/pdf this package
Google Docs exports (text inside Form XObjects) extracts nothing full text
Word exports (Identity-H fonts + ToUnicode CMaps) U+FFFD soup decoded
Type3 fonts with ToUnicode but an /Encoding dict control-char garbage decoded
Td/T*-positioned text (most PDFs) positions lost positioned
Array token split across /Contents segments lexer hangs forever handled
Decompression bombs, stalled filter chains unbounded CPU/memory hard budgets
Cyclic page trees stack overflow (crash) rejected upfront
Inline images (BI/ID/EI) derails the lexer skipped cleanly

Everything is implemented here, from ISO 32000 directly, with no external dependencies: the object layer (cross-reference tables and streams, object streams, hybrid references, stream filters, and standard-handler decryption), the standard font encodings and Adobe Glyph List, and everything from the content stream down — lexer, interpreter, text state machine, CTM/Form-XObject handling, ToUnicode parsing, CID widths.

Undecodable glyphs (no ToUnicode, no standard encoding) are dropped, not emitted as garbage, so image-only or outlined-text PDFs yield empty output you can detect, instead of plausible-looking noise.

Limitations

  • No OCR: scanned pages and text converted to vector outlines have no text to extract.
  • No layout analysis beyond line/word reconstruction: complex multi-column layouts may interleave.
  • Encrypted files open only when the empty user or owner password unlocks them (RC4, AES-128, AES-256); password-protected files return an error.
  • Image filters (DCT/JPX/CCITT/JBIG2) are not decoded — text extraction never needs them.

Benchmarks

The benchmarks/ directory is a separate module (so its dependencies stay out of this one) that compares extraction against ledongthuc/pdf and rsc.io/pdf over identical synthetic corpora. The corpus checks both whether the expected text is recovered and whether extraction completes safely. A comparator that returns incorrect text, errors, or panics is excluded from the performance run for that fixture.

Results below were measured on 2026-07-15 from the current worktree based on commit 4d13aa9, using Go 1.26.4 on macOS 26.5.1 (darwin/arm64, Apple M5 Pro). Values are one run of go test -bench . -benchmem -run '^$' -count=1 ./...; rerun on your own hardware before making a performance decision.

Corpus this package ledongthuc/pdf rsc.io/pdf
simple ok ok incorrect text
Form XObject ok incorrect text incorrect text
Flate-compressed content ok ok incorrect text
xref stream ok ok incorrect text
object stream ok ok incorrect text
RC4-encrypted ok unsupported unsupported

Latency (ns/op):

Corpus this package ledongthuc/pdf
simple 12,548 29,796
Form XObject 15,342 incorrect text
Flate content 20,080 41,339
xref stream 13,168 26,940
object stream 19,330 47,061
RC4-encrypted 61,169 unsupported

Memory (B/op) and allocations (allocs/op):

Corpus this package B/op ledongthuc/pdf B/op this package allocs/op ledongthuc/pdf allocs/op
simple 53,120 62,963 153 368
Form XObject 57,480 incorrect text 198 incorrect text
Flate content 98,553 107,891 171 386
xref stream 54,008 62,882 157 365
object stream 54,530 100,340 176 541
RC4-encrypted 85,727 unsupported 315 unsupported

To reproduce the support matrix and performance measurements:

cd benchmarks
go test -run TestCompetitorComparison -v ./...   # support matrix
go test -bench . -benchmem -run '^$' -count=1 ./... # raw results above
# For a less noisy local comparison, repeat and analyze the output:
go test -bench . -benchmem -run '^$' -count=5 ./...

The corpus is synthetic and deliberately small: it measures parser and extractor behavior, not throughput on a representative production document set. It does show that this package recovers the expected text from every fixture, including Form XObjects, xref streams, object streams, and encrypted files.

pdftest

github.com/giraffesyo/pdf/pdftest builds minimal synthetic PDFs for tests (in the spirit of httptest): document skeletons, composite fonts, ToUnicode CMaps, Form XObjects, segmented content streams. This package's own regression suite is built on it — every failure pattern above is reproduced synthetically, with fuzzing on top.

License

MIT. Embeds the Adobe Glyph List (Apache-2.0) for glyph-name decoding.

Documentation

Overview

Package pdf extracts text from PDF files, with glyph positions.

Extract returns per-page positioned glyphs; Page.Text reconstructs plain text by clustering glyphs into lines and inserting word spacing derived from glyph gaps and font metrics.

The package is pure Go with no external dependencies. It implements the PDF object layer (cross-reference tables and streams, object streams, stream filters, and standard-handler decryption) natively per ISO 32000, and on top of it a content-stream lexer, interpreter, and font decoder tuned for real-world files: it descends into Form XObjects (where e.g. Google Docs exports keep their text), honors /ToUnicode even alongside an /Encoding dictionary, tracks positions through every text operator, never loops on tokens straddling /Contents array segments, and defends against decompression bombs, stalled filter chains, and cyclic page trees.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Document

type Document struct {
	Pages []Page
}

Document is the extraction result for a whole file.

func Extract

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

Extract parses the PDF in r and extracts every page's glyphs. Malformed pages yield whatever was decoded before the failure; a malformed file returns an error. The context is checked between pages.

func (*Document) Text

func (d *Document) Text() string

Text reconstructs the whole document's plain text: pages separated by blank lines, empty pages skipped.

type Glyph

type Glyph struct {
	Text    string  // decoded text, non-empty
	X, Y    float64 // origin
	Advance float64 // horizontal advance
	Size    float64 // effective font size
}

Glyph is one decoded glyph (or glyph cluster) with its position in unrotated page space.

type Page

type Page struct {
	Glyphs []Glyph
}

Page holds the glyphs of one page in content order.

func (Page) Text

func (p Page) Text() string

Text reconstructs a page's plain text from glyph positions: glyphs are clustered into lines by Y, ordered by X, and spaces are inserted where the horizontal gap between glyphs is too wide to be kerning.

Directories

Path Synopsis
internal
crypt
Package crypt implements the PDF standard security handler (ISO 32000-1 §7.6.3 and ISO 32000-2 §7.6.4): RC4 and AES stream/string decryption with the file key derived from an empty user or owner password.
Package crypt implements the PDF standard security handler (ISO 32000-1 §7.6.3 and ISO 32000-2 §7.6.4): RC4 and AES stream/string decryption with the file key derived from an empty user or owner password.
encoding
Package encoding implements the simple-font character encodings of ISO 32000-1 Annex D and the Adobe Glyph List glyph-name algorithm.
Package encoding implements the simple-font character encodings of ISO 32000-1 Annex D and the Adobe Glyph List glyph-name algorithm.
filter
Package filter implements the PDF stream decode filters of ISO 32000-1 §7.4 that text extraction needs: FlateDecode, LZWDecode, ASCIIHexDecode, ASCII85Decode and RunLengthDecode, with the PNG and TIFF predictors.
Package filter implements the PDF stream decode filters of ISO 32000-1 §7.4 that text extraction needs: FlateDecode, LZWDecode, ASCIIHexDecode, ASCII85Decode and RunLengthDecode, with the PNG and TIFF predictors.
object
Package object is a native PDF object layer: a lexer and parser for the COS object syntax (ISO 32000-1 §7.2–7.3), cross-reference tables and streams (§7.5), and a Value model for navigating the resulting object graph.
Package object is a native PDF object layer: a lexer and parser for the COS object syntax (ISO 32000-1 §7.2–7.3), cross-reference tables and streams (§7.5), and a Value model for navigating the resulting object graph.
safeio
Package safeio bounds reads from untrusted streams: decompression bombs and stalled filter chains must cost bounded memory and CPU.
Package safeio bounds reads from untrusted streams: decompression bombs and stalled filter chains must cost bounded memory and CPU.
Package pdftest builds minimal synthetic PDF files for tests, in the spirit of net/http/httptest.
Package pdftest builds minimal synthetic PDF files for tests, in the spirit of net/http/httptest.

Jump to

Keyboard shortcuts

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