Skip to content

speedata/baseline PDF backend#

baseline pdf logo

The boxes and glue PDF backend can be used independently and does not use anything from the boxes and glue frontend or backend. This means you can easily use this PDF library for your own projects without too many dependencies.

The package reference is located at https://pkg.go.dev/github.com/speedata/baseline-pdf and the import path is github.com/speedata/baseline-pdf. For the repository itself head to https://github.com/speedata/baseline-pdf.

Installation#

The installation is very simple by importing the package into your code. First initialize a module and get the library:

go mod init mymodule
go get github.com/speedata/baseline-pdf@latest

and use the library:

package main

import (
    "os"

    pdf "github.com/speedata/baseline-pdf"
)

func main() {
    w, _ := os.Create("out.pdf")
    pw := pdf.NewPDFWriter(w)
    // ...
}

The main PDF object#

The PDF backend is a very low level interface to write PDF files. The starting point of the PDF writer is a call to

func NewPDFWriter(file io.Writer) *PDF

which returns an object:

type PDF struct {
    Catalog           Dict
    InfoDict          Dict
    DefaultPageWidth  float64
    DefaultPageHeight float64
    Colorspaces       []*Separation
    NumDestinations   map[int]*NumDest
    NameDestinations  []*NameDest
    Outlines          []*Outline
    Major             uint // Major version. Should be 1.
    Minor             uint // Minor version. Just for information purposes. No checks are done.
}

When creating objects, the PDF backend takes care of housekeeping such as remembering the positions of the objects to write the correct XRef table. You can attach a logger to the PDF object to get some information about reading and writing fonts. The logger interface is rather simple:

type Logger interface {
    Info(string, ...any)
}

Next steps#

Now that you have the PDF object, you can load font files (a “face” in this documentation), images or create pages by building a content stream yourself and pass this to create a new page.

After writing the pages, create the catalog and other necessary objects for the PDF and then call

func (pw *PDF) Finish() error

which writes the following objects:

  • outlines
  • pages (including annotations)
  • name tree
  • document catalog
  • the used faces and images
  • info dict
  • xref table (cross references)

Closing the PDF

Finish() does not close the file. This has to be done from the caller.

Other (meta)data#

If you need other data such as color profiles, structure elements, XML metadata or additional entries in the info dict, you need to do that yourself.

You can use the InfoDict or Catalog dictionary to add additional fields to these dictionary, such as

// you should use pdf.String(...) or create a PDF encoded string yourself.
PDFWriter.InfoDict["Title"] = pdf.String("A title")

or

rdf := PDFWriter.NewObject()
rdf.Data.WriteString(d.getMetadata()) // assume that this returns XML metadata
rdf.Dictionary = pdf.Dict{
    "Type":    "/Metadata",
    "Subtype": "/XML",
}
if err = rdf.Save(); err != nil {
    return err
}
PDFWriter.Catalog["Metadata"] = rdf.ObjectNumber.Ref()