API Reference
JSON Schema
Define PDF documents declaratively with JSON
Overview
gpdf supports defining documents entirely in JSON. This is ideal for:
- API-driven PDF generation
- Dynamic documents from external data
- Template systems without Go code
- Configuration-based document creation
Basic Usage
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"body": [
{"row": {"cols": [
{"span": 12, "text": "Hello from JSON!", "style": {"size": 24, "bold": true}}
]}}
]
}`)
doc, err := template.FromJSON(schema, nil)
if err != nil {
log.Fatal(err)
}
data, err := doc.Generate()
┌─ A4 ──────────────────────────────────┐
│ │
│ Hello from JSON! ← 24pt, Bold │
│ │
└───────────────────────────────────────┘
Data Binding with Go Templates
JSON schemas support Go template expressions for dynamic content:
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"metadata": {"title": "{{.Title}}"},
"body": [
{"row": {"cols": [
{"span": 12, "text": "{{.Title}}", "style": {"size": 24, "bold": true}}
]}},
{"row": {"cols": [
{"span": 12, "text": "Author: {{.Author}}"}
]}}
]
}`)
data := map[string]any{
"Title": "Quarterly Report",
"Author": "ACME Corporation",
}
doc, err := template.FromJSON(schema, data)
Schema Structure
{
"page": {
"size": "A4",
"margins": "20mm"
},
"metadata": {
"title": "Document Title",
"author": "Author Name",
"subject": "Subject",
"creator": "Creator"
},
"header": [ /* rows */ ],
"footer": [ /* rows */ ],
"body": [ /* rows */ ]
}
Page Configuration
| Field | Values | Default |
|---|---|---|
size | Since v1.0.14 ISO 216 / ISO 269 names "A0"–"A10", "B0"–"B10", "C0"–"C10", "DL", "Letter", "Legal" (case-insensitive) | "A4" |
orientation | Since v1.0.14 "portrait", "landscape" — "landscape" swaps width and height | "portrait" |
margins | Dimension string: "20mm", "1in", "15pt" | — |
background | Since v1.0.15 Page background: {"color", "image", "fit", "opacity"} — see below | — |
Since v1.0.15 background draws beneath the content of every page. image accepts the same sources as an image src, fit is "cover" (default), "contain", "stretch" or "original", and opacity is 0.0–1.0:
"page": {"size": "A4", "background": {"color": "#FFFDF5", "image": "letterhead.png", "fit": "contain", "opacity": 0.25}}
Rows and Columns
{"row": {"cols": [
{"span": 6, "text": "Left column"},
{"span": 6, "text": "Right column"}
]}}
Complete Example
schema := []byte(`{
"page": {"size": "A4", "margins": "20mm"},
"metadata": {"title": "JSON Schema Example", "author": "gpdf"},
"header": [
{"row": {"cols": [
{"span": 6, "text": "gpdf JSON Schema", "style": {"size": 16, "bold": true, "color": "#1A237E"}},
{"span": 6, "text": "Document Header", "style": {"align": "right", "italic": true}}
]}},
{"row": {"cols": [
{"span": 12, "line": {"color": "#1A237E", "thickness": "1pt"}}
]}}
],
"footer": [
{"row": {"cols": [
{"span": 12, "elements": [
{"type": "line"},
{"type": "pageNumber", "style": {"align": "center"}}
]}
]}}
],
"body": [
{"row": {"cols": [
{"span": 12, "text": "JSON Schema Generation", "style": {"size": 24, "bold": true}}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "5mm"}
]}},
{"row": {"cols": [
{"span": 12, "text": "This PDF was generated from a JSON schema. No Go builder code needed!"}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 6, "elements": [
{"type": "text", "content": "Features", "style": {"size": 16, "bold": true}},
{"type": "list", "list": {"items": [
"Declarative document definition",
"All element types supported",
"Style options",
"Header and footer support"
]}}
]},
{"span": 6, "elements": [
{"type": "text", "content": "Supported Elements", "style": {"size": 16, "bold": true}},
{"type": "list", "list": {"type": "ordered", "items": [
"Text with styles",
"Tables with headers",
"Lists (ordered/unordered)",
"Lines and spacers",
"QR codes and barcodes",
"Images (base64)"
]}}
]}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 12, "table": {
"header": ["Feature", "Format", "Status"],
"rows": [
["Text styling", "JSON style object", "Supported"],
["Tables", "header + rows arrays", "Supported"],
["Lists", "ordered/unordered", "Supported"],
["Images", "base64 encoded", "Supported"],
["QR codes", "data string", "Supported"],
["Barcodes", "Code128", "Supported"]
],
"columnWidths": [35, 35, 30],
"headerStyle": {"bold": true, "color": "white", "background": "#1A237E"},
"stripeColor": "#F5F5F5"
}}
]}},
{"row": {"cols": [
{"span": 12, "spacer": "10mm"}
]}},
{"row": {"cols": [
{"span": 6, "qrcode": {"data": "https://gpdf.dev", "size": "25mm"}},
{"span": 6, "barcode": {"data": "GPDF-JSON-001", "format": "code128"}}
]}}
]
}`)
doc, err := template.FromJSON(schema, nil)
┌─ A4 ──────────────────────────────────────────────┐
│ gpdf JSON Schema Document Header │ ← header
│ ──────────────────────────────────────────────── │
│ │
│ JSON Schema Generation ← 24pt bold │
│ │
│ This PDF was generated from a JSON schema. │
│ │
│ Features Supported Elements │
│ • Declarative... 1. Text with styles │
│ • All element... 2. Tables with headers │
│ • Style options 3. Lists │
│ • Header/footer 4. Lines and spacers │
│ 5. QR codes and barcodes │
│ 6. Images (base64) │
│ │
│ ┌──────────┬──────────────────┬──────────┐ │
│ │ Feature │ Format │ Status │ │
│ ├──────────┼──────────────────┼──────────┤ │
│ │ Text │ JSON style obj │Supported │ │
│ │ Tables │ header + rows │Supported │ │
│ │ ... │ ... │ ... │ │
│ └──────────┴──────────────────┴──────────┘ │
│ │
│ ┌────┐ ║║│║║│║║║│║║│ │
│ │ QR │ GPDF-JSON-001 │
│ └────┘ │
│ │
│ ──────────────────────────────────────────────── │
│ Page 1 │ ← footer
└───────────────────────────────────────────────────┘
Element Types in JSON
Column Shorthand
For single elements, use shorthand directly on the column:
{"span": 12, "text": "Hello", "style": {"bold": true}}
{"span": 12, "spacer": "10mm"}
{"span": 12, "line": {"color": "#FF0000"}}
Elements Array
For multiple elements in one column, use the elements array:
{"span": 12, "elements": [
{"type": "text", "content": "Title", "style": {"size": 18, "bold": true}},
{"type": "spacer", "height": "5mm"},
{"type": "text", "content": "Body text"},
{"type": "line"},
{"type": "pageNumber", "style": {"align": "center"}}
]}
Since v1.0.15 A link element is text that links to style.link, drawn blue and underlined by default:
{"type": "link", "content": "Visit gpdf.dev", "style": {"link": "https://gpdf.dev"}}
Style Object
{
"size": 16,
"bold": true,
"italic": true,
"color": "#1A237E",
"background": "#F5F5F5",
"align": "center",
"font": "NotoSansJP"
}
| Field | Type | Description |
|---|---|---|
size | number | Font size in points |
bold | boolean | Bold weight |
italic | boolean | Italic style |
color | string | Text color ("#RRGGBB", "red", "blue", etc.) |
background | string | Background color |
align | string | "left", "center", "right" |
font | string | Font family name |
borderRadius | string | Since v1.0.15 Round the background corners (e.g. "4pt") |
opacity | number | Since v1.0.15 Opacity 0.0–1.0 |
link | string | Since v1.0.15 URI the text links to (also works on rich-text fragments) |
Table Object
{
"header": ["Col A", "Col B", "Col C"],
"rows": [
["A1", "B1", "C1"],
["A2", "B2", "C2"]
],
"columnWidths": [40, 30, 30],
"columnAlign": ["left", "right", "right"],
"headerStyle": {"bold": true, "color": "white", "background": "#1A237E"},
"stripeColor": "#F5F5F5",
"border": {"width": "1pt", "color": "#1A237E"},
"cellBorder": {"width": "0.5pt", "color": "gray(0.5)", "style": "dashed"},
"borderCollapse": true,
"background": "#FAFAFA"
}
Since v1.0.10 columnAlign sets per-column horizontal text alignment ("left", "center", "right") for both header and body cells. Columns without an entry fall back to left alignment.
Since v1.0.7 border draws an outer frame, cellBorder adds the same border around every header + body cell (grid lines), borderCollapse merges adjacent cell borders, and background fills the table's outer box. See Border Object for the shape of border / cellBorder.
Image Object
{"span": 6, "image": {
"src": "data:image/png;base64,...",
"width": "60mm",
"minWidth": "40mm",
"border": {"widths": ["2pt", "2pt", "2pt", "2pt"], "color": "#E53935"},
"background": "#FFF8E1"
}}
| Field | Description |
|---|---|
src | Base64, data URI, or file path. Since v1.0.15 SVG is also accepted, including data:image/svg+xml;utf8,... URIs and inline <svg> markup |
width / height | Display dimension |
minWidth / minHeight | Since v1.0.6 Overflow to next page when shrinking below this would be required |
fit | "contain" (default), "cover", "stretch", "original" |
align | "left", "center", "right" |
border | Since v1.0.7 Border around the image (see Border Object) |
background | Since v1.0.7 Fill color behind the image (handy for transparent PNGs) |
borderRadius | Since v1.0.15 Clip the image to rounded corners |
opacity | Since v1.0.15 Opacity 0.0–1.0 |
link | Since v1.0.15 URI the image links to |
Border Object
Since v1.0.7
Used by table.border, table.cellBorder, and image.border:
{
"width": "1pt",
"color": "#1A237E",
"style": "solid"
}
For per-edge widths in CSS order (top, right, bottom, left), use widths instead of width:
{"widths": ["2pt", "1pt", "2pt", "1pt"], "color": "#1A237E", "style": "dashed"}
| Field | Type | Description |
|---|---|---|
width | string | Uniform edge width (e.g. "1pt", "0.5mm") |
widths | array of 4 strings | Per-edge widths [top, right, bottom, left] (wins over width) |
color | string | Edge color ("#RRGGBB", named, or "gray(0.5)") |
style | string | "solid" (default), "dashed", "dotted", "none" |
Rich Text Object
Since v1.0.14
A paragraph made of inline fragments with individual styles — the JSON equivalent of ColBuilder.RichText. Use it as a column shorthand ("richText": {...}) or as an element ({"type": "richText", "richText": {...}}):
{"span": 12, "richText": {
"style": {"align": "center"},
"fragments": [
{"text": "Welcome to "},
{"text": "{{.AppName}}", "style": {"bold": true, "color": "#007BFF"}},
{"text": "! Status: "},
{"text": "PAID", "style": {"bold": true, "color": "#2E7D32"}},
{"text": " — "},
{"text": "old price", "style": {"strikethrough": true}}
]
}}
{"type": "richText", "richText": {"fragments": [
{"text": "Normal, "},
{"text": "italic", "style": {"italic": true}},
{"text": " and "},
{"text": "underlined", "style": {"underline": true}}
]}}
| Field | Type | Description |
|---|---|---|
style | object | Paragraph-level Style Object (e.g. align); also the base style of every fragment |
fragments | array | Inline spans {"text": string, "style": Style}; each fragment's style is applied on top of the block style |
Fragment text is evaluated by Go templates like any other string, so {{.AppName}} is replaced with your data when you call template.FromJSON(schema, data).
Box Object
Since v1.0.14
A styled container that stacks its nested elements vertically — the JSON equivalent of ColBuilder.Box. Use it as a column shorthand ("box": {...}) or as an element ({"type": "box", "box": {...}}). Boxes can be nested to build layouts the flat row/column grid cannot express on its own:
{"row": {"cols": [
{"span": 3, "box": {
"background": "#E8EAF6", "height": "20mm", "padding": "3mm",
"elements": [{"type": "text", "content": "LOGO", "style": {"bold": true, "align": "center"}}]
}},
{"span": 5, "box": {
"padding": "2mm",
"elements": [
{"type": "text", "content": "line 1"},
{"type": "text", "content": "line 2"}
]
}},
{"span": 4, "box": {
"border": {"width": "1pt", "color": "#1A237E"},
"paddings": ["2mm", "3mm", "2mm", "3mm"],
"elements": [
{"type": "text", "content": "Outer box", "style": {"bold": true}},
{"type": "box", "box": {
"background": "#FFF3E0", "padding": "2mm",
"elements": [{"type": "text", "content": "Nested box"}]
}}
]
}}
]}}
| Field | Type | Description |
|---|---|---|
width / height | string | Box dimensions (dimension string, e.g. "60mm") |
padding | string | Uniform inner padding |
paddings | array of 4 strings | Per-edge padding [top, right, bottom, left] (wins over padding) |
margin | string | Uniform outer margin |
margins | array of 4 strings | Per-edge margin [top, right, bottom, left] (wins over margin) |
background | string | Fill color |
border | object | Border around the box (see Border Object) |
elements | array | Nested elements stacked vertically (same shape as the Elements Array); may contain another box |
borderRadius | string | Since v1.0.15 Round the background and border corners |
opacity | number | Since v1.0.15 Opacity 0.0–1.0 of the box and its content |
link | string | Since v1.0.15 URI the whole box links to |
List Object
{"type": "list", "list": {"items": ["Item 1", "Item 2", "Item 3"]}}
{"type": "list", "list": {"type": "ordered", "items": ["First", "Second", "Third"]}}
QR Code Object
{"span": 6, "qrcode": {"data": "https://gpdf.dev", "size": "25mm", "minSize": "20mm"}}
Since v1.0.6 minSize moves the QR code to the next page instead of shrinking it below the given dimension when the remaining space is too small.
Barcode Object
{"span": 6, "barcode": {"data": "INV-001", "format": "code128"}}
Absolute Positioning
Place elements at exact XY coordinates, outside the normal grid flow:
{
"absolute": [
{
"x": "120mm",
"y": "20mm",
"elements": [
{"type": "text", "content": "CONFIDENTIAL", "style": {"size": 20, "bold": true, "color": "red"}}
]
},
{
"x": "10mm",
"y": "250mm",
"width": "25mm",
"height": "25mm",
"elements": [
{"type": "qrcode", "qrcode": {"data": "https://gpdf.dev", "size": "20mm"}}
]
},
{
"x": "0mm",
"y": "0mm",
"origin": "page",
"elements": [
{"type": "text", "content": "Page origin"}
]
}
]
}
The absolute array can appear at the top level (applies to all pages) or inside individual page definitions.
| Field | Type | Required | Description |
|---|---|---|---|
x | string | Yes | X coordinate (dimension string) |
y | string | Yes | Y coordinate (dimension string) |
width | string | No | Explicit width (default: remaining space) |
height | string | No | Explicit height (default: remaining space) |
origin | string | No | "content" (default) or "page" |
elements | array | Yes | Array of element objects |
Dimension Strings
| Format | Example |
|---|---|
| Millimeters | "20mm" |
| Points | "12pt" |
| Centimeters | "2.5cm" |
| Inches | "1in" |
Named Colors
JSON schemas support named colors: "red", "green", "blue", "yellow", "cyan", "magenta", "black", "white", "gray".
Or use hex format: "#FF6B6B", "#1A237E".
Combining with Go Options
Override or extend JSON schemas with Go options:
fontData, _ := os.ReadFile("fonts/NotoSansJP-Regular.ttf")
doc, err := template.FromJSON(schema, data,
template.WithFont("NotoSansJP", fontData),
template.WithDefaultFont("NotoSansJP", 12),
)