pdfkit

package module
v0.12.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: BSD-3-Clause Imports: 19 Imported by: 0

README

pdfkit

CI Go Reference Coverage

A pure-Go, zero-C PDF 1.7 writer with a Go-idiomatic API. It embeds TrueType and OpenType/CFF fonts as subsetted composite fonts, draws vector graphics and text, and places JPEG and raster images. Fonts are parsed and shaped with go-opentype; nothing outside the Go standard library and our own pure-Go libraries is required.

pdfkit is the Go-native counterpart to our Ruby Prawn port (go-ruby-prawn); here the API is Go-idiomatic rather than a gem port.

Features

  • Documents — catalog, page tree, cross-reference table and trailer; write to any io.Writer; optional Flate stream compression.
  • Graphics — paths (move/line/cubic/rect/close), fill & stroke (nonzero and even-odd), DeviceGray/RGB/CMYK colour, line width/cap/join/miter/dash, CTM transforms (translate/scale/rotate/skew), clipping, q/Q state, and constant-alpha transparency via ExtGState.
  • Text — embeds fonts as Type0 (Identity-H) composite fonts with glyph subsetting, a per-glyph /W width array and a /ToUnicode CMap for copy/paste. TrueType glyfFontFile2 / CIDFontType2 (compact subset with a /CIDToGIDMap stream); CFF/OpenType → FontFile3 / CIDFontType0 with CFF charstring subsetting (only the used glyphs' charstrings are embedded). Char/word spacing, leading, render modes, a simple wrapping helper, and an optional shaped-text API (GSUB/GPOS via go-opentype) for Arabic/Indic/CJK.
  • Images — JPEG embedded directly (DCTDecode); PNG and any image.Image rasterised as XObjects (FlateDecode) with an /SMask for alpha. Pixel-identical bitmaps are shared: each image is content-addressed by its uncompressed samples, so a repeat is embedded — and compressed — once per document and every placement, on any page, references the one XObject.
  • Pages — standard sizes (A3/A4/A5/Letter/Legal/Tabloid), portrait/landscape, custom sizes; Pt/Mm/In unit helpers.
  • Widget bridgePage.AddWidget and Page.AddWidgetVector "print" a go-widgets/toolkit widget tree onto a page. AddWidget rasterises the tree and places it as an image XObject — pixel-identical to the screen. AddWidgetVector instead emits PDF vector operators, so fills/strokes stay crisp and text stays selectable, including a TrueType-font widget label's own face embedded as real Type0 text.
  • Deterministic — with the zero Options, output has no timestamps and a content-derived /ID, so identical inputs produce byte-identical PDFs.

Install

go get github.com/go-pdfkit/pdfkit

Usage

package main

import (
	"os"

	"github.com/go-pdfkit/pdfkit"
)

func main() {
	ttf, _ := os.ReadFile("font.ttf")
	font, _ := pdfkit.LoadFont(ttf)

	doc := pdfkit.New(pdfkit.Options{Title: "Hello"})
	p := doc.AddPage(pdfkit.A4)

	p.SetFont(font, 24)
	p.Text(pdfkit.Mm(20), p.Height()-pdfkit.Mm(20), "Hello, pdfkit")

	p.SetStrokeColor(pdfkit.RGB8(0x0d, 0x94, 0x88))
	p.SetLineWidth(2)
	p.MoveTo(pdfkit.Mm(20), pdfkit.Mm(20))
	p.LineTo(pdfkit.Mm(190), pdfkit.Mm(20))
	p.Stroke()

	f, _ := os.Create("out.pdf")
	defer f.Close()
	doc.Write(f)
}

Shaped (complex-script) text uses p.TextShaped(x, y, s, features...), which runs the go-opentype shaper so Arabic, Indic and CJK position correctly. The run is written as one TJ array per baseline segment — a numeric correction only where shaping departs from the font's own advances (kerning, marks), none for plain text — and unchanged font/colour state is not rewritten, so a page of prose is a few tens of KB compressed, not hundreds. The default Text path stays a simple left-to-right cmap mapping.

Printing a widget tree
import "github.com/go-widgets/toolkit"

root := toolkit.NewContainer(toolkit.NewBoxLayout())
btn := toolkit.NewButton("Submit", nil)
btn.Style = toolkit.ButtonProminent
root.AddWidget(btn)
root.AddWidget(toolkit.NewLabel("Status: ready"))

rect := pdfkit.Rect{X: pdfkit.Mm(20), Y: pdfkit.Mm(200), Width: pdfkit.Mm(80), Height: pdfkit.Mm(30)}

// Raster: pixel-identical to the screen, not selectable.
_ = p.AddWidget(root, rect, nil)

// Vector: crisp fills/strokes, selectable text (needs an embedded Font).
rect.Y -= pdfkit.Mm(40)
_ = p.AddWidgetVector(root, rect, &pdfkit.WidgetOptions{Font: font})

WidgetOptions.Scale sets the layout-pixels-per-point ratio (default DefaultWidgetScale, 2); WidgetOptions.Theme selects the toolkit theme (default toolkit.DefaultLight()).

Testing

GOWORK=off CGO_ENABLED=0 go test ./... runs the suite at exact 100% statement coverage. Correctness is checked against an independent parser: generated documents are re-opened with rsc.io/pdf and their structure verified. The embedded TrueType subset is re-parsed with go-opentype and each drawn glyph, resolved through the /CIDToGIDMap, is confirmed contour-identical to the original; the embedded CFF subset is asserted smaller than the whole CFF table and re-parsed so each kept glyph still renders intact. Tests are deterministic and network-free: they use a synthesised TrueType font, a synthesised CFF2 font and a bundled OFL OpenType/CFF font.

Scope and limitations

  • Both outline flavours are subsetted: TrueType glyf fonts via go-opentype's SubsetTrueType (compact renumbering + a /CIDToGIDMap stream) and CFF/OpenType fonts via SubsetCFF (charstring subsetting, glyph numbering preserved). All subsetting and the font-descriptor metrics come straight from go-opentype; pdfkit keeps no private sfnt re-parse.
  • A CID-keyed CFF or a CFF2 (variable) font cannot be charstring-subsetted by the preserve-numbering path, so it gracefully falls back to embedding the whole CFF/CFF2 table.
  • Encryption, tagged/PDF-A, forms and annotations are not yet implemented.

License

BSD-3-Clause — see LICENSE. Copyright (c) 2026 the go-pdfkit/pdfkit authors.

Documentation

Overview

Package pdfkit is a pure-Go, CGO-free PDF 1.7 writer with a Go-idiomatic API.

It builds documents from pages, draws vector graphics and text, embeds TrueType and OpenType/CFF fonts as subsetted composite (Type0) fonts, and places JPEG and raster images. Fonts are parsed and shaped with github.com/go-opentype/opentype; nothing outside the Go standard library and our own pure-Go libraries is required.

Quick start

doc := pdfkit.New(pdfkit.Options{})
face, _ := pdfkit.LoadFont(ttfBytes)
p := doc.AddPage(pdfkit.A4)
p.SetFont(face, 24)
p.Text(72, 720, "Hello, PDF")
_ = doc.Write(w) // any io.Writer

Coordinate system

User space is measured in points (1/72 inch) with the origin at the lower-left corner and y increasing upward, matching PDF. The Pt, Mm and In helpers convert physical units; the standard page sizes (A4, Letter, ...) and NewPageSize give a page's dimensions.

Text and fonts

LoadFont parses a font blob once; a Font is immutable and may be shared. SetFont selects it for a page, then Text draws a left-to-right run. TextShaped runs the go-opentype shaper (GSUB/GPOS) for complex scripts and writes the run as one TJ array per baseline segment, with a numeric correction only where shaping departs from the font's own advances (kerning, marks). Font and colour operators are written once and not repeated while unchanged; coordinates carry at most four decimals. Every embedded font is written as a subset with Identity-H encoding, a per-glyph /W width array and a /ToUnicode CMap so copy and paste recover the original text. TrueType outlines embed as a subsetted FontFile2 / CIDFontType2 with a /CIDToGIDMap stream (the subset renumbers glyphs, so the map sends each CID — the original glyph id — to its subset id); CFF/OpenType outlines embed as a charstring-subsetted FontFile3 / CIDFontType0 whose glyph numbering is preserved, so an Identity /CIDToGIDMap suffices.

Images

DrawJPEG stores the original JPEG bytes as a DCTDecode stream, so nothing is re-encoded. DrawPNG and DrawImage walk any image.Image into 8-bit DeviceRGB samples compressed with FlateDecode, and an image that is not fully opaque gets its alpha channel as a DeviceGray /SMask.

An image is content-addressed by its uncompressed samples together with the width, height, colour space, bits per component and the alpha samples — the raw JPEG bytes in the DCTDecode case. Pixel-identical bitmaps therefore share a single XObject across the whole document, whichever page paints them and whichever entry point embedded them; the samples are hashed before they are compressed, so a repeat never pays for compression twice. This matters for pages that reuse one icon many times: an HTML renderer feeding pdfkit 166 rasterised copies of a handful of icon SVGs now emits a handful of streams.

Determinism

With the zero Options the output contains no timestamps and a content-derived /ID, so identical inputs produce byte-identical documents. Set Options.Now to stamp creation and modification dates. The image cache is consulted but never iterated: object order and /Im<i> numbering follow first-sighting order, so deduplication does not put map iteration on the output path.

Widget bridge

AddWidget and AddWidgetVector "print" a github.com/go-widgets/toolkit widget tree onto a page. AddWidget lays the tree out at the target size, renders it through a go-widgets/painter PixelPainter and places the result as an image XObject — any UI, exactly as it draws on screen. AddWidgetVector runs the same tree through a painter that emits PDF vector operators instead of pixels, so fills and strokes stay crisp and text drawn through the toolkit's built-in font becomes real, selectable PDF text (it needs a WidgetOptions.Font). A widget label set in a TrueType/OpenType toolkit font (a painter.Face) embeds that face's own bytes and is emitted as selectable Type0 text too, so vector output is not limited to the toolkit's built-in bitmap font.

Font embedding

go-opentype/opentype supplies every primitive PDF embedding needs: the descriptor scalars (units-per-em, bounding box, ascent/descent, cap height, italic angle, flags, StemV), the by-glyph advances for the /W array, and the glyph subsetters. TrueType 'glyf' fonts are subsetted with Font.SubsetTrueType and CFF fonts with Font.SubsetCFF, so pdfkit keeps no private sfnt re-parse or subsetter of its own. A CID-keyed CFF or a CFF2 (variable) font, which the preserve-numbering CFF subsetter does not handle, gracefully falls back to embedding its whole 'CFF '/'CFF2' table.

Example

Example builds a one-page document with embedded-font text and vector graphics, then writes it to a buffer. The output is deterministic: with the zero Options there are no timestamps and the /ID is content-derived.

package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"

	"github.com/go-pdfkit/pdfkit"
)

func main() {
	font, err := pdfkit.LoadFont(mustRead("testdata/SourceSerif4-Regular.otf"))
	if err != nil {
		panic(err)
	}

	doc := pdfkit.New(pdfkit.Options{Title: "Hello"})
	p := doc.AddPage(pdfkit.A4)

	p.SetFont(font, 24)
	_ = p.Text(pdfkit.Mm(20), p.Height()-pdfkit.Mm(20), "Hello, pdfkit")

	p.SetStrokeColor(pdfkit.RGB8(0x0d, 0x94, 0x88))
	p.SetLineWidth(2)
	p.MoveTo(pdfkit.Mm(20), pdfkit.Mm(20))
	p.LineTo(pdfkit.Mm(190), pdfkit.Mm(20))
	p.Stroke()

	var buf bytes.Buffer
	if err := doc.Write(&buf); err != nil {
		panic(err)
	}
	fmt.Println(strings.SplitN(buf.String(), "\n", 2)[0])
}

func mustRead(path string) []byte {
	b, err := os.ReadFile(path)
	if err != nil {
		panic(err)
	}
	return b
}
Output:
%PDF-1.7

Index

Examples

Constants

View Source
const (
	CapButt   = 0
	CapRound  = 1
	CapSquare = 2
)

Line-cap styles for SetLineCap.

View Source
const (
	JoinMiter = 0
	JoinRound = 1
	JoinBevel = 2
)

Line-join styles for SetLineJoin.

View Source
const (
	RenderFill       = 0 // fill glyphs
	RenderStroke     = 1 // stroke glyph outlines
	RenderFillStroke = 2 // fill then stroke
	RenderInvisible  = 3 // neither (useful for OCR text layers)
	RenderFillClip   = 4 // fill and add to clip
	RenderStrokeClip = 5 // stroke and add to clip
	RenderFSClip     = 6 // fill, stroke and add to clip
	RenderClip       = 7 // add to clip only
)

Text render modes for SetRenderMode (a subset of PDF's Tr values).

View Source
const DefaultProducer = "go-pdfkit/pdfkit"

DefaultProducer is the /Producer value used when Options.Producer is empty.

View Source
const DefaultWidgetScale = 2.0

DefaultWidgetScale is the number of layout pixels per PDF point used when WidgetOptions.Scale is unset. A value of 2 lays the tree out at twice the point resolution, giving crisper raster output and finer layout rounding.

Variables

View Source
var (
	A3      = PageSize{Width: Mm(297), Height: Mm(420)}
	A4      = PageSize{Width: Mm(210), Height: Mm(297)}
	A5      = PageSize{Width: Mm(148), Height: Mm(210)}
	Letter  = PageSize{Width: In(8.5), Height: In(11)}
	Legal   = PageSize{Width: In(8.5), Height: In(14)}
	Tabloid = PageSize{Width: In(11), Height: In(17)}
)

Standard ISO 216 A-series and US page sizes, in points.

Functions

func In

func In(v float64) float64

In converts inches to points.

func Mm

func Mm(v float64) float64

Mm converts millimetres to points.

func Pt

func Pt(v float64) float64

Pt returns v points unchanged. It documents intent at call sites.

Types

type CMYK

type CMYK struct{ C, M, Y, K float64 }

CMYK is a DeviceCMYK colour with cyan, magenta, yellow and black components in [0,1].

type Color

type Color interface {
	// contains filtered or unexported methods
}

Color is a paint in one of PDF's device colour spaces. Its ops method emits the content-stream operator that selects it for filling (stroke=false) or stroking (stroke=true). Component values are in the range [0,1].

type Document

type Document struct {
	// contains filtered or unexported fields
}

Document is a PDF document under construction. Build it with New, append pages with AddPage, then serialise with Write. It is not safe for concurrent use.

Example (MultiPage)

ExampleDocument_multiPage lays out several pages of different sizes.

package main

import (
	"bytes"
	"fmt"

	"github.com/go-pdfkit/pdfkit"
)

func main() {
	doc := pdfkit.New(pdfkit.Options{})
	doc.AddPage(pdfkit.A4)
	doc.AddPage(pdfkit.Letter.Landscape())
	doc.AddPage(pdfkit.NewPageSize(pdfkit.In(4), pdfkit.In(6)))

	var buf bytes.Buffer
	_ = doc.Write(&buf)
	fmt.Println(bytes.Contains(buf.Bytes(), []byte("/Count 3")))
}
Output:
true

func New

func New(opts Options) *Document

New returns a new, empty Document configured by opts.

func (*Document) AddOutlineItem added in v0.9.0

func (d *Document) AddOutlineItem(title string, level, pageIndex int)

AddOutlineItem appends a bookmark to the document outline: title at nesting level (1 = top level; a higher level nests under the most recent shallower item), jumping to page pageIndex (0-based). Out-of-range pages are ignored. Items build the /Outlines tree a PDF viewer shows as its navigation sidebar.

func (*Document) AddPage

func (d *Document) AddPage(size PageSize) *Page

AddPage appends a page of the given size (in points; see PageSize helpers and the standard sizes such as A4) and returns it for drawing.

func (*Document) Write

func (d *Document) Write(w io.Writer) error

Write serialises the document to w as a complete PDF file: PDF 1.7 with a classic cross-reference table, or, when Options.ObjectStreams is set, PDF 1.5 with its small objects packed into object streams and a cross-reference stream in place of the table. It returns the first write error encountered. Calling Write does not consume the document; it may be written more than once.

type Font

type Font struct {
	// contains filtered or unexported fields
}

Font is a loaded TrueType or OpenType font ready to be used and embedded. It is immutable and may be shared across documents and goroutines; per-document glyph usage is tracked separately by the Document. Build one with LoadFont.

func LoadFont

func LoadFont(data []byte) (*Font, error)

LoadFont parses a TrueType ('glyf') or OpenType/CFF ('OTTO'/CFF) font from its raw bytes. The bytes are retained and must not be mutated afterwards. Parsing, glyph indexing, metrics, shaping and subsetting are all delegated to github.com/go-opentype/opentype; pdfkit keeps no private sfnt re-parse.

func (*Font) BaseName

func (f *Font) BaseName() string

BaseName returns the font's PostScript name, used for the PDF /BaseFont.

func (*Font) IsCFF

func (f *Font) IsCFF() bool

IsCFF reports whether the font carries CFF/OpenType outlines (embedded as a CIDFontType0), as opposed to TrueType 'glyf' outlines (CIDFontType2).

func (*Font) NumGlyphs

func (f *Font) NumGlyphs() int

NumGlyphs returns the number of glyphs in the font.

func (*Font) UnitsPerEm

func (f *Font) UnitsPerEm() int

UnitsPerEm returns the font's design grid size.

type Gray

type Gray struct{ V float64 }

Gray is a DeviceGray colour: a single intensity from 0 (black) to 1 (white).

type Options

type Options struct {
	// Title, Author, Subject and Keywords populate the document information
	// dictionary. Empty values are omitted. Subject is a one-line description of
	// the document; Keywords is a list of search terms (conventionally
	// comma-separated). Each is written as a PDF text string, so a non-ASCII value
	// is encoded UTF-16BE.
	Title    string
	Author   string
	Subject  string
	Keywords string

	// Producer is the /Producer string in the information dictionary. When
	// empty it defaults to DefaultProducer.
	Producer string

	// Now, when non-nil, is called once at Write time to stamp /CreationDate
	// and /ModDate. When nil no dates are written, keeping output reproducible;
	// tests should leave it nil.
	Now func() time.Time

	// Compress enables FlateDecode compression of content and embedded-font
	// streams. Image streams choose their own filter regardless.
	Compress bool

	// ObjectStreams packs the document's non-stream objects — page and font
	// dictionaries, link annotations, outline items, name trees — into PDF 1.5
	// object streams and replaces the classic cross-reference table with a
	// cross-reference stream. With Compress also set the object streams are
	// flate-compressed as a whole, which is where the saving is: a link
	// annotation costs some 220 bytes as a bare indirect object plus its xref
	// line, and a few tens of bytes packed with its neighbours. Off by default,
	// so the bytes existing consumers get do not change: the file then declares
	// PDF 1.7 and carries every object bare with a classic table.
	ObjectStreams bool

	// ID, when both entries are non-nil, is used verbatim as the trailer /ID
	// pair. When nil the ID is derived deterministically from the document
	// body, so identical documents get identical IDs without a clock.
	ID [2][]byte
}

Options configures a Document. The zero value is valid and yields a deterministic, uncompressed document with no timestamps.

type Page

type Page struct {
	// contains filtered or unexported fields
}

Page is a single page's content. It accumulates a content stream as drawing methods are called; the operators mirror PDF's imaging model. The default user space has its origin at the lower-left corner with y increasing upward.

func (p *Page) AddLink(rect Rect, uri string)

AddLink adds a borderless clickable link over rect — in the same PDF user-space coordinates the drawing methods use — that opens uri when activated. It is how a typeset hyperref link (\href/\url) becomes navigable in the PDF, matching the <a href> the SVG output already emits.

func (*Page) AddNamedDest added in v0.8.0

func (p *Page) AddNamedDest(name string, x, y float64)

AddNamedDest anchors the named destination name at (x, y) on this page, so an internal link can jump to it. The point (x, y) is the top-left the viewer scrolls to, in the page's user space.

func (p *Page) AddNamedLink(rect Rect, dest string)

AddNamedLink adds a borderless clickable link over rect that jumps to the named destination dest in the same document — the in-PDF counterpart of the SVG output's <a href="#name"> for \hyperlink.

func (*Page) AddWidget added in v0.3.0

func (p *Page) AddWidget(root toolkit.Widget, rect Rect, opts *WidgetOptions) error

AddWidget lays root out to fill rect (in points), renders the whole widget tree to an RGBA raster through a painter.PixelPainter, and places that raster as an image XObject on the page at rect. It is the "print any UI to PDF" path: every widget renders exactly as it would on screen. opts may be nil.

func (*Page) AddWidgetVector added in v0.3.0

func (p *Page) AddWidgetVector(root toolkit.Widget, rect Rect, opts *WidgetOptions) error

AddWidgetVector lays root out to fill rect (in points) and renders the widget tree with PDF vector operators, so text stays selectable and edges stay crisp. Text is drawn with opts.Font, which must be non-nil. The whole tree is clipped to rect. opts may be nil only if a font is not needed, which is never the case for a real tree, so a nil-or-fontless opts returns errWidgetVectorNoFont.

func (*Page) Clip

func (p *Page) Clip()

Clip intersects the clipping path with the current path using the nonzero rule (W). It must be followed by a path-painting or EndPath operator.

func (*Page) ClipEvenOdd

func (p *Page) ClipEvenOdd()

ClipEvenOdd intersects the clipping path using the even-odd rule (W*).

func (*Page) ClosePath

func (p *Page) ClosePath()

ClosePath closes the current subpath with a straight segment to its start (h).

func (*Page) CurveTo

func (p *Page) CurveTo(x1, y1, x2, y2, x3, y3 float64)

CurveTo adds a cubic Bézier segment to (x3, y3) with control points (x1, y1) and (x2, y2) (c).

func (*Page) DrawImage

func (p *Page) DrawImage(img image.Image, r Rect)

DrawImage embeds img and paints it into the rectangle r (in points). Any alpha channel becomes a soft mask, so partially transparent images composite correctly. Sample data is FlateDecode-compressed.

Pixel-identical images share one XObject document-wide: the samples are hashed before they are compressed, so redrawing the same bitmap costs a hash and nothing else.

func (*Page) DrawJPEG

func (p *Page) DrawJPEG(data []byte, r Rect) error

DrawJPEG embeds JPEG bytes directly (DCTDecode, no re-encoding) into r, preserving the original compression. Grayscale (1), RGB/YCbCr (3) and CMYK (4) component counts are supported.

func (*Page) DrawPNG

func (p *Page) DrawPNG(data []byte, r Rect) error

DrawPNG decodes PNG bytes and embeds the image into r. It returns an error if the data is not a valid PNG.

func (*Page) EndPath

func (p *Page) EndPath()

EndPath ends the path with no fill or stroke (n), used after a clip.

func (*Page) Fill

func (p *Page) Fill()

Fill fills the current path with the nonzero winding rule (f).

func (*Page) FillEvenOdd

func (p *Page) FillEvenOdd()

FillEvenOdd fills the current path with the even-odd rule (f*).

func (*Page) FillStroke

func (p *Page) FillStroke()

FillStroke fills (nonzero) then strokes the current path (B).

func (*Page) FillStrokeEvenOdd

func (p *Page) FillStrokeEvenOdd()

FillStrokeEvenOdd fills (even-odd) then strokes the current path (B*).

func (*Page) Height

func (p *Page) Height() float64

Height returns the page height in points.

func (*Page) LineTo

func (p *Page) LineTo(x, y float64)

LineTo adds a straight segment to (x, y) (l).

func (*Page) MoveTo

func (p *Page) MoveTo(x, y float64)

MoveTo begins a new subpath at (x, y) (m).

func (*Page) Rectangle

func (p *Page) Rectangle(r Rect)

Rectangle adds a rectangle subpath (re).

func (*Page) Restore

func (p *Page) Restore()

Restore pops the graphics state (Q). The font/colour operators written since the matching Save are forgotten with it, so the next SetFont/SetFillColor/ SetStrokeColor writes even a value that looks unchanged.

func (*Page) Rotate

func (p *Page) Rotate(deg float64)

Rotate rotates the coordinate system counter-clockwise by deg degrees about the origin.

func (*Page) Save

func (p *Page) Save()

Save pushes the current graphics state (q).

func (*Page) Scale

func (p *Page) Scale(sx, sy float64)

Scale scales the coordinate system by (sx, sy).

func (*Page) SetAlpha

func (p *Page) SetAlpha(fill, stroke float64)

SetAlpha sets the constant fill and stroke alpha (opacity) in [0,1] via an ExtGState resource (ca/CA).

func (*Page) SetCharSpacing

func (p *Page) SetCharSpacing(v float64)

SetCharSpacing sets additional spacing between glyphs, in points (Tc).

func (*Page) SetDash

func (p *Page) SetDash(pattern []float64, phase float64)

SetDash sets the line dash pattern and phase (d). An empty pattern restores a solid line.

func (*Page) SetFillColor

func (p *Page) SetFillColor(c Color)

SetFillColor selects the fill colour. Selecting the colour already in force writes nothing.

func (*Page) SetFont

func (p *Page) SetFont(f *Font, size float64)

SetFont selects font f at the given size in points for subsequent text. The font is registered with the document for embedding on the first use.

func (*Page) SetLeading

func (p *Page) SetLeading(v float64)

SetLeading sets the line leading (baseline-to-baseline distance) used by TextLines, in points (TL).

func (*Page) SetLineCap

func (p *Page) SetLineCap(style int)

SetLineCap sets the line-cap style (J).

func (*Page) SetLineJoin

func (p *Page) SetLineJoin(style int)

SetLineJoin sets the line-join style (j).

func (*Page) SetLineWidth

func (p *Page) SetLineWidth(w float64)

SetLineWidth sets the stroke line width in user-space units (w).

func (*Page) SetMiterLimit

func (p *Page) SetMiterLimit(limit float64)

SetMiterLimit sets the miter limit (M).

func (*Page) SetRenderMode

func (p *Page) SetRenderMode(mode int)

SetRenderMode sets the text rendering mode (Tr); see the Render constants.

func (*Page) SetStrokeColor

func (p *Page) SetStrokeColor(c Color)

SetStrokeColor selects the stroke colour. Selecting the colour already in force writes nothing.

func (*Page) SetWordSpacing

func (p *Page) SetWordSpacing(v float64)

SetWordSpacing sets additional spacing at space characters, in points (Tw). It has no visible effect on composite (Type0) fonts and is provided for completeness.

func (*Page) Shade added in v0.12.0

func (p *Page) Shade(s Shading) error

Shade paints the gradient over the current clip.

PDF has no "fill this path with a gradient" operator: a gradient is painted through whatever clip is in force. So the shape comes first and the paint second — set the path, clip to it, then Shade:

p.MoveTo(...); p.CurveTo(...); p.ClosePath()
p.Clip(); p.EndPath()
p.Shade(g)

Wrap the pair in Save and Restore, or the clip stays in force for everything drawn afterwards.

It reports an error for fewer than two stops, for a stop with no colour, for offsets that do not strictly increase, and for stops that do not all share one colour space — PDF names the space once for the whole shading, so a gradient from grey to CMYK cannot be written rather than being quietly converted.

func (*Page) Skew

func (p *Page) Skew(axDeg, ayDeg float64)

Skew shears the coordinate system by the given x and y angles in degrees.

func (*Page) Stroke

func (p *Page) Stroke()

Stroke strokes the current path (S).

func (*Page) Text

func (p *Page) Text(x, y float64, s string) error

Text draws s with its baseline origin at (x, y) using the current font. It returns errNoFont if no font is set.

func (*Page) TextLines

func (p *Page) TextLines(x, y float64, lines []string) error

TextLines draws consecutive lines starting with the first baseline at (x, y), advancing by the current leading between lines.

func (*Page) TextShaped

func (p *Page) TextShaped(x, y float64, s string, features ...string) error

TextShaped draws s with complex-script shaping (GSUB substitution and GPOS positioning) via the go-opentype shaper, placing the run's origin at (x, y). The default Text path stays a simple left-to-right cmap mapping; use this for Arabic, Indic, CJK and any text needing ligatures, marks or kerning. features names OpenType feature tags to enable (e.g. "liga").

The run is written as one TJ array per baseline segment: the viewer advances the pen by each glyph's /W width itself, so the only numbers in the stream are the corrections where shaping put a glyph somewhere else (kerning, a positioned mark) — none at all for plain unkerned text. A glyph with a vertical offset gets its own positioned Tj, since TJ cannot move the pen vertically.

func (*Page) TextWidth

func (p *Page) TextWidth(s string) float64

TextWidth returns the width of s in points at the current font and size. It returns 0 when no font is set.

func (*Page) Transform

func (p *Page) Transform(a, b, c, d, e, f float64)

Transform concatenates the affine matrix [a b c d e f] onto the current transformation matrix (cm). Points map as x' = a*x + c*y + e and y' = b*x + d*y + f.

func (*Page) Translate

func (p *Page) Translate(tx, ty float64)

Translate shifts the coordinate system by (tx, ty).

func (*Page) Width

func (p *Page) Width() float64

Width returns the page width in points.

func (*Page) WrapText

func (p *Page) WrapText(s string, maxWidth float64) []string

WrapText greedily breaks s into lines no wider than maxWidth points at the current font and size, splitting on spaces. A single word wider than maxWidth occupies its own line. It returns nil if no font is set.

type PageSize

type PageSize struct {
	Width  float64
	Height float64
}

PageSize is a page's dimensions in points.

func NewPageSize

func NewPageSize(width, height float64) PageSize

NewPageSize builds a custom page size from a width and height in points.

func (PageSize) Landscape

func (s PageSize) Landscape() PageSize

Landscape returns s rotated to landscape orientation (width >= height).

func (PageSize) Portrait

func (s PageSize) Portrait() PageSize

Portrait returns s in portrait orientation (height >= width).

type RGB

type RGB struct{ R, G, B float64 }

RGB is a DeviceRGB colour with red, green and blue components in [0,1].

func RGB8

func RGB8(r, g, b uint8) RGB

RGB8 builds an RGB colour from 8-bit components (0-255).

type Rect

type Rect struct {
	X      float64
	Y      float64
	Width  float64
	Height float64
}

Rect is an axis-aligned rectangle in user space, given by its lower-left corner and its size.

type Shading added in v0.12.0

type Shading struct {
	X0, Y0, X1, Y1 float64
	Stops          []Stop
	ExtendStart    bool
	ExtendEnd      bool
}

A Shading is an axial gradient: colour interpolated along the line from (X0,Y0) to (X1,Y1), in the page's user space.

It is what a logo, a chart's fill and a printed background all need, and until now the only way to put one in a PDF from here was to rasterise it — which turns a shape that scales without limit into pixels, and on a large print is exactly the defect the vector file was chosen to avoid.

Extend says whether the end colours carry on past the ends of the axis. Without them the area beyond each end is left unpainted, which for a gradient used as a background shows as two hard bands of nothing.

type Stop added in v0.12.0

type Stop struct {
	Offset float64
	Color  Color
}

A Stop is one colour on a gradient, at a position along it from 0 at the start to 1 at the end.

type WidgetOptions added in v0.3.0

type WidgetOptions struct {
	// Theme is the toolkit theme the widgets paint with. When nil,
	// toolkit.DefaultLight() is used.
	Theme *toolkit.Theme

	// Scale is the number of layout pixels per PDF point. Values <= 0 default to
	// DefaultWidgetScale. Larger values give a crisper raster (AddWidget) and
	// finer layout rounding for both paths.
	Scale float64

	// Font is the embedded font used for selectable text on the vector path
	// (AddWidgetVector). It is ignored by the raster AddWidget path.
	Font *Font
}

WidgetOptions configures how a widget tree is transferred onto a page. The nil *WidgetOptions is valid and selects every default.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL