JSON Schema

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
size"A4", "A3", "Letter", "Legal""A4"
marginsDimension string: "20mm", "1in", "15pt"

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"}}
]}

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

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
width / heightDisplay 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)

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"

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