Document

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 {
	AdditionalXMLMetadata string // Extra XML metadata to be added to the PDF. Must be a correctly formatted XML fragment (multiple elements are not allowed).
	Author                string
	Attachments           []Attachment
	Bleed                 bag.ScaledPoint
	ColorProfile          *ColorProfile
	CompressLevel         uint
	Creator               string
	CreationDate          time.Time
	CurrentPage           *Page
	DefaultLanguage       *lang.Lang
	DefaultPageHeight     bag.ScaledPoint
	DefaultPageWidth      bag.ScaledPoint
	DumpOutput            bool
	Faces                 []*pdf.Face
	Filename              string
	Format                Format // The PDF format (PDF/X-1, PDF/X-3, PDF/A, etc.)
	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="http://purl.org/dc/elements/1.1/">
  <dc:title>A short story</dc:title>
  <dc:creator>A. U. Thor.</dc:creator>
</rdf:Description>

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)

Images

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

Attachments

You can attach documents to a PDF file:

a := document.Attachment{
	Name:        "test.pdf",
	Description: "A very nice test document",
	MimeType:    "application/pdf",
	Data:        []byte("test"),
}
f.Doc.Attachments = append(f.Doc.Attachments, a)

The possible attributes in the attachment structure are:

type Attachment struct {
	// Name of the attachment (the visible name in the PDF)
	// This is the name of the file as it will be displayed in the PDF viewer
	// and is not necessarily the same as the original file name.
	Name string
	// Description of the attachment
	Description string
	// MimeType of the attachment
	MimeType string
	// Data of the attachment
	Data []byte
	// Creation date of the attachment
	CreationDate time.Time
	// Modified date of the attachment
	ModDate time.Time
}

Accessibility

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

Debugging

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