Codync
免费开源的 1:1 Grok Bot 与 Muse 替代方案。可在 iPhone、Mac 或 Linux 桌面上将 Claude 代码、Codex、Cursor 以及 40 多个编码代理作为持久机器人使用。支持群组聊天、线程、应用。
AI 翻译
制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗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.
io.Writer; optional Flate stream compression.q/Q state, and
constant-alpha transparency via ExtGState./W width array and a /ToUnicode CMap for
copy/paste. TrueType glyf → FontFile2 / 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.
A layout engine that places its own glyphs draws them with
Page.ShowGlyphs — glyph ids at the positions it computed, each with the
text it stands for — and hands over the fonts it already parsed with
NewFont(*opentype.Font).Page.Shade).image.Image
rasterised as XObjects (FlateDecode) with an /SMask for alpha, the colour
samples written straight (not premultiplied), as a soft mask without
/Matte requires.
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.Document.NewForm(bbox) returns a
Form, drawn with every Page method (paths, colours, alpha, shadings,
images, text, other forms) in its own form space. Page.DrawForm(f, rect)
maps its box onto a rectangle, and Page.PaintForm(f, a, b, c, d, e, f)
places it under any matrix, and Page.Document() reaches the document from
a page to make forms. A form painted any number of times, on any page,
is one stream: a logo, an emoji or a formula used thirty times costs thirty
Do operators. Forms may paint forms made before or after them. A cycle is
refused (ErrFormCycle). A form's content belongs to the tagged sequence it
is painted in (§14.7.4.2), so BeginTag and tagged links inside a form write
nothing.Pt/Mm/In unit helpers.pdfkit/widget: widget.Add and
widget.AddVector "print" a
go-widgets/toolkit widget tree onto a
page.
Add rasterises the tree and places it as an image XObject,
pixel-identical to the screen.AddVector instead emits PDF vector operators, so fills and strokes stay
crisp and text stays selectable. A TrueType-font widget label is embedded
in its own face as real Type0 text.pdfkit alone does not link the toolkit: 196 packages instead of
403, and a test keeps it that way.Options, output has no timestamps and a
content-derived /ID, so identical inputs produce byte-identical PDFs.go get github.com/go-pdfkit/pdfkit
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.
Text a layout engine has already shaped and placed goes through
p.ShowGlyphs(x, y, glyphs): each pdfkit.Glyph is a glyph id, its origin's
offset from the run origin and the text it stands for (the /ToUnicode
entry). The same TJ encoding applies — a correction only where a position
departs from the font's own advance by a thousandth of an em or more, computed
from absolute positions so that the pen never drifts. go-webengine's
pdfcanvas draws a laid-out page this way.
import (
"github.com/go-pdfkit/pdfkit/widget"
"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.
_ = widget.Add(p, root, rect, nil)
// Vector: crisp fills/strokes, selectable text (needs an embedded Font).
rect.Y -= pdfkit.Mm(40)
_ = widget.AddVector(p, root, rect, &widget.Options{Font: font})
Options.Scale sets the layout-pixels-per-point ratio (default
widget.DefaultScale, 2). Options.Theme selects the toolkit theme (default
toolkit.DefaultLight()).
The widget bridge moved out of the root package. Make these replacements:
v0.19 (pdfkit) | v0.20 (pdfkit/widget) |
|---|---|
p.AddWidget(root, rect, opts) | widget.Add(p, root, rect, opts) |
p.AddWidgetVector(root, rect, opts) | widget.AddVector(p, root, rect, opts) |
pdfkit.WidgetOptions | widget.Options |
pdfkit.DefaultWidgetScale | widget.DefaultScale |
Nothing else changed. A program that never used the bridge only gets smaller.
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.
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.CFF/CFF2 table.AddLink, AddNamedDest and
AddNamedLink put a clickable /Link with a URI or a named destination over
a rectangle. Text (sticky note) annotations too, since v0.16.0:
Page.AddTextAnnotation puts a note with its contents, author, subject,
icon, colour and opacity on a page — go-slides carries a slide's speaker
notes in them. No other annotation type is written, and nothing here draws
an appearance stream — go-pdfkit/render does that when reading.AddOutlineItem) nest by level; since v0.16.0
AddOutlineItemWith styles a title bold or italic and points it at a place on
the page ([page /XYZ x y null]) instead of fitting the whole page.Page.BeginActualText(s) …
EndMarkedContent() wrap what is drawn in a /Span with /ActualText, the
text extraction, copying and search use instead of the glyphs. An empty
string hides decorations from the text (numbers in a margin, a numbered disc
after a line of code): Poppler's pdftotext then leaves them out. Spans left
open are closed when the page is written.go-pdfkit/reader reads RC4-40 through AES-256 and writes AES-128 and
AES-256 with permissions and both passwords.go-pdfkit/forms reads, fills and flattens
an AcroForm, and go-pdfkit/xfa reads the other kind.Document.Structure() returns
the root of the logical structure (ISO 32000-1, 14.7), and Add builds the
tree in reading order with the standard types (, ,
, ///, ,
and with , , …).
… ties what is drawn to an element
(a marked-content sequence with an MCID, mapped back through the parent
tree). marks backgrounds, page numbers and ornaments,
and puts a link annotation under its Link element with
its . Notes get an element of their own, and elements
with no content are left out. After v0.18.0, carries
the standard structure attributes (§14.8.5): a 's , which
PDF/UA asks for, a cell's … , and
(the XMP metadata with and ) complete what PDF/UA-1
asks of the file; a small tagged document passes veraPDF's PDF/UA-1
profile. Tagging every drawing is the caller's part. An untagged document
is written as before.BSD-3-Clause — see LICENSE. Copyright (c) 2026 the go-pdfkit/pdfkit authors.
StructSectStructH1StructPStructLStructLIStructLblStructLBodyStructTableStructFigureStructFormulaAltStructCodeStructLinkPage.BeginTag(e)EndMarkedContent()Page.BeginArtifactPage.AddTaggedLink/ContentsAnnotStructElem.AttributesTHScopeRowSpanOptions.LangDisplayDocTitlePDFUAdc:titlepdfuaid:partgo-pdfkit/ops preserves a structure tree it is given around
the pages that survive.