shridarpatil/zigpdf
High-performance PDF generation system using declarative PDM templates.
Ultra-fast PDF generation framework written in Zig
Generate PDFs in 1-8ms with declarative templates. Production-ready, language-agnostic CLI that works with any programming language.
New to ZigPDF? β QUICKSTART.md - Get started in 5 minutes
Build & Run:
zig build
./zig-out/bin/zigpdf --help
Generate your first PDF:
# Create template
cat > invoice.pdm <<'EOF'
#page(width: 595, height: 842, margin: 50)
#font(helvetica-bold, helvetica)
#text("{{title}}", font: 0, size: 18, margin-bottom: 10)
#text("Date: {{date}}", font: 1, size: 12)
EOF
# Compile template
./zig-out/bin/zigpdf --markup-to-template invoice.pdm invoice.bin
# Generate PDF
echo '{"fields":{"title":"Invoice #001","date":"2024-10-10"}}' | \
./zig-out/bin/zigpdf --generate-pdf invoice.bin - output.pdf
π Done! PDF created in ~1ms
{{variable}}
substitutionWorks with any programming language via simple CLI:
#if
/#else
blocks)#if
/#else
Full documentation index: docs/README.md
Method | 100 PDFs | Per PDF | Throughput | Use Case |
---|---|---|---|---|
Process-per-PDF | 22,000ms | 220ms | 4.5/sec | Scripts |
Batch Mode | 165ms | 1.65ms | 607/sec | Production |
Speedup | 134x | 134x | 134x |
=== Simple Documents ===
Batch Mode (100 PDFs): 165ms
Average per PDF: 1.65ms
Throughput: 607 PDFs/sec
=== Large Tables (500 rows) ===
Per PDF: 4.5ms
Throughput: 220 PDFs/sec
echo '{"fields":{"title":"My Doc"}}' | zigpdf --generate-pdf template.bin - output.pdf
# Generate NDJSON (one JSON per line)
cat > batch.ndjson <<'EOF'
{"data":{"fields":{"title":"Report 1"}},"output":"report1.pdf"}
{"data":{"fields":{"title":"Report 2"}},"output":"report2.pdf"}
EOF
# Process all PDFs in one process
zigpdf --batch-mode template.bin < batch.ndjson
Python:
import json
import subprocess
proc = subprocess.Popen(['zigpdf', '--batch-mode', 'template.bin'],
stdin=subprocess.PIPE, text=True)
for i in range(100):
req = {"data": {"fields": {"title": f"Doc {i}"}}, "output": f"doc{i}.pdf"}
proc.stdin.write(json.dumps(req) + '\n')
proc.stdin.close()
proc.wait()
Go:
cmd := exec.Command("zigpdf", "--batch-mode", "template.bin")
stdin, _ := cmd.StdinPipe()
cmd.Start()
encoder := json.NewEncoder(stdin)
for _, req := range requests {
encoder.Encode(req)
}
stdin.Close()
cmd.Wait()
Node.js:
const zigpdf = spawn('zigpdf', ['--batch-mode', 'template.bin']);
for (const req of requests) {
zigpdf.stdin.write(JSON.stringify(req) + '\n');
}
zigpdf.stdin.end();
#page(width: 595, height: 842, margin: 40)
#font(helvetica-bold, helvetica)
# Elements flow top-to-bottom automatically
#text("{{title}}", font: 0, size: 18, margin-bottom: 10)
#text("{{subtitle}}", font: 1, size: 12, margin-bottom: 20)
#line(width: 1.5, margin-bottom: 15)
#text("Total: ${{amount}}", font: 0, size: 16)
#if(payment_status == "paid") {
#text("β PAID", x: 350, y: 645, font: 0, size: 11)
} else {
#text("β OVERDUE", x: 350, y: 645, font: 0, size: 11)
}
#if(invoice_total > "10000") {
#text("β PRIORITY ACCOUNT", x: 40, y: 384, font: 0, size: 9)
}
Operators: ==
, !=
, >
, <
, >=
, <=
Performance: <0.03ms per condition
#table(
data: "items",
x: 50, y: 700,
columns: [
(width: 200, align: left),
(width: 100, align: right)
],
headers: ["Description", "Amount"],
font: 1, size: 10
)
Tables automatically split across pages!
zig/
βββ src/
β βββ pdf/
β β βββ writer.zig # PDF 1.4 object generation
β β βββ content.zig # Drawing primitives
β β βββ font.zig # Font handling
β β βββ paginate.zig # Table pagination
β β βββ template.zig # Binary template format
β βββ pdf_lib.zig # Main library entry
βββ docs/
β βββ tutorial/ # PDM syntax tutorials
β βββ features/ # Feature documentation
β βββ performance/ # Benchmark reports
β βββ implementation/ # Technical details
βββ examples/ # Usage examples
βββ templates/ # Binary templates
Magic: TPDF (0x54504446)
Version: 1
Page Config: width, height, margins
Fonts: [font_type, ...]
Fields: [key, x, y, font_index, size, ...]
Tables: columns, headers, style
Static Content: precompiled PDF streams
Benefits: Fast loading (~0.1ms), reusable, versioned, compact (1-10KB)
zig build
zig build -Doptimize=ReleaseFast
zig build run # Single PDF example
zig build gen1000 # 1000 PDFs benchmark
zig build template # Template builder
# Compile template
zigpdf --markup-to-template <input.pdm> <output.bin>
# Generate single PDF
zigpdf --generate-pdf <template.bin> <data.json|-> <output.pdf>
# Batch mode (fastest)
zigpdf --batch-mode <template.bin> < input.ndjson
# Help
zigpdf --help
IMPORTANT: Fields must be nested under "fields"
key!
β Correct:
{
"fields": {
"title": "Invoice #001",
"date": "2024-10-10",
"items": [
["Item", "Price"],
["Service", "$100"]
]
}
}
β Wrong (will create blank PDF):
{
"title": "Invoice #001",
"date": "2024-10-10"
}
#if
/#else
)
Content stream compression (~40% size reduction)
TrueType/OpenType fonts
Additional image formats (JPEG, WebP)
PDF/A compliance
Digital signatures
Parallel batch mode
Visual template editor
ZigPDF Non-Commercial License
See LICENSE for complete terms.
Built with Zig - a general-purpose programming language for maintaining robust, optimal, and reusable software.
Why Zig?
Made with β‘ by the ZigPDF Team