func (c *Canvas) font(fnt font.Face, pt vg.Point) {
	if _, ok := c.fonts[fnt.Font]; ok {
		return
	}
	name := fnt.Name()
	key := fontKey{font: fnt, embed: c.embed}
	raw := new(bytes.Buffer)
	_, err := fnt.Face.WriteSourceTo(nil, raw)
	if err != nil {
		log.Panicf("vgpdf: could not generate font %q data for PDF: %+v", name, err)
	}
	zdata, jdata, err := getFont(key, raw.Bytes(), codePageEncoding)
	if err != nil {
		log.Panicf("vgpdf: could not generate font data for PDF: %v", err)
	}
	c.fonts[fnt.Font] = struct{}{}
	c.doc.AddFontFromBytes(name, "", jdata, zdata)
}
font registers a font and a size with the PDF canvas.
package vgpdf  
import (
	"bufio"
	"bytes"
	_ "embed"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"io"
	"log"
	"math"
	"os"
	"path/filepath"
	"sync"
	pdf "github.com/go-pdf/fpdf"
	stdfnt "golang.org/x/image/font"
	"gonum.org/v1/plot/font"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
)
var codePageEncoding []byte
func init() {
	draw.RegisterFormat("pdf", func(w, h vg.Length) vg.CanvasWriterTo {
		return New(w, h)
	})
}
const DPI = 72
type Canvas struct {
	doc  *pdf.Fpdf
	w, h vg.Length
	dpi       int
	numImages int
	stack     []context
	fonts     map[font.Font]struct{}
	embed bool
}
type context struct {
	fill  color.Color
	line  color.Color
	width vg.Length
}
func New(w, h vg.Length) *Canvas {
	cfg := pdf.InitType{
		UnitStr: "pt",
		Size:    pdf.SizeType{Wd: w.Points(), Ht: h.Points()},
	}
	c := &Canvas{
		doc:   pdf.NewCustom(&cfg),
		w:     w,
		h:     h,
		dpi:   DPI,
		stack: make([]context, 1),
		fonts: make(map[font.Font]struct{}),
		embed: true,
	}
	c.NextPage()
	vg.Initialize(c)
	return c
}
func (c *Canvas) EmbedFonts(v bool) bool {
	prev := c.embed
	c.embed = v
	return prev
}
func (c *Canvas) DPI() float64 {
	return float64(c.dpi)
}
func (c *Canvas) context() *context {
	return &c.stack[len(c.stack)-1]
}
func (c *Canvas) Size() (w, h vg.Length) {
	return c.w, c.h
}
func (c *Canvas) SetLineWidth(w vg.Length) {
	c.context().width = w
	lw := c.unit(w)
	c.doc.SetLineWidth(lw)
}
func (c *Canvas) SetLineDash(dashes []vg.Length, offs vg.Length) {
	ds := make([]float64, len(dashes))
	for i, d := range dashes {
		ds[i] = c.unit(d)
	}
	c.doc.SetDashPattern(ds, c.unit(offs))
}
func (c *Canvas) SetColor(clr color.Color) {
	if clr == nil {
		clr = color.Black
	}
	c.context().line = clr
	c.context().fill = clr
	r, g, b, a := rgba(clr)
	c.doc.SetFillColor(r, g, b)
	c.doc.SetDrawColor(r, g, b)
	c.doc.SetTextColor(r, g, b)
	c.doc.SetAlpha(a, "Normal")
}
func (c *Canvas) Rotate(r float64) {
	c.doc.TransformRotate(-r*180/math.Pi, 0, 0)
}
func (c *Canvas) Translate(pt vg.Point) {
	xp, yp := c.pdfPoint(pt)
	c.doc.TransformTranslate(xp, yp)
}
func (c *Canvas) Scale(x float64, y float64) {
	c.doc.TransformScale(x*100, y*100, 0, 0)
}
func (c *Canvas) Push() {
	c.stack = append(c.stack, *c.context())
	c.doc.TransformBegin()
}
func (c *Canvas) Pop() {
	c.doc.TransformEnd()
	c.stack = c.stack[:len(c.stack)-1]
}
func (c *Canvas) Stroke(p vg.Path) {
	if c.context().width > 0 {
		c.pdfPath(p, "D")
	}
}
func (c *Canvas) Fill(p vg.Path) {
	c.pdfPath(p, "F")
}
func (c *Canvas) FillString(fnt font.Face, pt vg.Point, str string) {
	if fnt.Font.Size == 0 {
		return
	}
	c.font(fnt, pt)
	style := ""
	if fnt.Font.Weight == stdfnt.WeightBold {
		style += "B"
	}
	if fnt.Font.Style == stdfnt.StyleItalic {
		style += "I"
	}
	c.doc.SetFont(fnt.Name(), style, c.unit(fnt.Font.Size))
	c.Push()
	defer c.Pop()
	c.Translate(pt)
	c.Scale(1, -1)
	left, top, right, bottom := c.sbounds(fnt, str)
	w := right - left
	h := bottom - top
	margin := c.doc.GetCellMargin()
	c.doc.MoveTo(-left-margin, top)
	c.doc.CellFormat(w, h, str, "", 0, "BL", false, 0, "")
}
func (c *Canvas) sbounds(fnt font.Face, txt string) (left, top, right, bottom float64) {
	_, h := c.doc.GetFontSize()
	style := ""
	if fnt.Font.Weight == stdfnt.WeightBold {
		style += "B"
	}
	if fnt.Font.Style == stdfnt.StyleItalic {
		style += "I"
	}
	d := c.doc.GetFontDesc(fnt.Name(), style)
	if d.Ascent == 0 {
		top = 0.81 * h
	} else {
		top = -float64(d.Ascent) * h / float64(d.Ascent-d.Descent)
	}
	return 0, top, c.doc.GetStringWidth(txt), top + h
}
func (c *Canvas) DrawImage(rect vg.Rectangle, img image.Image) {
	opts := pdf.ImageOptions{ImageType: "png", ReadDpi: true}
	name := c.imageName()
	buf := new(bytes.Buffer)
	err := png.Encode(buf, img)
	if err != nil {
		log.Panicf("error encoding image to PNG: %v", err)
	}
	c.doc.RegisterImageOptionsReader(name, opts, buf)
	xp, yp := c.pdfPoint(rect.Min)
	wp, hp := c.pdfPoint(rect.Size())
	c.doc.ImageOptions(name, xp, yp, wp, hp, false, opts, 0, "")
}