go-fitz
| Language | Go (cgo, or experimental purego without cgo) |
|---|---|
| License | AGPL-3.0 (go-fitz itself and the bundled MuPDF) |
| Repository | github.com/gen2brain/go-fitz |
| Documentation | pkg.go.dev/github.com/gen2brain/go-fitz |
| Depends on | MuPDF (static libraries bundled for common platforms; or an external MuPDF with the extlib build tag) |
| Read / write | yes (render, text, HTML, SVG, links, outline, metadata) / no |
go-fitz gives Go programs MuPDF’s rendering and text extraction: Image renders a page to *image.RGBA, Text returns the page text, HTML and SVG convert a page, and ToC, Links and Metadata read document structure. It opens everything MuPDF opens: PDF, EPUB, MOBI, XPS, CBZ, FB2 and Office documents. Static MuPDF builds are included for Linux, macOS and Windows (amd64, arm64), so go get works with only a C compiler.
go-fitz can’t modify or create PDFs. It is AGPL-3.0: if you distribute your program or run it as a network service, you must release your source under the AGPL (or get a commercial MuPDF license from Artifex and use your own build). Each Document has its own MuPDF context: use one document per goroutine.
Installation#
go get github.com/gen2brain/go-fitz
Needs cgo (a C compiler). The bundled libraries lack CJK fonts; for CJK documents build against a system MuPDF with go build -tags extlib. With CGO_ENABLED=0 (or -tags nocgo) go-fitz loads a libmupdf shared library at runtime via purego.
Basic usage: render pages to PNG#
package main
import (
"fmt"
"image/png"
"log"
"os"
"github.com/gen2brain/go-fitz"
)
func main() {
doc, err := fitz.New("in.pdf")
if err != nil {
log.Fatal(err)
}
defer doc.Close()
fmt.Printf("%d pages\n", doc.NumPage())
for n := 0; n < doc.NumPage(); n++ { // pages are numbered from 0
img, err := doc.ImageDPI(n, 150)
if err != nil {
log.Fatal(err)
}
f, err := os.Create(fmt.Sprintf("page-%03d.png", n+1))
if err != nil {
log.Fatal(err)
}
if err := png.Encode(f, img); err != nil {
log.Fatal(err)
}
f.Close()
}
}
doc.Image(n) renders at the default 300 DPI; doc.ImagePNG(n, dpi) returns encoded PNG bytes directly.
How to extract text from a PDF#
for n := 0; n < doc.NumPage(); n++ {
text, err := doc.Text(n)
if err != nil {
log.Fatal(err)
}
fmt.Printf("--- page %d ---\n%s\n", n+1, text)
}
doc.HTML(n, true) returns the page as HTML with positioned text and fonts.
How to read PDF metadata and the table of contents#
meta := doc.Metadata() // keys like "title", "author", "format", "producer"
fmt.Println(meta["title"], meta["author"], meta["format"])
toc, err := doc.ToC()
if err == nil {
for _, item := range toc {
fmt.Printf("%*s%s (page %d)\n", item.Level*2, "", item.Title, item.Page)
}
}
How to open a PDF from memory#
data, err := os.ReadFile("in.pdf")
if err != nil {
log.Fatal(err)
}
doc, err := fitz.NewFromMemory(data)
fitz.NewFromReader(r) reads from an io.Reader.
Tips#
- Rendering is CPU-heavy: render pages in parallel with one
Documentper goroutine. doc.Bound(n)returns the page bounds without rendering the page.- For a permissive license, render with PDFium through a cgo binding or call
pdftoppm(Poppler) as an external process.