gomupdf

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

README

gomupdf

CI codecov Go Reference Go Report Card

A focused cgo binding over the MuPDF C core for reading, extracting, rendering, and writing PDF documents from Go.

The API is compact and idiomatic: open a (possibly encrypted) PDF from a file or from memory, then pull reading-order text, positioned word/span geometry, tables, images, vector drawings, links, and the outline from each page. Pages render to rasters, and new documents can be assembled, modified, and saved (optionally encrypted).

Requirements

This package links against the MuPDF C library via cgo, so a C toolchain and MuPDF (shared library and development headers) must be present at build time. CGO_ENABLED=1 is required (it is on by default for native builds).

Installing MuPDF

macOS (Homebrew)

brew install mupdf

Homebrew installs into /opt/homebrew (Apple Silicon) or /usr/local (Intel); the default cgo flags target /opt/homebrew. On Intel Macs, point cgo at the right prefix (see Custom install locations).

Debian / Ubuntu

sudo apt-get install libmupdf-dev mupdf-tools

Fedora / RHEL

sudo dnf install mupdf-devel

Arch Linux

sudo pacman -S libmupdf

From source (any platform, when no package is available)

git clone --recursive https://github.com/ArtifexSoftware/mupdf.git
cd mupdf
make HAVE_X11=no HAVE_GLUT=no prefix=/usr/local install

Windows is not covered by the default cgo flags; build with a MinGW/MSYS2 toolchain and set CGO_CFLAGS / CGO_LDFLAGS to your MuPDF install (see below).

Custom install locations

The default cgo flags (declared in mupdf.go) target the standard prefixes: -I/opt/homebrew/include -L/opt/homebrew/lib on darwin and the system include paths on linux, linking -lmupdf (and -lmupdf-third on linux). If your MuPDF lives elsewhere, supplement the flags via environment variables instead of editing the source:

export CGO_CFLAGS="-I/your/prefix/include"
export CGO_LDFLAGS="-L/your/prefix/lib -lmupdf -lmupdf-third"
go build ./...
Verify
go install github.com/srijanmukherjee/gomupdf/...@latest  # should compile cleanly

A linker error such as ld: library 'mupdf' not found means MuPDF is not installed or not on the library path — install it or set CGO_LDFLAGS as above.

Install

go get github.com/srijanmukherjee/gomupdf

Quick start

package main

import (
	"fmt"
	"log"

	"github.com/srijanmukherjee/gomupdf"
)

func main() {
	doc, err := gomupdf.Open("document.pdf")
	if err != nil {
		log.Fatal(err)
	}
	defer doc.Close()

	if doc.NeedsPass() && !doc.Authenticate("secret") {
		log.Fatal("wrong password")
	}

	for i, page := range doc.Pages() {
		text, err := page.GetText()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("page %d:\n%s\n", i, text)
	}
}

Convenience openers handle authentication in one step and return an error on a wrong password:

doc, err := gomupdf.OpenWithPassword("document.pdf", password)
doc, err := gomupdf.OpenStreamWithPassword(pdfBytes, password)

Text & geometry

All geometry is in PDF points, origin top-left, y growing downward.

text, _   := doc.Text()          // whole document, pages joined by form feed
pages, _  := doc.TextByPage()    // per-page text
lines, _  := doc.AllLines()      // flat line stream, soft hyphens stripped, blanks dropped

blocks, _ := page.StructuredText() // []Block → []Span with Rect, font, baseline
spans, _  := page.Spans()          // flattened text fragments in document order
words, _  := page.Words()          // word boxes with character-level precision

page.StructuredJSON() returns the raw structured-text JSON for callers that want to traverse the block/line/char tree themselves.

quads, _ := page.Search("invoice")     // oriented quads for each hit
rects, _ := page.SearchRects("invoice") // axis-aligned rects
toc, _   := doc.TOC()                   // flat, depth-first outline
links, _ := page.Links()                // clickable rects + target URIs

Tables

page.FindTables detects tables with either a word-alignment strategy or a vector-ruling strategy:

tables, _ := page.FindTables() // default: word-alignment ("text") strategy
tables, _ := page.FindTables(gomupdf.TableSettings{Strategy: gomupdf.StrategyLines})

for _, t := range tables {
	fmt.Println(t.NumRows(), t.NumCols(), t.Rows)
}

Rendering & images

pm, _ := page.Pixmap(gomupdf.PixmapOptions{Zoom: 2.0}) // 144 DPI RGB raster
png, _ := pm.PNG()
_ = pm.SavePNG("page.png")

imgs, _ := page.GetImages()        // placement + source metadata
img, _  := page.ExtractImage(0)    // original encoded bytes (JPEG/PNG/...)
paths, _ := page.GetDrawings()     // vector fill/stroke paths

Writing & assembly

doc, _ := gomupdf.NewPDF()
defer doc.Close()
doc.NewPage(595, 842)              // A4 in points
p, _ := doc.LoadPage(0)
p.InsertText(72, 800, 12, "Hello")
p.InsertImage(geometry.NewRect(0, 0, 200, 200), imageBytes)
doc.InsertPDF(otherPDFBytes, "")   // append all pages of another document

data, _ := doc.SaveBytes(true)                       // serialize (with garbage collection)
data, _ := doc.SaveEncryptedBytes("user", "owner")   // AES-256 encrypted

Subpackages

  • geometry — the 2D primitives (Point, Rect, IRect, Matrix, Quad) used throughout the API.
  • experimental — a higher-level, ergonomic layer: lifecycle-managed documents, a row/word model for layout-aware extraction, region and key/value queries, located regex search, and helpers for rendering, image extraction, and merging PDFs and images.

Feature support

Legend: ✅ supported · 🟡 partial · ⬜ not yet

Area Capability Status
Read Open / stream / password / metadata
Read Page count, load, iterate
Read Plain & structured text, char-level words
Read Geometry primitives (geometry pkg)
Read Text search (quads & rects)
Read Tables — word-alignment & vector-ruling strategies
Read Textbox / line-break extraction
Structure Outline (TOC)
Structure Page links
Structure Page labels, page boxes, embedded files
Render Pixmap → raster (PNG, image.Image, pixel access)
Render Extract images + placement bbox
Render Vector drawings / paths
Render OCR, image masks
Write New PDF / page / delete / merge
Write Insert text & images
Write Save (full rewrite) & AES-256 encryption
Write Annotations 🟡 rectangle only
Write Widgets/forms, redaction, overlay, fonts

Concurrency & memory

A Document owns a single native context and is not safe for concurrent use; all of its methods are serialized internally by a mutex. To process documents in parallel, open one Document per goroutine. Always Close() a document when done (a finalizer is only a backstop). The in-memory bytes backing a streamed PDF are held for the document's lifetime.

Acknowledgements

  • MuPDF by Artifex Software is the C library that does the heavy lifting — parsing, rendering, and text extraction. This package is a thin Go layer over it; all credit for the underlying PDF engine belongs to the MuPDF authors.
  • PyMuPDF (the Python MuPDF binding) and pdfplumber are the prior art that shaped this library's extraction and table-detection design. The word-alignment table strategy follows the well-trodden approach those projects established. Thank you to their authors and maintainers.

License

MuPDF is distributed under the GNU AGPL-3.0, and this package links against it, so the same license applies (see LICENSE). Review its obligations before distributing binaries built with this package.

Documentation

Overview

Package gomupdf is a focused cgo binding over the MuPDF C core (https://mupdf.com/core) for reading, extracting, rendering, and writing PDFs. It exposes a compact API: open a (possibly encrypted) PDF from a file or from memory, authenticate, and pull reading-order text and positioned geometry per page, along with rendering and document-assembly helpers.

MuPDF + cgo discipline (the four rules):

  1. fz_try/fz_catch use setjmp/longjmp. A longjmp must NEVER cross the cgo→Go boundary, so every throwing fz_* call is wrapped inside a C helper that does fz_try/fz_catch and returns an error string to Go.
  2. fz_context is not thread-safe. Each Document owns its own context and is guarded by a mutex; do not share a Document across goroutines without it.
  3. All MuPDF objects are explicitly dropped (fz_drop_*); the C helpers clean up in fz_always so a Go-side mistake cannot leak.
  4. The in-memory PDF bytes backing fz_open_memory are NOT copied by MuPDF, so we hold a C-allocated copy alive for the Document's whole lifetime.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Block

type Block struct {
	Type  string // "text" | "image"
	BBox  Rect
	Spans []Span
}

Block is a text or image block containing zero or more spans.

type Document

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

Document is an open PDF. Methods are serialized internally; a Document binds one MuPDF context. Always Close it.

func NewPDF

func NewPDF() (*Document, error)

NewPDF creates a new, empty PDF document.

func Open

func Open(filename string) (*Document, error)

Open opens a PDF document from a file path.

Example

Open a PDF and print the reading-order text of every page.

package main

import (
	"fmt"
	"log"

	"github.com/srijanmukherjee/gomupdf"
)

func main() {
	doc, err := gomupdf.Open("document.pdf")
	if err != nil {
		log.Fatal(err)
	}
	defer doc.Close()

	for i, page := range doc.Pages() {
		text, err := page.GetText()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("page %d:\n%s\n", i, text)
	}
}

func OpenStream

func OpenStream(pdf []byte) (*Document, error)

OpenStream opens a PDF from in-memory bytes. It does not fail on encryption; the returned Document is left locked (NeedsPass() true) until Authenticate succeeds.

func OpenStreamWithPassword

func OpenStreamWithPassword(pdf []byte, password string) (*Document, error)

OpenStreamWithPassword is OpenWithPassword for in-memory bytes.

func OpenWithPassword

func OpenWithPassword(filename, password string) (*Document, error)

OpenWithPassword opens a file and authenticates in one step, returning an error if the password is wrong (QoL over Open + Authenticate).

func (*Document) AllLines

func (d *Document) AllLines() ([]string, error)

AllLines returns every page's Lines concatenated into a single flat line stream across the whole document.

func (*Document) Authenticate

func (d *Document) Authenticate(password string) bool

Authenticate tries a password and returns true if the document is now readable (correct password, or it was never locked).

Example

Open an encrypted PDF, authenticating with a password.

package main

import (
	"fmt"
	"log"

	"github.com/srijanmukherjee/gomupdf"
)

func main() {
	doc, err := gomupdf.Open("encrypted.pdf")
	if err != nil {
		log.Fatal(err)
	}
	defer doc.Close()

	if doc.NeedsPass() && !doc.Authenticate("secret") {
		log.Fatal("wrong password")
	}

	fmt.Println(doc.PageCount())
}

func (*Document) Close

func (d *Document) Close()

Close releases all native resources. Safe to call twice.

func (*Document) DeletePage

func (d *Document) DeletePage(n int) error

DeletePage removes page n (0-based).

func (*Document) InsertPDF

func (d *Document) InsertPDF(src []byte, password string) error

InsertPDF appends every page of the source PDF (given as bytes) to this document. password unlocks an encrypted source ("" if none).

func (*Document) IsEncrypted

func (d *Document) IsEncrypted() bool

IsEncrypted reports whether the PDF was password-protected (stays true even after successful authentication, unlike NeedsPass).

func (*Document) LoadPage

func (d *Document) LoadPage(i int) (*Page, error)

LoadPage returns a handle to page i (0-based). The page is lightweight (it defers to the document on each call); no separate Close is required.

func (*Document) Metadata

func (d *Document) Metadata() (map[string]string, error)

Metadata returns document metadata (title, author, format, …). Absent keys are omitted.

func (*Document) NeedsPass

func (d *Document) NeedsPass() bool

NeedsPass reports whether the document is encrypted and not yet unlocked. Unlike MuPDF's static flag, this flips to false once Authenticate succeeds.

func (*Document) NewPage

func (d *Document) NewPage(width, height float64) error

NewPage appends a blank page of the given size (points).

func (*Document) PageCount

func (d *Document) PageCount() int

PageCount returns the number of pages. Returns 0 if the document is closed or unreadable.

func (*Document) Pages

func (d *Document) Pages() iter.Seq2[int, *Page]

Pages iterates pages in order. Use as:

for i, page := range doc.Pages() { ... }

func (*Document) Save

func (d *Document) Save(path string, garbage bool) error

Save writes the document to a PDF file.

func (*Document) SaveBytes

func (d *Document) SaveBytes(garbage bool) ([]byte, error)

SaveBytes serializes the document to PDF bytes. garbage collects unused objects.

func (*Document) SaveEncryptedBytes

func (d *Document) SaveEncryptedBytes(userPwd, ownerPwd string) ([]byte, error)

SaveEncryptedBytes serializes the document with AES-256 encryption. userPwd is required to open; ownerPwd grants full permissions (may be "").

func (*Document) TOC

func (d *Document) TOC() ([]TOCEntry, error)

TOC returns the document outline as a flat, depth-first list. Empty if the document has no bookmarks.

func (*Document) Text

func (d *Document) Text() (string, error)

Text returns the full document text, pages separated by a form feed ("\f").

func (*Document) TextByPage

func (d *Document) TextByPage() ([]string, error)

TextByPage returns each page's text as a slice.

type Drawing

type Drawing struct {
	Type     string
	Color    [3]float64 // sRGB 0..1
	Width    float64    // stroke width, ctm-scaled (0 for fills)
	LineJoin int
	Alpha    float64
	Items    []PathItem
	Rect     geometry.Rect // bounding box of all points
}

Drawing is one vector path captured from the page. Type is "f" (fill) or "s" (stroke). MuPDF reports fill and stroke of the same path as separate device calls, so each path's fill and stroke are reported as separate entries rather than a single combined entry.

type ExtractedImage

type ExtractedImage struct {
	Ext   string // jpeg | png | jpx | …
	Bytes []byte
}

ExtractedImage is the encoded bytes of an image plus its file extension.

type ImageInfo

type ImageInfo struct {
	Index  int
	BBox   geometry.Rect
	Width  int // source image pixel width
	Height int // source image pixel height
	BPC    int // bits per component
	N      int // colorspace components (0 if none)
	Ext    string
}

ImageInfo describes an image placed on a page. BBox is the placement rectangle in page points.

type Link struct {
	Rect geometry.Rect
	URI  string
}

Link is a page link: a clickable rect with a target URI.

type Page

type Page struct {
	Number int // 0-based page index
	// contains filtered or unexported fields
}

Page is a handle to a single page.

func (*Page) AddRectAnnot

func (p *Page) AddRectAnnot(r geometry.Rect) error

AddRectAnnot adds a rectangle (square) annotation on page i.

func (*Page) Bound

func (p *Page) Bound() (geometry.Rect, error)

Bound returns the page's bounding box in points.

func (*Page) ExtractImage

func (p *Page) ExtractImage(index int) (*ExtractedImage, error)

ExtractImage returns the encoded bytes of the index-th image on the page. Original encoding is preserved when available (e.g. JPEG); uncompressed images are re-encoded as PNG. Returns nil if there is no image at that index.

func (*Page) FindTables

func (p *Page) FindTables(opts ...TableSettings) ([]Table, error)

FindTables detects tables on the page. Default strategy is "text" (rulings from word alignment); set Strategy: StrategyLines to derive rulings from the page's vector drawings instead.

func (*Page) GetDrawings

func (p *Page) GetDrawings() ([]Drawing, error)

GetDrawings returns the page's vector drawings.

func (*Page) GetImages

func (p *Page) GetImages() ([]ImageInfo, error)

GetImages returns the images drawn on the page, in fill order, each with its placement bbox and source dimensions.

func (*Page) GetText

func (p *Page) GetText() (string, error)

GetText returns the page's reading-order plain text.

func (*Page) InsertImage

func (p *Page) InsertImage(r geometry.Rect, img []byte) error

InsertImage places an encoded image (jpeg/png/…) into rect r on page i.

func (*Page) InsertText

func (p *Page) InsertText(x, y, size float64, text string) error

InsertText draws a line of Helvetica text at (x, y) (baseline) on page i.

func (*Page) Lines

func (p *Page) Lines() ([]string, error)

Lines returns the page's non-empty lines with the soft hyphen (U+00AD) stripped and trailing whitespace trimmed.

func (p *Page) Links() ([]Link, error)

Links returns the page's links.

func (*Page) Pixmap

func (p *Page) Pixmap(opts ...PixmapOptions) (*Pixmap, error)

Pixmap renders the page.

Example

Render the first page to a PNG file at 144 DPI.

package main

import (
	"log"

	"github.com/srijanmukherjee/gomupdf"
)

func main() {
	doc, err := gomupdf.Open("document.pdf")
	if err != nil {
		log.Fatal(err)
	}
	defer doc.Close()

	page, err := doc.LoadPage(0)
	if err != nil {
		log.Fatal(err)
	}
	pm, err := page.Pixmap(gomupdf.PixmapOptions{Zoom: 2.0})
	if err != nil {
		log.Fatal(err)
	}
	if err := pm.SavePNG("page-0.png"); err != nil {
		log.Fatal(err)
	}
}

func (*Page) Search

func (p *Page) Search(needle string) ([]geometry.Quad, error)

Search finds all occurrences of needle on the page and returns their hit quads. Matching is MuPDF's case-insensitive, whitespace-tolerant search. Returns nil if there are no hits.

func (*Page) SearchRects

func (p *Page) SearchRects(needle string) ([]geometry.Rect, error)

SearchRects is Search returning bounding rectangles instead of quads.

func (*Page) Spans

func (p *Page) Spans() ([]Span, error)

Spans returns all text spans on the page in document order — the flat positioned-text stream that table reconstruction typically starts from.

func (*Page) StructuredJSON

func (p *Page) StructuredJSON() (string, error)

StructuredJSON returns MuPDF structured text as JSON (blocks → lines → chars, each with bbox). This is the raw geometry feed for layout reconstruction; see Words/Blocks for typed access.

func (*Page) StructuredText

func (p *Page) StructuredText() ([]Block, error)

StructuredText returns the page's blocks and spans with bounding boxes. Spans are positioned text fragments; clustering them by x yields columns and by y yields rows, which is how callers needing exact column geometry reconstruct tables rather than relying on reading-order text.

func (*Page) Words

func (p *Page) Words() ([]Word, error)

Words returns the page's words with character-level bounding boxes. These boxes are more precise than the span-split approximations and are the recommended input for FindTables.

type PathItem

type PathItem struct {
	Op  string
	Pts []geometry.Point
}

PathItem is one segment of a drawing path:

Op "l"  → line:  Pts[0]→Pts[1]
Op "c"  → bezier: Pts[0] ctrl1, Pts[1] ctrl2, Pts[2] end (relative to prior point)
Op "m"  → moveto: Pts[0]
Op "h"  → closepath (no points)

type Pixmap

type Pixmap struct {
	Width   int
	Height  int
	N       int
	Stride  int
	Alpha   bool
	Samples []byte
}

Pixmap is a rendered raster of a page. Samples is row-major, Stride bytes per row, N components per pixel (1 gray, 2 gray+α, 3 rgb, 4 rgba).

func (*Pixmap) Image

func (pm *Pixmap) Image() (image.Image, error)

Image converts the pixmap to a standard library image.

func (*Pixmap) PNG

func (pm *Pixmap) PNG() ([]byte, error)

PNG encodes the pixmap as PNG bytes.

func (*Pixmap) Pixel

func (pm *Pixmap) Pixel(x, y int) []byte

Pixel returns the N component bytes at (x, y).

func (*Pixmap) SavePNG

func (pm *Pixmap) SavePNG(path string) error

SavePNG writes the pixmap to a PNG file.

type PixmapOptions

type PixmapOptions struct {
	Zoom  float64 // scale factor (1.0 = 72 DPI); <=0 means 1.0
	Gray  bool    // render in grayscale instead of RGB
	Alpha bool    // include an alpha channel
}

PixmapOptions controls rendering.

type Rect

type Rect struct {
	X, Y, W, H float64
}

Rect is a bounding box in PDF points (origin top-left, y grows downward), expressed as a position and size. It is the box type carried by extracted words, spans, and blocks.

func (Rect) CenterY

func (r Rect) CenterY() float64

CenterY returns the vertical midpoint, useful when clustering boxes into rows.

func (Rect) X1

func (r Rect) X1() float64

X1 returns the right edge (X + W).

func (Rect) Y1

func (r Rect) Y1() float64

Y1 returns the bottom edge (Y + H).

type Span

type Span struct {
	Text     string
	BBox     Rect
	OriginX  float64
	OriginY  float64
	FontName string
	FontSize float64
}

Span is a positioned run of text: its text, bounding box, baseline origin, and font.

type TOCEntry

type TOCEntry struct {
	Level int
	Title string
	Page  int
}

TOCEntry is one table-of-contents item: a heading level, its title, and the destination page. Page is 0-based, or -1 for external/unresolved destinations.

type Table

type Table struct {
	BBox Rect
	Rows [][]string
	ColX []float64 // column boundary x-positions (len = cols+1)
	RowY []float64 // row boundary y-positions (len = rows+1)
}

Table is a detected table: a row-major grid of cell strings plus geometry.

func (*Table) NumCols

func (t *Table) NumCols() int

func (*Table) NumRows

func (t *Table) NumRows() int

NumRows / NumCols.

type TableSettings

type TableSettings struct {
	Strategy           TableStrategy // text | lines (default text)
	SnapTolerance      float64       // cluster edge coords within this distance
	MinWordsVertical   int           // words sharing an x to form a column ruling
	MinWordsHorizontal int           // words sharing a y to form a row ruling
	IntersectionTol    float64       // edge crossing tolerance
	AlignTolerance     float64       // max deviation for a drawing segment to count as axis-aligned (lines)
}

TableSettings configures table detection; see DefaultTableSettings for the documented defaults.

func DefaultTableSettings

func DefaultTableSettings() TableSettings

DefaultTableSettings returns sensible defaults for table detection.

type TableStrategy

type TableStrategy string

TableStrategy selects how column/row rulings are found.

const (
	StrategyText  TableStrategy = "text"  // rulings from word alignment
	StrategyLines TableStrategy = "lines" // rulings from vector drawings
)

type Word

type Word struct {
	Text  string
	BBox  Rect
	Block int
	Line  int
}

Word is a whitespace-delimited word with its character-derived bounding box. BBox is the union of the word's character boxes, giving precise geometry for table reconstruction and column/row clustering.

Directories

Path Synopsis
Package experimental is a question-first layer over gomupdf.
Package experimental is a question-first layer over gomupdf.
Package geometry provides a self-contained 2D geometry toolkit for PDF coordinates: Point, Rect, IRect, Matrix, and Quad.
Package geometry provides a self-contained 2D geometry toolkit for PDF coordinates: Point, Rect, IRect, Matrix, and Quad.

Jump to

Keyboard shortcuts

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