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

FieldValuesDefault
sizeSince v1.0.14 ISO 216 / ISO 269 names "A0"–"A10", "B0"–"B10", "C0"–"C10", "DL", "Letter", "Legal" (case-insensitive)"A4"
orientationSince v1.0.14 "portrait", "landscape" — "landscape" swaps width and height"portrait"
marginsDimension string: "20mm", "1in", "15pt"—
backgroundSince 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"
}
FieldTypeDescription
sizenumberFont size in points
boldbooleanBold weight
italicbooleanItalic style
colorstringText color ("#RRGGBB", "red", "blue", etc.)
backgroundstringBackground color
alignstring"left", "center", "right"
fontstringFont family name
borderRadiusstringSince v1.0.15 Round the background corners (e.g. "4pt")
opacitynumberSince v1.0.15 Opacity 0.0–1.0
linkstringSince 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"
}}
FieldDescription
srcBase64, 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 / heightDisplay dimension
minWidth / minHeightSince v1.0.6 Overflow to next page when shrinking below this would be required
fit"contain" (default), "cover", "stretch", "original"
align"left", "center", "right"
borderSince v1.0.7 Border around the image (see Border Object)
backgroundSince v1.0.7 Fill color behind the image (handy for transparent PNGs)
borderRadiusSince v1.0.15 Clip the image to rounded corners
opacitySince v1.0.15 Opacity 0.0–1.0
linkSince 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"}
FieldTypeDescription
widthstringUniform edge width (e.g. "1pt", "0.5mm")
widthsarray of 4 stringsPer-edge widths [top, right, bottom, left] (wins over width)
colorstringEdge color ("#RRGGBB", named, or "gray(0.5)")
stylestring"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}}
]}}
FieldTypeDescription
styleobjectParagraph-level Style Object (e.g. align); also the base style of every fragment
fragmentsarrayInline 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"}]
            }}
        ]
    }}
]}}
FieldTypeDescription
width / heightstringBox dimensions (dimension string, e.g. "60mm")
paddingstringUniform inner padding
paddingsarray of 4 stringsPer-edge padding [top, right, bottom, left] (wins over padding)
marginstringUniform outer margin
marginsarray of 4 stringsPer-edge margin [top, right, bottom, left] (wins over margin)
backgroundstringFill color
borderobjectBorder around the box (see Border Object)
elementsarrayNested elements stacked vertically (same shape as the Elements Array); may contain another box
borderRadiusstringSince v1.0.15 Round the background and border corners
opacitynumberSince v1.0.15 Opacity 0.0–1.0 of the box and its content
linkstringSince 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.

FieldTypeRequiredDescription
xstringYesX coordinate (dimension string)
ystringYesY coordinate (dimension string)
widthstringNoExplicit width (default: remaining space)
heightstringNoExplicit height (default: remaining space)
originstringNo"content" (default) or "page"
elementsarrayYesArray of element objects

Dimension Strings

FormatExample
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),
)