Skip to content

PDF Document#

The starting point of all backend activity is to create a Document struct. Initialize with an io.Writer

func NewDocument(w io.Writer) *PDFDocument

which gets you a big structure:

type PDFDocument struct {
    Author               string
    Bleed                bag.ScaledPoint
    ColorProfile         *ColorProfile
    CompressLevel        uint
    Creator              string
    CreationDate         time.Time
    CurrentPage          *Page
    DefaultLanguage      *lang.Lang
    DefaultPageHeight    bag.ScaledPoint
    DefaultPageWidth     bag.ScaledPoint
    Faces                []*pdf.Face
    Filename             string
    Keywords             string
    Languages            map[string]*lang.Lang
    Pages                []*Page
    PDFWriter            *pdf.PDF
    RootStructureElement *StructureElement
    ShowCutmarks         bool
    ShowHyperlinks       bool
    Spotcolors           []*color.Color
    Subject              string
    SuppressInfo         bool
    Title                string
    ViewerPreferences    map[string]string

After you are done writing Pages and other material to the PDF, you must end your work with

func (d *PDFDocument) Finish() error

which does everything that is left over, except for closing the PDF file.

PDF metadata#

To add metadata, just set the appropriate fields in the main PDFDocument struct:

pd := NewDocument(w)
pd.Author = "A. U. Thor"
pd.Title = "A short story"

The backend fills in the Info dict and adds the required XML metadata to the PDF file.

/Title (A short story)
/Author (A. U. Thor.)

in the Info dict and the XML metadata:

<rdf:Description rdf:about="" xmlns:dc="">
  <dc:title>A short story</dc:title>
  <dc:creator>A. U. Thor.</dc:creator>

Creating pages#

A new page is created with

func (d *PDFDocument) NewPage() *Page

This sets the current page of the document to a new page with the default page height and page width. It also adds this page to the slice of document pages, so that when writing the PDF, you don't have to do anything special to get the page into the PDF.

type Page struct {
    Height            bag.ScaledPoint
    Width             bag.ScaledPoint
    ExtraOffset       bag.ScaledPoint
    Background        []Object
    Objects           []Object
    Userdata          map[any]any
    Finished          bool
    StructureElements []*StructureElement
    Annotations       []pdf.Annotation
    Spotcolors        []*color.Color
    Objectnumber      pdf.Objectnumber

If you are finished with a page, you call Shipout() to put the page into the PDF.

func (p *Page) Shipout()

Shipout() creates crop marks (if requested), adds bleed amount to the page dimensions, writes all the Objects from the Background and Objects slice to the PDF as well as the Annotations, the Spotcolors and StructureElements.

func (p *Page) OutputAt(x bag.ScaledPoint, y bag.ScaledPoint, vlist *node.VList)
type Object struct {
    X     bag.ScaledPoint
    Y     bag.ScaledPoint
    Vlist *node.VList

Page callback#

You can register a pre-shipout callback (which is called before the bleed marks are created) with

func (d *PDFDocument) RegisterCallback(cb Callback, fn any)

and register the PreShipoutCallback which must have the signature func(page *Page).

type CallbackShipout func(page *Page)
preShipout := func(pg *document.Page) {
mydoc.RegisterCallback(document.CallbackPreShipout, preShipout)


func (d *PDFDocument) CreateImage(imgfile *pdf.Imagefile, pagenumber int, box string) *image.Image
func (d *PDFDocument) LoadImageFile(filename string) (*pdf.Imagefile, error)


type StructureElement struct {
    ID         int
    Role       string
    ActualText string
    Parent *StructureElement
    Obj    *pdf.Object
func (se *StructureElement) AddChild(cld *StructureElement)


func (d *PDFDocument) SetVTrace(t VTrace)
type VTrace int
func (d *PDFDocument) ClearVTrace(t VTrace)
func (d *PDFDocument) IsTrace(t VTrace) bool
func (d *PDFDocument) OutputXMLDump(w io.Writer) error