boxesandglue/baseline PDF backend#
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/boxesandglue/baseline-pdf and the import path is github.com/boxesandglue/baseline-pdf
. For the repository itself head to https://github.com/boxesandglue/baseline-pdf.
Installation#
The installation is very simple by importing the package into your code. First initialize a module and get the library:
and use the library:
package main
import (
"os"
pdf "github.com/boxesandglue/baseline-pdf"
)
func main() {
w, _ := os.Create("out.pdf")
pw := pdf.NewPDFWriter(w)
// ...
}
Getting started#
The following source creates a two page PDF with a single page contents stream which is re-used in both pages, but with a different viewport.
package main
import (
"log"
"os"
pdf "github.com/boxesandglue/baseline-pdf"
)
func dothings() error {
w, err := os.Create("out.pdf")
if err != nil {
return err
}
defer w.Close()
pw := pdf.NewPDFWriter(w)
pw.DefaultPageHeight = 510 // dtp point
pw.DefaultPageWidth = 310
pw.DefaultOffsetX = -10
pw.DefaultOffsetY = -10
// The contents of the page. A simple rectangle
// starting at 0,0 and width 300 and height 500
stream := pw.NewObject()
stream.Data.WriteString("0 0 300 500 re s")
if err = stream.Save(); err != nil {
return err
}
// The first page has the default dimensions.
// When you pass 0 as the second argument, the pages object
// will be created for you.
// Since we don't want to do anything else with the created page,
// the return value is discarded.
pw.AddPage(stream, 0)
// Page 2 has the same contents, but a different
// viewpoint:
page2 := pw.AddPage(stream, 0)
page2.Width = 100
page2.Height = 100
page2.OffsetX = -100
page2.OffsetY = -100
pw.Finish()
return nil
}
func main() {
if err := dothings(); err != nil {
log.Fatal(err)
}
}
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
which returns an object:
type PDF struct {
Catalog Dict
InfoDict Dict
DefaultOffsetX float64
DefaultOffsetY float64
DefaultPageWidth float64
DefaultPageHeight float64
Colorspaces []*Separation
NameDestinations map[String]*NameDest
Outlines []*Outline
Major uint
Minor uint
NoPages int // set when PDF is finished
}
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.
Logging#
The package variable
is an slog logger (*slog.Logger
) and initialized to write to os.Discard
and has the log level of math.MaxInt
, therefore it never logs anything unless replaced by a slog logger of your choice.
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
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