Documentation
¶
Overview ¶
Package experimental is a question-first layer over gomupdf.
The base library hands you a bag of positioned fragments (spans, words, quads, blocks) and leaves the geometry to you. This package lets you ask the page questions instead:
v, _ := page.ValueRightOf("Total") // key/value extraction
t := page.TextIn(box) // crop text by region
hits := page.Find(`\d{4}-\d{4}`) // regex with locations
One coordinate model is used everywhere: Rect, origin top-left, y grows down, units are PDF points. Conversions from the base library's two rect shapes (gomupdf.Rect{X,Y,W,H} and geometry.Rect{X0,Y0,X1,Y1}) live here so callers never juggle both.
Status: experimental. Heuristics are best-effort and tuned for structured, layout-rich documents. Signatures may change.
Index ¶
- Variables
- func ClusterFloats(values []float64, tol float64) [][]float64
- func CollectBlock(rows []Row, start int, opt BlockOptions) []string
- func Mean(values []float64) float64
- func Merge(out string, sources ...any) error
- type BlockOptions
- type Bookmark
- type Doc
- func (d *Doc) AppendImage(src any) error
- func (d *Doc) AppendPDF(src any) error
- func (d *Doc) Bytes() ([]byte, error)
- func (d *Doc) Close()
- func (d *Doc) Find(pattern string, opts ...QueryOption) ([]Match, error)
- func (d *Doc) Images() ([]Image, error)
- func (d *Doc) Info() (Info, error)
- func (d *Doc) Lines() ([]string, error)
- func (d *Doc) NumPages() int
- func (d *Doc) Outline() ([]Bookmark, error)
- func (d *Doc) Page(i int) (*Page, error)
- func (d *Doc) Pages() iter.Seq2[int, *Page]
- func (d *Doc) Raw() *gomupdf.Document
- func (d *Doc) Save(path string) error
- func (d *Doc) SaveImages(dir string) ([]string, error)
- func (d *Doc) SavePNGs(dir string, opts ...RenderOption) ([]string, error)
- func (d *Doc) Tables(opts ...TableOption) ([]Table, error)
- func (d *Doc) Text() (string, error)
- func (d *Doc) Thumbnail(opts ...RenderOption) (image.Image, error)
- func (d *Doc) ValueBelow(label string, opts ...QueryOption) (string, bool, error)
- func (d *Doc) ValueRightOf(label string, opts ...QueryOption) (string, bool, error)
- type Image
- type Info
- type Link
- type Match
- type OpenOption
- type Page
- func (p *Page) Bound() (Rect, error)
- func (p *Page) Find(pattern string, opts ...QueryOption) ([]Match, error)
- func (p *Page) Image(opts ...RenderOption) (image.Image, error)
- func (p *Page) Images() ([]Image, error)
- func (p *Page) Lines() ([]string, error)
- func (p *Page) Links() ([]Link, error)
- func (p *Page) PNG(opts ...RenderOption) ([]byte, error)
- func (p *Page) Raw() *gomupdf.Page
- func (p *Page) Rows(opts ...RowOption) ([]Row, error)
- func (p *Page) SavePNG(path string, opts ...RenderOption) error
- func (p *Page) Search(needle string, opts ...QueryOption) ([]Match, error)
- func (p *Page) Tables(opts ...TableOption) ([]Table, error)
- func (p *Page) TablesIn(r Rect, opts ...TableOption) ([]Table, error)
- func (p *Page) Text() (string, error)
- func (p *Page) TextIn(r Rect) (string, error)
- func (p *Page) ValueBelow(label string, opts ...QueryOption) (string, bool, error)
- func (p *Page) ValueRightOf(label string, opts ...QueryOption) (string, bool, error)
- func (p *Page) Words() (Words, error)
- func (p *Page) WordsIn(r Rect) (Words, error)
- type QueryOption
- type Rect
- func (r Rect) CenterX() float64
- func (r Rect) CenterY() float64
- func (r Rect) Contains(s Rect) bool
- func (r Rect) ContainsPoint(x, y float64) bool
- func (r Rect) Empty() bool
- func (r Rect) Expand(d float64) Rect
- func (r Rect) Geometry() geometry.Rect
- func (r Rect) Height() float64
- func (r Rect) Overlaps(s Rect) bool
- func (r Rect) Union(s Rect) Rect
- func (r Rect) Width() float64
- type RenderOption
- type Row
- type RowOption
- type Table
- type TableOption
- type Word
- type Words
- func (ws Words) Band(lo, hi float64) Words
- func (ws Words) Bounds() Rect
- func (ws Words) DropOutliers(factor float64) Words
- func (ws Words) In(r Rect) Words
- func (ws Words) LeftOf(x float64) Words
- func (ws Words) Lefts() []float64
- func (ws Words) RightOf(x float64) Words
- func (ws Words) SortByX() Words
- func (ws Words) SortReading() Words
- func (ws Words) Text() string
- func (ws Words) Tops() []float64
Constants ¶
This section is empty.
Variables ¶
var ErrPassword = errors.New("experimental: document is encrypted and the password is missing or incorrect")
ErrPassword is returned by Open when a document is encrypted and the supplied password is missing or incorrect. Test for it with errors.Is.
Functions ¶
func ClusterFloats ¶
ClusterFloats groups sorted values into runs where each value is within tol of the previous one. It is the building block for detecting vertical lanes (columns) from a bag of word x-positions, and rows from y-positions:
xs := words.Lefts() lanes := experimental.ClusterFloats(xs, 8) // 8pt column tolerance
The input is not mutated; output groups are in ascending order.
func CollectBlock ¶
func CollectBlock(rows []Row, start int, opt BlockOptions) []string
CollectBlock walks rows downward from start, collecting the text of words inside the x-band [Lo, Hi] until it hits a Stop keyword, runs past MaxGap empty lines, or reaches MaxLines. It captures the gnarly multi-line region reads (postal addresses, label-anchored blocks) that layout-aware extraction otherwise hand-rolls every time.
func Mean ¶
Mean returns the arithmetic mean of values (0 for an empty slice). Handy for turning a position cluster into a single lane center.
Types ¶
type BlockOptions ¶
type BlockOptions struct {
Lo, Hi float64 // x-band the block lives in
MaxLines int // cap on collected lines (default 7)
MaxGap int // empty lines tolerated mid-block (default 1)
Stop *regexp.Regexp // stop when a band word matches (e.g. next field label)
GuardLeft bool // also stop when a word left of the band matches Stop
}
BlockOptions configures CollectBlock.
type Bookmark ¶
type Bookmark struct {
Level int // 1-based nesting depth
Title string
Page int // 0-based target page, or -1 if external/unresolved
}
Bookmark is one entry of the document outline (table of contents).
type Doc ¶
type Doc struct {
// contains filtered or unexported fields
}
Doc is a thin, lifecycle-managed handle over a gomupdf.Document. It exists so callers stop juggling Open/Authenticate/Close ceremony and page handles.
doc, err := experimental.Open("document.pdf", experimental.Password("1234"))
if err != nil { ... }
defer doc.Close()
for _, page := range doc.Pages() { ... }
func Open ¶
func Open(src any, opts ...OpenOption) (*Doc, error)
Open opens a PDF from any of: a file path (string), raw bytes ([]byte), or an io.Reader (read fully into memory). Encryption is handled transparently when a Password option is given; otherwise an encrypted PDF returns an error.
func (*Doc) AppendImage ¶
AppendImage appends the image (path, []byte, or io.Reader) as a new full-bleed page sized to the image's pixel dimensions (1px = 1pt). Encoded JPEG/PNG/GIF bytes are accepted as-is.
func (*Doc) Close ¶
func (d *Doc) Close()
Close releases native resources. Safe to call more than once.
func (*Doc) Find ¶
func (d *Doc) Find(pattern string, opts ...QueryOption) ([]Match, error)
Find scans every page and returns all matches, tagged by page.
func (*Doc) Lines ¶
Lines returns every page's cleaned lines (soft hyphens stripped, blanks dropped) as one flat stream — a flat line stream suitable for line-oriented parsing.
func (*Doc) Pages ¶
Pages iterates pages in order: for i, page := range doc.Pages() { ... }. Pages that fail to load are skipped.
func (*Doc) Raw ¶
Raw exposes the underlying gomupdf.Document as an escape hatch for features this layer does not wrap (write/modify, metadata, TOC, drawings, ...).
func (*Doc) SaveImages ¶
SaveImages extracts every image and writes them into dir as page<P>-img<I>.<ext>, returning the written paths. dir is created if needed.
func (*Doc) SavePNGs ¶
func (d *Doc) SavePNGs(dir string, opts ...RenderOption) ([]string, error)
SavePNGs renders every page into dir as page-1.png, page-2.png, ... and returns the written paths. dir is created if needed.
func (*Doc) Tables ¶
func (d *Doc) Tables(opts ...TableOption) ([]Table, error)
Tables detects tables across every page, tagged by page.
func (*Doc) Thumbnail ¶
func (d *Doc) Thumbnail(opts ...RenderOption) (image.Image, error)
Thumbnail renders the first page to an image.Image (default options unless overridden, e.g. experimental.Zoom(0.3)).
func (*Doc) ValueBelow ¶
ValueBelow scans pages in order and returns the first label/value hit.
func (*Doc) ValueRightOf ¶
ValueRightOf scans pages in order and returns the first label/value hit.
type Image ¶
type Image struct {
Page int
Index int
Ext string // jpeg, png, jpx, ...
Bytes []byte // original encoded bytes
Width int // source pixel width
Height int // source pixel height
Region Rect // placement rectangle on the page
}
Image is an embedded image extracted from a page, tagged with its page and fill-order index, carrying its original encoded bytes and placement region.
type Info ¶
type Info struct {
Pages int
Encrypted bool
Title string
Author string
Subject string
Keywords string
Creator string
Producer string
Format string
Created string // raw creationDate string
Modified string // raw modDate string
Metadata map[string]string
}
Info is a typed snapshot of document-level facts, sparing callers the stringly-typed metadata map and separate count/encryption calls.
type Match ¶
Match is a located text hit: the matched text and its bounding rect, plus the page it came from and the visual line it sat on (for context).
type OpenOption ¶
type OpenOption func(*openConfig)
OpenOption configures Open.
func Password ¶
func Password(pw string) OpenOption
Password supplies the password for an encrypted PDF.
type Page ¶
type Page struct {
// contains filtered or unexported fields
}
Page is a positioned-text view of one PDF page. It loads the page's words once (lazily) and serves every spatial query from that cache.
func (*Page) Find ¶
func (p *Page) Find(pattern string, opts ...QueryOption) ([]Match, error)
Find returns every regex match on the page, each with its bounding rect. Matching runs per visual line, so a pattern spanning adjacent words on the same line is found and its rect is the union of those words.
hits := page.Find(`\d{4}-\d{2}-\d{2}`) // dates, with their locations
func (*Page) Image ¶
func (p *Page) Image(opts ...RenderOption) (image.Image, error)
Image renders the page to a standard library image.Image.
func (*Page) Images ¶
Images extracts every embedded image on the page, preserving original encoding where available.
func (*Page) Lines ¶
Lines returns the page's non-empty lines (soft hyphens stripped) as produced by gomupdf's reading-order extractor.
func (*Page) PNG ¶
func (p *Page) PNG(opts ...RenderOption) ([]byte, error)
PNG renders the page and returns encoded PNG bytes.
func (*Page) Raw ¶
Raw exposes the underlying gomupdf.Page for unwrapped features (pixmap, images, drawings, tables, search quads, ...).
func (*Page) Rows ¶
Rows groups the page's words into visual lines by vertical position: words are swept top-to-bottom and a new line starts when a word's top exceeds the current line's first word by more than the tolerance. Each row's words are sorted left-to-right. This is the workhorse for table-style and multi-column layouts where native line breaks are unreliable across columns.
func (*Page) SavePNG ¶
func (p *Page) SavePNG(path string, opts ...RenderOption) error
SavePNG renders the page and writes it to path as PNG.
func (*Page) Search ¶
func (p *Page) Search(needle string, opts ...QueryOption) ([]Match, error)
Search finds a literal substring on the page and returns each hit's location. Use Find for regular expressions.
func (*Page) Tables ¶
func (p *Page) Tables(opts ...TableOption) ([]Table, error)
Tables detects tables on the page. By default it tries the text strategy and falls back to the lines strategy when text finds nothing — so callers need not know the document's layout up front. Force a strategy with TableText / TableLines.
func (*Page) TablesIn ¶
func (p *Page) TablesIn(r Rect, opts ...TableOption) ([]Table, error)
TablesIn returns the page's tables whose bounding box overlaps region r.
func (*Page) TextIn ¶
TextIn returns the text inside region r, clustered into reading-order lines (rows joined by newline, words within a row by space). This is region/area cropping: hand it a header box, a column, a cell — get just that text.
func (*Page) ValueBelow ¶
ValueBelow finds the label on the page and returns the text on the nearest line below it that sits within the label's horizontal band — for values printed under their heading rather than beside it.
func (*Page) ValueRightOf ¶
ValueRightOf finds the label on the page and returns the text immediately to its right on the same line — the bread-and-butter of key/value extraction:
v, ok := page.ValueRightOf("Order No")
v, ok := page.ValueRightOf("Total", experimental.MaxGap(40))
The label may be a regular expression. ok is false if the label is not found.
type QueryOption ¶
type QueryOption func(*queryConfig)
QueryOption configures Find / ValueRightOf / ValueBelow.
func CaseSensitive ¶
func CaseSensitive() QueryOption
CaseSensitive makes label/pattern matching case-sensitive (default: insensitive).
func MaxGap ¶
func MaxGap(pts float64) QueryOption
MaxGap stops a right-of value scan when the horizontal gap between two words exceeds pts, so a far-away column is not swept into the value.
func Pad ¶
func Pad(pts float64) QueryOption
Pad widens the x-band used by ValueBelow by pts on each side (default 2).
type Rect ¶
type Rect struct {
X0, Y0, X1, Y1 float64
}
Rect is an axis-aligned rectangle in PDF points. Origin is top-left and y grows downward, matching the page coordinate system used throughout gomupdf.
func (Rect) ContainsPoint ¶
ContainsPoint reports whether (x, y) lies within r.
func (Rect) Geometry ¶
Geometry converts back to the base library's corner rect, for callers that need to hand a region to gomupdf APIs (e.g. InsertImage, AddRectAnnot).
type RenderOption ¶
type RenderOption func(*renderConfig)
RenderOption configures rasterization.
func Zoom ¶
func Zoom(z float64) RenderOption
Zoom sets the render scale factor directly (1.0 == 72 DPI).
type Row ¶
Row is a visual line of words sharing roughly the same vertical position, already sorted left-to-right.
func ClusterRows ¶ added in v0.1.1
ClusterRows groups an arbitrary set of words into visual lines by vertical position, identically to Rows. Use it when you need to cluster a filtered or combined word set (e.g. after DropOutliers, or merging words from several sources) rather than a whole page.
type RowOption ¶
type RowOption func(*rowConfig)
RowOption configures Rows.
func RowTolerance ¶
RowTolerance sets the max vertical gap (points) between a word and the current line before a new line starts. Default 3.5.
type Table ¶
Table is a detected table tagged with its source page. It embeds gomupdf.Table, so Rows, ColX, RowY, NumRows() and NumCols() are available directly; Region() gives the bounding box in the unified Rect type.
type TableOption ¶
type TableOption func(*tableConfig)
TableOption configures table detection.
func TableLines ¶
func TableLines() TableOption
TableLines forces the vector-drawing ("lines") strategy.
func TableText ¶
func TableText() TableOption
TableText forces the word-alignment ("text") strategy.
type Word ¶
type Word struct {
Text string
Rect Rect
Block int // source block index (reading-order hint from MuPDF)
Line int // source line index within the block
}
Word is a single positioned word. Its geometry is a unified Rect (top-left origin, y down, PDF points). The accessors below name the edges the way most layout-aware code refers to them.
type Words ¶
type Words []Word
Words is a slice of Word with chainable spatial filters. Methods return new slices and never mutate the receiver, so they compose:
row.Words.Band(lo, hi).Text()
func (Words) Band ¶
Band keeps words whose left edge (x0) falls within [lo, hi]. This is the x-band filter for reading a single column.
func (Words) DropOutliers ¶
DropOutliers removes words whose height exceeds factor × the median word height — the standard trick for stripping oversized diagonal watermarks. A factor <= 0 defaults to 2.2.
func (Words) Lefts ¶
Lefts returns the left edge (x0) of every word — feed straight into ClusterFloats to find column lanes.
func (Words) SortReading ¶
SortReading returns the words in reading order (top-to-bottom, then left-to-right), tolerating small vertical jitter within a line.