A modern PDF library for Go — layout engine, HTML to PDF, forms, digital signatures, barcodes, and PDF/A compliance.
go get github.com/carlos7ags/folioRequires Go 1.21+. One external dependency: golang.org/x/image.
package main
import (
"github.com/carlos7ags/folio/document"
"github.com/carlos7ags/folio/font"
"github.com/carlos7ags/folio/layout"
)
func main() {
doc := document.NewDocument(document.PageSizeA4)
doc.Info.Title = "Hello World"
doc.SetAutoBookmarks(true)
doc.Add(layout.NewHeading("Hello, Folio!", layout.H1))
doc.Add(layout.NewParagraph(
"Generated with Folio — the modern PDF library for Go.",
font.Helvetica, 12,
))
doc.Save("hello.pdf")
}The fastest way to generate PDFs — paste any HTML template and get a PDF. No Chrome, no Puppeteer, no server required.
import (
"github.com/carlos7ags/folio/document"
"github.com/carlos7ags/folio/html"
)
doc := document.NewDocument(document.PageSizeLetter)
elems, _ := html.Convert(`
<h1>Invoice #1042</h1>
<p>Bill to: <strong>Acme Corp</strong></p>
<table border="1">
<tr><th>Item</th><th>Amount</th></tr>
<tr><td>Consulting</td><td>$1,200</td></tr>
</table>
`, nil)
for _, e := range elems {
doc.Add(e)
}
doc.Save("invoice.pdf")Supports 40+ HTML elements, inline and <style> block CSS, flexbox, CSS grid,
SVG, named/hex/rgb colors, @page rules, and tables with colspan.
Try HTML to PDF live in your browser
Folio uses a plan-based layout engine — layout is a pure function with no mutation during rendering. Elements can be laid out multiple times safely, which makes page break splitting clean and predictable.
doc := document.NewDocument(document.PageSizeLetter)
doc.Info.Title = "Quarterly Report"
doc.Info.Author = "Finance Team"
doc.SetAutoBookmarks(true)
doc.Add(layout.NewHeading("Q3 Revenue Report", layout.H1))
doc.Add(layout.NewParagraph("Revenue grew 23% year over year.",
font.Helvetica, 12).
SetAlign(layout.AlignJustify).
SetSpaceAfter(10))
tbl := layout.NewTable().SetAutoColumnWidths()
h := tbl.AddHeaderRow()
h.AddCell("Product", font.HelveticaBold, 10)
h.AddCell("Units", font.HelveticaBold, 10)
h.AddCell("Revenue", font.HelveticaBold, 10)
r := tbl.AddRow()
r.AddCell("Widget A", font.Helvetica, 10)
r.AddCell("1,200", font.Helvetica, 10)
r.AddCell("$48,000", font.Helvetica, 10)
doc.Add(tbl)
doc.Save("report.pdf")| Element | Description |
|---|---|
Paragraph |
Word-wrapped text with alignment, leading, orphans/widows |
Heading |
H1-H6 with preset sizes, spacing, and auto-bookmarks |
Table |
Borders, colspan, rowspan, header repetition, auto-column widths |
List |
Bullet, numbered, Roman, alpha, nested |
Div |
Container with borders, background, padding |
Flex |
Flexbox layout with direction, wrap, alignment |
Image |
JPEG, PNG, TIFF with aspect ratio preservation |
LineSeparator |
Horizontal rule (solid, dashed, dotted) |
TabbedLine |
Tab stops with dot leaders (for TOCs) |
Link |
Clickable text with URL or internal destination |
Float |
Left/right floating with text wrap |
Columns |
Multi-column layout with automatic balancing |
AreaBreak |
Explicit page break |
BarcodeElement |
Code128, QR, EAN-13 inline in layout |
p := layout.NewStyledParagraph(
layout.Run("Normal text ", font.Helvetica, 12),
layout.Run("bold ", font.HelveticaBold, 12),
layout.Run("colored and underlined", font.Helvetica, 12).
WithColor(layout.ColorRed).
WithUnderline(),
)
doc.Add(p)tbl := layout.NewTable().SetAutoColumnWidths()
// Or explicit widths:
tbl.SetColumnUnitWidths([]layout.UnitValue{
layout.Pct(30), layout.Pct(70),
})
// Header rows repeat automatically on page breaks
h := tbl.AddHeaderRow()
h.AddCell("Name", font.HelveticaBold, 10)
h.AddCell("Value", font.HelveticaBold, 10)
r := tbl.AddRow()
cell := r.AddCell("Styled cell", font.Helvetica, 10)
cell.SetBorders(layout.AllBorders(layout.DashedBorder(1, layout.ColorBlue)))
cell.SetBackground(layout.ColorLightGray)
cell.SetVAlign(layout.VAlignMiddle)import "github.com/carlos7ags/folio/barcode"
qr, _ := barcode.QR("https://example.com")
doc.Add(layout.NewBarcodeElement(qr, 100).SetAlign(layout.AlignCenter))
bc, _ := barcode.Code128("SHIP-2024-001")
doc.Add(layout.NewBarcodeElement(bc, 200))
ean, _ := barcode.EAN13("590123412345")
doc.Add(layout.NewBarcodeElement(ean, 150))import "github.com/carlos7ags/folio/forms"
form := forms.NewAcroForm()
form.Add(forms.TextField("name", [4]float64{72, 700, 300, 720}, 0))
form.Add(forms.Checkbox("agree", [4]float64{72, 670, 92, 690}, 0, false))
form.Add(forms.Dropdown("role", [4]float64{72, 640, 250, 660}, 0,
[]string{"Developer", "Designer", "Manager"}))
doc.SetAcroForm(form)
doc.Save("form.pdf")import "github.com/carlos7ags/folio/sign"
signer, _ := sign.NewLocalSigner(privateKey, []*x509.Certificate{cert})
signed, _ := sign.SignPDF(pdfBytes, sign.Options{
Signer: signer,
Level: sign.LevelBB,
Reason: "Approved",
Location: "New York",
})
os.WriteFile("signed.pdf", signed, 0644)Supports PAdES B-B, B-T (timestamped), and B-LT (long-term validation with
embedded OCSP responses and CRLs). Also supports external signers (HSM, KMS)
via the Signer interface. Uses Go stdlib crypto.
import "github.com/carlos7ags/folio/reader"
// Read
r, _ := reader.Open("document.pdf")
fmt.Println("Pages:", r.PageCount())
page, _ := r.Page(0)
text, _ := page.ExtractText()
// Merge
r1, _ := reader.Open("doc1.pdf")
r2, _ := reader.Open("doc2.pdf")
m, _ := reader.Merge(r1, r2)
m.SaveTo("merged.pdf")doc.SetFooter(func(ctx document.PageContext, page *document.Page) {
text := fmt.Sprintf("Page %d of %d", ctx.PageIndex+1, ctx.TotalPages)
page.AddText(text, font.Helvetica, 9, 280, 30)
})
doc.SetWatermarkConfig(document.WatermarkConfig{
Text: "DRAFT",
FontSize: 72,
Opacity: 0.15,
Angle: 45,
})doc.SetTagged(true) // PDF/UA — screen readers, text extraction
doc.SetPdfA(document.PdfAConfig{Level: document.PdfA2B}) // archival
doc.SetAutoBookmarks(true) // auto-generate from headings
doc.SetPageLabels(
document.PageLabelRange{PageIndex: 0, Style: document.LabelRomanLower},
document.PageLabelRange{PageIndex: 4, Style: document.LabelDecimal},
)layout.ColorRed // 16 named colors
layout.RGB(0.2, 0.4, 0.8) // RGB
layout.CMYK(1, 0, 0, 0) // CMYK for print
layout.Hex("#FF8800") // hex string
layout.Gray(0.5) // grayscalego install github.com/carlos7ags/folio/cmd/folio@latest
folio merge -o combined.pdf doc1.pdf doc2.pdf
folio info document.pdf
folio text document.pdf
folio blank -o empty.pdf -size a4 -pages 5Element.PlanLayout(area) -> LayoutPlan (immutable)
PlacedBlock.Draw(ctx, x, y) -> PDF operators
- No mutation during layout — elements can be laid out multiple times safely
- Content splitting across pages via overflow elements
- Intrinsic sizing via MinWidth/MaxWidth for auto-column tables
- Deterministic output — byte-for-byte reproducible PDFs
- One external dependency —
golang.org/x/image
folio/
core/ PDF object model
content/ Content stream builder
document/ Document API (pages, outlines, PDF/A, watermarks)
font/ Standard 14 + TrueType embedding + subsetting
image/ JPEG, PNG, TIFF
layout/ Layout engine (all elements + rendering)
barcode/ Code128, QR, EAN-13
forms/ AcroForms (text, checkbox, radio, dropdown, signature)
html/ HTML + CSS to PDF conversion
svg/ SVG to PDF rendering
sign/ Digital signatures (PAdES, CMS, timestamps)
reader/ PDF parser (read, extract, merge)
cmd/folio/ CLI tool
- Template library — invoice, report, certificate, resume
- Hosted cloud API — POST HTML, get PDF
- Java SDK via Panama FFI
- .NET SDK via P/Invoke
Contributions welcome. Please open an issue before submitting large PRs.
git clone https://github.com/carlos7ags/folio
cd folio
go test ./...Apache License 2.0 — see LICENSE.
