Getting started

You need Go version 1.18 or later.

Let’s start with an empty directory and a new Go module:

go mod init bagtest

and create a file main.go which looks like this:

package main

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/speedata/boxesandglue/backend/bag"
	"github.com/speedata/boxesandglue/frontend"
)

var (
	str = `In olden times when wishing still helped one, there lived a king whose daughters
	were all beautiful; and the youngest was so beautiful that the sun itself, which
	has seen so much, was astonished whenever it shone in her face.
	Close by the king's castle lay a great dark forest, and under an old lime-tree in the forest
	was a well, and when the day was very warm, the king's child went out into the
	forest and sat down by the side of the cool fountain; and when she was bored she
	took a golden ball, and threw it up on high and caught it; and this ball was her
	favorite plaything.`
)

func typesetSample() error {
	f, err := frontend.New("sample.pdf")
	if err != nil {
		return err
	}

	f.Doc.Title = "The frog king"

	if f.Doc.DefaultLanguage, err = frontend.GetLanguage("en"); err != nil {
		return err
	}

	// Load a font, define a font family, and add this font to the family.
	ff := f.NewFontFamily("text")
	ff.AddMember(
		&frontend.FontSource{Source: "fonts/CrimsonPro-Regular.ttf"},
		frontend.FontWeight400,
		frontend.FontStyleNormal,
	)

	// Create a recursive data structure for typesetting initialized with the
	// text from the top (but with space normalized).
	para := frontend.NewParagraph()
	para.Items = []any{strings.Join(strings.Fields(str), " ")}

	// Format the text into a paragraph. Some of these settings (font family and
	// font size) can be part of the typesetting element.
	vlist, _, err := f.FormatParagraph(para, bag.MustSp("125pt"),
		frontend.Leading(bag.MustSp("14pt")),
		frontend.FontSize(bag.MustSp("12pt")),
		frontend.Family(ff),
	)
	if err != nil {
		return err
	}

	// Output the text and finish the page and the PDF file.
	p := f.Doc.NewPage()
	p.OutputAt(bag.MustSp("1cm"), bag.MustSp("26cm"), vlist)
	p.Shipout()
	if err = f.Doc.Finish(); err != nil {
		return err
	}
	return nil
}

func main() {
	starttime := time.Now()
	err := typesetSample()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("finished in ", time.Now().Sub(starttime))
}

Run go mod tidy to let Go download all required libraries and get the font from https://fonts.google.com/specimen/Crimson+Pro. Then you can run the program by calling go run main.go. You will see output such as:

{"level":"info","ts":1654157162.5800772,"caller":"pdf/pdffont.go:109","msg":"Load font fonts/CrimsonPro-VariableFont_wght.ttf"}
{"level":"info","ts":1654157162.589091,"caller":"pdf/pdffont.go:165","msg":"Write font fonts/CrimsonPro-VariableFont_wght.ttf to PDF"}
{"level":"info","ts":1654157162.5899708,"caller":"document/document.go:671","msg":"Output written to sample.pdf (7715 bytes)"}

The result is a file called sample.pdf which looks like this:

samplepdf