PDF generation library for Zig - pure Zig, zero dependencies
Find a file
R.Eugenio ae11220ee8 Estandarizar: CLAUDE.md → claude.md + refs CREDENCIALES
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 15:13:50 +01:00
.claude/commands Actualizar /init para leer credenciales e infraestructura 2026-01-07 00:40:20 +01:00
docs feat: v0.2 - Complete text system (cell, multiCell, alignment) 2025-12-08 19:46:30 +01:00
examples refactor: Rename zpdf to zcatpdf for consistency with zcat* family 2025-12-09 02:10:57 +01:00
src refactor: Rename zpdf to zcatpdf for consistency with zcat* family 2025-12-09 02:10:57 +01:00
.gitignore Añadir /init optimizado (lee NORMAS_ESENCIALES + teamdocs) 2025-12-23 13:28:54 +01:00
build.zig refactor: Rename zpdf to zcatpdf for consistency with zcat* family 2025-12-09 02:10:57 +01:00
build.zig.zon Release v1.0 - Feature Complete PDF Generation Library 2025-12-09 02:01:17 +01:00
claude.md Estandarizar: CLAUDE.md → claude.md + refs CREDENCIALES 2026-01-11 15:13:50 +01:00
FUTURE_IMPROVEMENTS.md refactor: Rename zpdf to zcatpdf for consistency with zcat* family 2025-12-09 02:10:57 +01:00
IMPLEMENTATION_PLAN.md refactor: Rename zpdf to zcatpdf for consistency with zcat* family 2025-12-09 02:10:57 +01:00
README.md docs: Add Known Limitations section (TTF subsetting) 2025-12-14 19:41:31 +01:00
VERIFIED_FEATURES.md docs: Add VERIFIED_FEATURES.md - tracking production-tested features 2025-12-10 12:00:55 +01:00
ZIG_VERSION_NOTES.md docs: Renombrar TEAM_STANDARDS a teamdocs 2025-12-11 19:33:44 +01:00

zcatpdf - PDF Generation Library for Zig

A pure Zig library for creating PDF documents with minimal dependencies.

const zcatpdf = @import("zcatpdf");

pub fn main() !void {
    var pdf = zcatpdf.Pdf.init(allocator, .{});
    defer pdf.deinit();

    var page = try pdf.addPage(.{});
    try page.setFont(.helvetica_bold, 24);
    try page.drawText(50, 750, "Hello, PDF!");

    try pdf.save("hello.pdf");
}

Features

  • Pure Zig - Minimal dependencies (only libdeflate for compression)
  • PDF 1.4 - Compatible with all PDF readers
  • Complete text system - Fonts, alignment, word wrap, cells
  • Images - JPEG and PNG (with alpha/transparency)
  • Vector graphics - Lines, curves, shapes, gradients
  • Tables - Helper for formatted tables
  • Barcodes - Code128 (1D) and QR Code (2D)
  • Links - Clickable URLs and internal page links
  • Bookmarks - Document outline/navigation
  • Transformations - Rotate, scale, translate, skew
  • Transparency - Fill and stroke opacity
  • Templates - Reusable document layouts
  • Markdown - Styled text with Markdown syntax

Installation

Add zcatpdf to your build.zig.zon:

.dependencies = .{
    .zcatpdf = .{
        .url = "https://git.reugenio.com/reugenio/zcatpdf/archive/v1.0.tar.gz",
        .hash = "...",
    },
},

In your build.zig:

const zcatpdf_dep = b.dependency("zcatpdf", .{
    .target = target,
    .optimize = optimize,
});
exe.root_module.addImport("zcatpdf", zcatpdf_dep.module("zcatpdf"));

Quick Reference

Table of Contents

  1. Document Creation
  2. Pages
  3. Text
  4. Fonts
  5. Colors
  6. Graphics
  7. Images
  8. Tables
  9. Links
  10. Bookmarks
  11. Barcodes
  12. Transformations
  13. Transparency
  14. Gradients
  15. Templates
  16. Markdown
  17. Compression

1. Document Creation

File: src/pdf.zig

const zcatpdf = @import("zcatpdf");

// Create document with default settings
var pdf = zcatpdf.Pdf.init(allocator, .{});
defer pdf.deinit();

// Create document with options
var pdf = zcatpdf.Pdf.init(allocator, .{
    .page_size = .a4,
    .orientation = .portrait,
    .unit = .pt,
});

// Set metadata
pdf.setTitle("Document Title");
pdf.setAuthor("Author Name");
pdf.setSubject("Subject");
pdf.setKeywords("keyword1, keyword2");
pdf.setCreator("Application Name");

// Save to file
try pdf.save("output.pdf");

// Or get as bytes
const data = try pdf.output();
defer allocator.free(data);

Types

Type File Description
Pdf src/pdf.zig Main document struct
Config src/pdf.zig Document configuration

2. Pages

File: src/page.zig, src/objects/base.zig

// Add page with document defaults
var page = try pdf.addPage(.{});

// Add page with specific size
var page = try pdf.addPage(.{ .size = .letter });

// Add page with custom dimensions (points)
var page = try pdf.addPageCustom(612, 792);

// Page sizes available
.a3      // 842 x 1191 pt
.a4      // 595 x 842 pt
.a5      // 420 x 595 pt
.letter  // 612 x 792 pt
.legal   // 612 x 1008 pt

// Orientations
.portrait
.landscape

Types

Type File Description
Page src/page.zig Page struct with drawing methods
PageSize src/objects/base.zig Standard page sizes
Orientation src/objects/base.zig Portrait/Landscape

3. Text

File: src/page.zig

// Simple text at position
try page.drawText(x, y, "Hello World");

// Cell with border and background
try page.cell(width, height, "Text", Border.all, .center, true);

// Multi-line text with word wrap
try page.multiCell(width, line_height, long_text, Border.none, .left, false);

// Get/set cursor position
const x = page.getX();
const y = page.getY();
page.setXY(100, 500);

// Line break
page.ln(20); // Move down 20 points

Cell Parameters

try page.cell(
    width,      // f32 - Cell width
    height,     // f32 - Cell height
    text,       // []const u8 - Text content
    border,     // Border - Border style
    align,      // Align - Text alignment
    fill,       // bool - Fill background
);

Border Options

Border.none    // No border
Border.all     // All sides
Border.left    // Left only
Border.right   // Right only
Border.top     // Top only
Border.bottom  // Bottom only
// Combine with Border.combine()

Alignment

.left
.center
.right

4. Fonts

File: src/fonts/type1.zig, src/fonts/ttf.zig

// Set font
try page.setFont(.helvetica, 12);
try page.setFont(.helvetica_bold, 14);
try page.setFont(.times_roman, 11);
try page.setFont(.courier, 10);

// Calculate string width
const width = zcatpdf.Font.helvetica.stringWidth("Hello", 12.0);

Available Fonts (Type1 built-in)

Font Constant
Helvetica .helvetica
Helvetica Bold .helvetica_bold
Helvetica Oblique .helvetica_oblique
Helvetica Bold Oblique .helvetica_bold_oblique
Times Roman .times_roman
Times Bold .times_bold
Times Italic .times_italic
Times Bold Italic .times_bold_italic
Courier .courier
Courier Bold .courier_bold
Courier Oblique .courier_oblique
Courier Bold Oblique .courier_bold_oblique
Symbol .symbol
ZapfDingbats .zapf_dingbats

TrueType Fonts (parsing only)

// Load TTF file
const font_data = try std.fs.cwd().readFileAlloc(allocator, "font.ttf", 10_000_000);
var ttf = try zcatpdf.TrueTypeFont.parse(allocator, font_data);
defer ttf.deinit();

// Get font info
std.debug.print("Family: {s}\n", .{ttf.family_name});
std.debug.print("Ascender: {d}\n", .{ttf.ascender});

// Calculate string width
const width = ttf.stringWidth("Hello", 12.0);

Types

Type File Description
Font src/fonts/type1.zig Type1 font enum
TrueTypeFont src/fonts/ttf.zig TTF parser

5. Colors

File: src/graphics/color.zig

// Set colors
page.setFillColor(zcatpdf.Color.red);
page.setStrokeColor(zcatpdf.Color.blue);

// RGB (0-255)
page.setFillColor(zcatpdf.Color.rgb(255, 128, 0));

// Hex
page.setFillColor(zcatpdf.Color.hex(0xFF8000));

// Grayscale (0.0-1.0)
page.setFillColor(zcatpdf.Color.gray(0.5));

// CMYK (0.0-1.0)
page.setFillColor(zcatpdf.Color.cmyk(0, 1, 1, 0)); // Red

Predefined Colors

Color.black
Color.white
Color.red
Color.green
Color.blue
Color.yellow
Color.cyan
Color.magenta
Color.orange
Color.purple
Color.pink
Color.brown
Color.gray
Color.light_gray
Color.dark_gray

Types

Type File Description
Color src/graphics/color.zig Color struct (RGB, CMYK, Gray)

6. Graphics

File: src/page.zig, src/content_stream.zig

Lines

try page.setLineWidth(2.0);
try page.drawLine(x1, y1, x2, y2);

Rectangles

// Stroke only
try page.drawRect(x, y, width, height);

// Fill only
try page.fillRect(x, y, width, height);

// Fill and stroke
try page.fillAndStrokeRect(x, y, width, height);

Circles and Ellipses

// Circle
try page.drawCircle(cx, cy, radius);
try page.fillCircle(cx, cy, radius);

// Ellipse
try page.drawEllipse(cx, cy, rx, ry);
try page.fillEllipse(cx, cy, rx, ry);

// Arc
try page.drawArc(cx, cy, rx, ry, start_angle, end_angle);

Bezier Curves

// Cubic Bezier
try page.drawBezier(x0, y0, x1, y1, x2, y2, x3, y3);

// Quadratic Bezier
try page.drawQuadBezier(x0, y0, x1, y1, x2, y2);

Line Style

try page.setLineWidth(2.0);
try page.setLineCap(.round);   // .butt, .round, .square
try page.setLineJoin(.round);  // .miter, .round, .bevel
try page.setDashPattern(&.{5, 3}, 0); // [dash, gap], phase

Types

Type File Description
ContentStream src/content_stream.zig Low-level PDF operators
LineCap src/content_stream.zig Line cap styles
LineJoin src/content_stream.zig Line join styles

7. Images

File: src/images/jpeg.zig, src/images/png.zig, src/images/image_info.zig

// Load JPEG
const jpeg_idx = try pdf.addJpegImageFromFile("photo.jpg");

// Load PNG
const png_idx = try pdf.addPngImageFromFile("logo.png");

// Load from memory
const img_idx = try pdf.addJpegImage(jpeg_bytes);
const img_idx = try pdf.addPngImage(png_bytes);

// Get image info
const info = pdf.getImage(img_idx).?;
std.debug.print("Size: {d}x{d}\n", .{info.width, info.height});

// Draw image at position with size
try page.image(img_idx, info, x, y, width, height);

// Draw image preserving aspect ratio
try page.imageFit(img_idx, info, x, y, max_width, max_height);

Supported Formats

Format Features
JPEG RGB, Grayscale
PNG RGB, RGBA (with alpha), Grayscale, Indexed

Types

Type File Description
ImageInfo src/images/image_info.zig Image metadata
ImageFormat src/images/image_info.zig JPEG, PNG enum

8. Tables

File: src/table.zig

const col_widths = [_]f32{ 200, 100, 100, 100 };

var table = zcatpdf.Table.init(page, .{
    .x = 50,
    .y = 700,
    .col_widths = &col_widths,
    .row_height = 20,
    .header_bg_color = zcatpdf.Color.hex(0xE0E0E0),
    .border = true,
});

// Header row
try table.header(&.{ "Description", "Qty", "Price", "Total" });

// Data rows
try table.row(&.{ "Product A", "2", "$10.00", "$20.00" });
try table.row(&.{ "Product B", "1", "$25.00", "$25.00" });

// Footer row
try table.footer(&.{ "", "", "Total:", "$45.00" });

Table Options

TableOptions{
    .x = 50,                           // X position
    .y = 700,                          // Y position
    .col_widths = &widths,             // Column widths array
    .row_height = 20,                  // Row height
    .header_bg_color = Color.gray,     // Header background
    .row_bg_color = null,              // Row background
    .alt_row_bg_color = null,          // Alternating row background
    .border = true,                    // Draw borders
    .header_font = .helvetica_bold,    // Header font
    .body_font = .helvetica,           // Body font
    .font_size = 10,                   // Font size
}

Types

Type File Description
Table src/table.zig Table helper
TableOptions src/table.zig Table configuration

File: src/links.zig, src/page.zig

// URL link with visual styling (blue + underline)
_ = try page.urlLink(x, y, "Click here", "https://example.com");

// URL link from current position
_ = try page.writeUrlLink("Visit website", "https://example.com");

// Internal link (jump to page)
try page.addInternalLink(target_page, x, y, width, height);

// URL link without visual (just annotation)
try page.addUrlLink("https://example.com", x, y, width, height);

Types

Type File Description
Link src/links.zig Link struct
PageLinks src/links.zig Page link collection

10. Bookmarks

File: src/outline.zig

// Add bookmark to page
try pdf.addBookmark("Chapter 1", 0);  // page index 0

// Add bookmark with Y position
try pdf.addBookmarkAt("Section 1.1", 0, 500);

Bookmarks appear in the PDF reader's sidebar for navigation.

Types

Type File Description
Outline src/outline.zig Document outline
OutlineItem src/outline.zig Single bookmark

11. Barcodes

File: src/barcodes/code128.zig, src/barcodes/qr.zig

Code128 (1D)

// Basic barcode
try page.drawCode128(x, y, "ABC-12345", height, module_width);

// Barcode with text below
try page.drawCode128WithText(x, y, "ABC-12345", height, module_width, show_text);

QR Code (2D)

try page.drawQRCode(x, y, "https://example.com", size, error_correction);

// Error correction levels
zcatpdf.QRCode.ErrorCorrection.L  // 7% recovery
zcatpdf.QRCode.ErrorCorrection.M  // 15% recovery
zcatpdf.QRCode.ErrorCorrection.Q  // 25% recovery
zcatpdf.QRCode.ErrorCorrection.H  // 30% recovery

Types

Type File Description
Code128 src/barcodes/code128.zig Code128 encoder
QRCode src/barcodes/qr.zig QR Code encoder

12. Transformations

File: src/page.zig

// Save state before transforming
try page.saveState();

// Rotate around point (degrees)
try page.rotate(45, center_x, center_y);

// Scale from point
try page.scale(2.0, 1.5, origin_x, origin_y);

// Translate
try page.translate(100, 50);

// Skew (degrees)
try page.skew(15, 0);  // X skew
try page.skew(0, 10);  // Y skew

// Custom transformation matrix
try page.transform(a, b, c, d, e, f);

// Restore state
try page.restoreState();

Important: Always use saveState()/restoreState() to limit transformation scope.


13. Transparency

File: src/graphics/extgstate.zig, src/page.zig

// Set fill opacity (0.0 = transparent, 1.0 = opaque)
try page.setFillOpacity(0.5);

// Set stroke opacity
try page.setStrokeOpacity(0.75);

// Set both at once
try page.setOpacity(0.3);

// Reset to fully opaque
try page.setOpacity(1.0);

Types

Type File Description
ExtGState src/graphics/extgstate.zig Extended graphics state

14. Gradients

File: src/graphics/gradient.zig, src/page.zig

Linear Gradients

// Horizontal gradient
try page.linearGradientRect(x, y, width, height,
    zcatpdf.Color.red, zcatpdf.Color.blue, .horizontal);

// Vertical gradient
try page.linearGradientRect(x, y, width, height,
    zcatpdf.Color.green, zcatpdf.Color.yellow, .vertical);

// Diagonal gradient
try page.linearGradientRect(x, y, width, height,
    zcatpdf.Color.purple, zcatpdf.Color.cyan, .diagonal);

Radial Gradients

// Circle gradient (center to edge)
try page.radialGradientCircle(cx, cy, radius,
    zcatpdf.Color.white, zcatpdf.Color.blue);

// Ellipse gradient
try page.radialGradientEllipse(cx, cy, rx, ry,
    zcatpdf.Color.yellow, zcatpdf.Color.red);

Types

Type File Description
Gradient src/graphics/gradient.zig Gradient definitions
LinearGradient src/graphics/gradient.zig Linear gradient
RadialGradient src/graphics/gradient.zig Radial gradient
GradientDirection src/page.zig horizontal, vertical, diagonal

15. Templates

File: src/template/template.zig

Templates define reusable document layouts with named regions.

// Use predefined invoice template
var tmpl = try zcatpdf.Template.invoiceTemplate(allocator);
defer tmpl.deinit();

// Or create custom template
var tmpl = zcatpdf.Template.init(allocator, "custom", 595, 842);
defer tmpl.deinit();

try tmpl.defineRegion("header", .{
    .x = 50,
    .y = 750,
    .width = 495,
    .height = 80,
    .region_type = .text,
});

// Use regions to position content
if (tmpl.getRegion("header")) |region| {
    try page.drawText(region.x, region.y, "Header Content");
}

Predefined Templates

  • Template.invoiceTemplate() - Invoice with header, customer, items, totals, footer
  • Template.letterTemplate() - Letter with sender, recipient, date, subject, body, signature

Types

Type File Description
Template src/template/template.zig Template struct
TemplateRegion src/template/template.zig Region definition
RegionType src/template/template.zig text, image, table, custom
FixedContent src/template/template.zig Repeating content

16. Markdown

File: src/markdown/markdown.zig

Parse Markdown-style text and render with appropriate styles.

var renderer = zcatpdf.MarkdownRenderer.init(allocator);
defer renderer.deinit();

try renderer.parse(
    \\# Heading 1
    \\
    \\This is **bold** and *italic* text.
    \\
    \\- Bullet item
    \\- Another item
    \\
    \\[Link text](https://example.com)
);

// Render to PDF
for (renderer.getLines()) |line| {
    for (line.spans) |span| {
        const font = zcatpdf.MarkdownRenderer.fontForStyle(span.style);
        try page.setFont(font, span.font_size orelse 12);

        if (span.color) |color| {
            page.setFillColor(zcatpdf.Color.hex(color));
        }

        try page.drawText(x, y, span.text);
        x += font.stringWidth(span.text, font_size);
    }
    y -= line_height;
}

Supported Syntax

Syntax Result
**text** or __text__ Bold
*text* or _text_ Italic
***text*** Bold + Italic
~~text~~ Strikethrough
[text](url) Link
# Heading Heading 1
## Heading Heading 2
### Heading Heading 3
- item Bullet list
1. item Numbered list

Types

Type File Description
MarkdownRenderer src/markdown/markdown.zig Parser/renderer
TextSpan src/markdown/markdown.zig Styled text span
SpanStyle src/markdown/markdown.zig Style flags

17. Compression

File: src/compression/zlib.zig, src/output/producer.zig

// Configure compression when creating document
var pdf = zcatpdf.Pdf.init(allocator, .{
    .compression = .{
        .enabled = true,
        .level = 6,        // 0-12, higher = better compression
        .min_size = 256,   // Don't compress streams smaller than this
    },
});

Compression Options

Option Default Description
enabled true Enable FlateDecode compression
level 6 Compression level (0-12)
min_size 256 Minimum stream size to compress

Types

Type File Description
CompressionOptions src/output/producer.zig Compression config

File Structure

src/
├── root.zig              # Public exports
├── pdf.zig               # Pdf document facade
├── page.zig              # Page with drawing methods
├── content_stream.zig    # PDF operators
├── table.zig             # Table helper
├── pagination.zig        # Page numbers, headers, footers
├── links.zig             # Link types
├── outline.zig           # Bookmarks
├── fonts/
│   ├── mod.zig           # Font exports
│   ├── type1.zig         # 14 Type1 fonts + metrics
│   └── ttf.zig           # TrueType parser
├── graphics/
│   ├── mod.zig           # Graphics exports
│   ├── color.zig         # Color types
│   ├── extgstate.zig     # Transparency (ExtGState)
│   └── gradient.zig      # Linear/Radial gradients
├── images/
│   ├── mod.zig           # Image exports
│   ├── image_info.zig    # ImageInfo struct
│   ├── jpeg.zig          # JPEG parser
│   └── png.zig           # PNG parser
├── barcodes/
│   ├── mod.zig           # Barcode exports
│   ├── code128.zig       # Code128 encoder
│   └── qr.zig            # QR Code encoder
├── compression/
│   ├── mod.zig           # Compression exports
│   └── zlib.zig          # libdeflate wrapper
├── objects/
│   ├── mod.zig           # Object exports
│   └── base.zig          # PageSize, Orientation
├── output/
│   ├── mod.zig           # Output exports
│   └── producer.zig      # PDF serialization
├── security/
│   ├── mod.zig           # Security exports
│   ├── rc4.zig           # RC4 cipher
│   └── encryption.zig    # PDF encryption
├── forms/
│   ├── mod.zig           # Forms exports
│   └── field.zig         # TextField, CheckBox
├── svg/
│   ├── mod.zig           # SVG exports
│   └── parser.zig        # SVG parser
├── template/
│   ├── mod.zig           # Template exports
│   └── template.zig      # Template definitions
└── markdown/
    ├── mod.zig           # Markdown exports
    └── markdown.zig      # Markdown parser

Examples

16 example files in examples/:

File Description
hello.zig Minimal PDF
invoice.zig Complete invoice
text_demo.zig Text system (cell, multiCell)
image_demo.zig JPEG and PNG images
table_demo.zig Table helper
pagination_demo.zig Multi-page with page numbers
links_demo.zig Clickable links
bookmarks_demo.zig Document outline
curves_demo.zig Bezier, circles, arcs
transforms_demo.zig Rotate, scale, skew
transparency_demo.zig Opacity/alpha
gradient_demo.zig Linear and radial gradients
barcode_demo.zig Code128 and QR codes
ttf_demo.zig TrueType font parsing
template_demo.zig Document templates
markdown_demo.zig Markdown styled text

Run Examples

# Build all
zig build

# Run specific example
./zig-out/bin/hello
./zig-out/bin/invoice
./zig-out/bin/barcode_demo
# etc.

Known Limitations

  • TTF Font Subsetting: When embedding TrueType fonts, the entire font file is included rather than just the glyphs used. This can result in larger PDF files when using custom fonts. Font subsetting is planned for a future version.

Building

# Build library
zig build

# Run tests
zig build test

# Build specific example
zig build hello

License

MIT


Version

v1.0 - Feature Complete (2025-12-09)