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. 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.
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.
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 ¶
- Constants
- Variables
- func In(v float64) float64
- func Mm(v float64) float64
- func Pt(v float64) float64
- type CMYK
- type Color
- type Document
- type Font
- type Gray
- type Options
- type Page
- func (p *Page) AddLink(rect Rect, uri string)
- func (p *Page) AddNamedDest(name string, x, y float64)
- func (p *Page) AddNamedLink(rect Rect, dest string)
- func (p *Page) AddWidget(root toolkit.Widget, rect Rect, opts *WidgetOptions) error
- func (p *Page) AddWidgetVector(root toolkit.Widget, rect Rect, opts *WidgetOptions) error
- func (p *Page) Clip()
- func (p *Page) ClipEvenOdd()
- func (p *Page) ClosePath()
- func (p *Page) CurveTo(x1, y1, x2, y2, x3, y3 float64)
- func (p *Page) DrawImage(img image.Image, r Rect)
- func (p *Page) DrawJPEG(data []byte, r Rect) error
- func (p *Page) DrawPNG(data []byte, r Rect) error
- func (p *Page) EndPath()
- func (p *Page) Fill()
- func (p *Page) FillEvenOdd()
- func (p *Page) FillStroke()
- func (p *Page) FillStrokeEvenOdd()
- func (p *Page) Height() float64
- func (p *Page) LineTo(x, y float64)
- func (p *Page) MoveTo(x, y float64)
- func (p *Page) Rectangle(r Rect)
- func (p *Page) Restore()
- func (p *Page) Rotate(deg float64)
- func (p *Page) Save()
- func (p *Page) Scale(sx, sy float64)
- func (p *Page) SetAlpha(fill, stroke float64)
- func (p *Page) SetCharSpacing(v float64)
- func (p *Page) SetDash(pattern []float64, phase float64)
- func (p *Page) SetFillColor(c Color)
- func (p *Page) SetFont(f *Font, size float64)
- func (p *Page) SetLeading(v float64)
- func (p *Page) SetLineCap(style int)
- func (p *Page) SetLineJoin(style int)
- func (p *Page) SetLineWidth(w float64)
- func (p *Page) SetMiterLimit(limit float64)
- func (p *Page) SetRenderMode(mode int)
- func (p *Page) SetStrokeColor(c Color)
- func (p *Page) SetWordSpacing(v float64)
- func (p *Page) Skew(axDeg, ayDeg float64)
- func (p *Page) Stroke()
- func (p *Page) Text(x, y float64, s string) error
- func (p *Page) TextLines(x, y float64, lines []string) error
- func (p *Page) TextShaped(x, y float64, s string, features ...string) error
- func (p *Page) TextWidth(s string) float64
- func (p *Page) Transform(a, b, c, d, e, f float64)
- func (p *Page) Translate(tx, ty float64)
- func (p *Page) Width() float64
- func (p *Page) WrapText(s string, maxWidth float64) []string
- type PageSize
- type RGB
- type Rect
- type WidgetOptions
Examples ¶
Constants ¶
const ( CapButt = 0 CapRound = 1 CapSquare = 2 )
Line-cap styles for SetLineCap.
const ( JoinMiter = 0 JoinRound = 1 JoinBevel = 2 )
Line-join styles for SetLineJoin.
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).
const DefaultProducer = "go-pdfkit/pdfkit"
DefaultProducer is the /Producer value used when Options.Producer is empty.
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 ¶
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 ¶
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 (*Document) AddOutlineItem ¶ added in v0.9.0
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.
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 ¶
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) IsCFF ¶
IsCFF reports whether the font carries CFF/OpenType outlines (embedded as a CIDFontType0), as opposed to TrueType 'glyf' outlines (CIDFontType2).
func (*Font) UnitsPerEm ¶
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 and Author populate the document information dictionary. Empty
// values are omitted.
Title string
Author 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
// 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 (*Page) AddLink ¶ added in v0.7.0
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
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 (*Page) AddNamedLink ¶ added in v0.8.0
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
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
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 ¶
CurveTo adds a cubic Bézier segment to (x3, y3) with control points (x1, y1) and (x2, y2) (c).
func (*Page) DrawImage ¶
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.
func (*Page) DrawJPEG ¶
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 ¶
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) Rotate ¶
Rotate rotates the coordinate system counter-clockwise by deg degrees about the origin.
func (*Page) SetAlpha ¶
SetAlpha sets the constant fill and stroke alpha (opacity) in [0,1] via an ExtGState resource (ca/CA).
func (*Page) SetCharSpacing ¶
SetCharSpacing sets additional spacing between glyphs, in points (Tc).
func (*Page) SetDash ¶
SetDash sets the line dash pattern and phase (d). An empty pattern restores a solid line.
func (*Page) SetFillColor ¶
SetFillColor selects the fill colour.
func (*Page) SetFont ¶
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 ¶
SetLeading sets the line leading (baseline-to-baseline distance) used by TextLines, in points (TL).
func (*Page) SetLineCap ¶
SetLineCap sets the line-cap style (J).
func (*Page) SetLineJoin ¶
SetLineJoin sets the line-join style (j).
func (*Page) SetLineWidth ¶
SetLineWidth sets the stroke line width in user-space units (w).
func (*Page) SetMiterLimit ¶
SetMiterLimit sets the miter limit (M).
func (*Page) SetRenderMode ¶
SetRenderMode sets the text rendering mode (Tr); see the Render constants.
func (*Page) SetStrokeColor ¶
SetStrokeColor selects the stroke colour.
func (*Page) SetWordSpacing ¶
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) Text ¶
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 ¶
TextLines draws consecutive lines starting with the first baseline at (x, y), advancing by the current leading between lines.
func (*Page) TextShaped ¶
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").
func (*Page) TextWidth ¶
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 ¶
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.
type PageSize ¶
PageSize is a page's dimensions in points.
func NewPageSize ¶
NewPageSize builds a custom page size from a width and height in points.
type RGB ¶
type RGB struct{ R, G, B float64 }
RGB is a DeviceRGB colour with red, green and blue components in [0,1].
type Rect ¶
Rect is an axis-aligned rectangle in user space, given by its lower-left corner and its size.
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.