# zpdf - PDF Generation Library for Zig A pure Zig library for creating PDF documents with minimal dependencies. ```zig const zpdf = @import("zpdf"); pub fn main() !void { var pdf = zpdf.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 zpdf to your `build.zig.zon`: ```zig .dependencies = .{ .zpdf = .{ .url = "https://git.reugenio.com/reugenio/zpdf/archive/v1.0.tar.gz", .hash = "...", }, }, ``` In your `build.zig`: ```zig const zpdf_dep = b.dependency("zpdf", .{ .target = target, .optimize = optimize, }); exe.root_module.addImport("zpdf", zpdf_dep.module("zpdf")); ``` ## Quick Reference ### Table of Contents 1. [Document Creation](#1-document-creation) 2. [Pages](#2-pages) 3. [Text](#3-text) 4. [Fonts](#4-fonts) 5. [Colors](#5-colors) 6. [Graphics](#6-graphics) 7. [Images](#7-images) 8. [Tables](#8-tables) 9. [Links](#9-links) 10. [Bookmarks](#10-bookmarks) 11. [Barcodes](#11-barcodes) 12. [Transformations](#12-transformations) 13. [Transparency](#13-transparency) 14. [Gradients](#14-gradients) 15. [Templates](#15-templates) 16. [Markdown](#16-markdown) 17. [Compression](#17-compression) --- ## 1. Document Creation **File:** `src/pdf.zig` ```zig const zpdf = @import("zpdf"); // Create document with default settings var pdf = zpdf.Pdf.init(allocator, .{}); defer pdf.deinit(); // Create document with options var pdf = zpdf.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` ```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` ```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 ```zig 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 ```zig 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 ```zig .left .center .right ``` --- ## 4. Fonts **File:** `src/fonts/type1.zig`, `src/fonts/ttf.zig` ```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 = zpdf.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) ```zig // Load TTF file const font_data = try std.fs.cwd().readFileAlloc(allocator, "font.ttf", 10_000_000); var ttf = try zpdf.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` ```zig // Set colors page.setFillColor(zpdf.Color.red); page.setStrokeColor(zpdf.Color.blue); // RGB (0-255) page.setFillColor(zpdf.Color.rgb(255, 128, 0)); // Hex page.setFillColor(zpdf.Color.hex(0xFF8000)); // Grayscale (0.0-1.0) page.setFillColor(zpdf.Color.gray(0.5)); // CMYK (0.0-1.0) page.setFillColor(zpdf.Color.cmyk(0, 1, 1, 0)); // Red ``` ### Predefined Colors ```zig 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 ```zig try page.setLineWidth(2.0); try page.drawLine(x1, y1, x2, y2); ``` ### Rectangles ```zig // 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 ```zig // 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 ```zig // 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 ```zig 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` ```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` ```zig const col_widths = [_]f32{ 200, 100, 100, 100 }; var table = zpdf.Table.init(page, .{ .x = 50, .y = 700, .col_widths = &col_widths, .row_height = 20, .header_bg_color = zpdf.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 ```zig 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 | --- ## 9. Links **File:** `src/links.zig`, `src/page.zig` ```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` ```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) ```zig // 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) ```zig try page.drawQRCode(x, y, "https://example.com", size, error_correction); // Error correction levels zpdf.QRCode.ErrorCorrection.L // 7% recovery zpdf.QRCode.ErrorCorrection.M // 15% recovery zpdf.QRCode.ErrorCorrection.Q // 25% recovery zpdf.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` ```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` ```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 ```zig // Horizontal gradient try page.linearGradientRect(x, y, width, height, zpdf.Color.red, zpdf.Color.blue, .horizontal); // Vertical gradient try page.linearGradientRect(x, y, width, height, zpdf.Color.green, zpdf.Color.yellow, .vertical); // Diagonal gradient try page.linearGradientRect(x, y, width, height, zpdf.Color.purple, zpdf.Color.cyan, .diagonal); ``` ### Radial Gradients ```zig // Circle gradient (center to edge) try page.radialGradientCircle(cx, cy, radius, zpdf.Color.white, zpdf.Color.blue); // Ellipse gradient try page.radialGradientEllipse(cx, cy, rx, ry, zpdf.Color.yellow, zpdf.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. ```zig // Use predefined invoice template var tmpl = try zpdf.Template.invoiceTemplate(allocator); defer tmpl.deinit(); // Or create custom template var tmpl = zpdf.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. ```zig var renderer = zpdf.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 = zpdf.MarkdownRenderer.fontForStyle(span.style); try page.setFont(font, span.font_size orelse 12); if (span.color) |color| { page.setFillColor(zpdf.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` ```zig // Configure compression when creating document var pdf = zpdf.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 ```bash # Build all zig build # Run specific example ./zig-out/bin/hello ./zig-out/bin/invoice ./zig-out/bin/barcode_demo # etc. ``` --- ## Building ```bash # 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)