- Renamed all references from zpdf to zcatpdf
- Module import: @import("zcatpdf")
- Consistent with zcatui, zcatgui naming convention
- All lowercase per Zig standards
Note: Directory rename (zpdf -> zcatpdf) and Forgejo repo rename
should be done manually after this commit.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
937 lines
21 KiB
Markdown
937 lines
21 KiB
Markdown
# zcatpdf - PDF Generation Library for Zig
|
|
|
|
A pure Zig library for creating PDF documents with minimal dependencies.
|
|
|
|
```zig
|
|
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`:
|
|
|
|
```zig
|
|
.dependencies = .{
|
|
.zcatpdf = .{
|
|
.url = "https://git.reugenio.com/reugenio/zcatpdf/archive/v1.0.tar.gz",
|
|
.hash = "...",
|
|
},
|
|
},
|
|
```
|
|
|
|
In your `build.zig`:
|
|
|
|
```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](#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 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`
|
|
|
|
```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 = 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)
|
|
|
|
```zig
|
|
// 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`
|
|
|
|
```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
|
|
|
|
```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 = 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
|
|
|
|
```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
|
|
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`
|
|
|
|
```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,
|
|
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
|
|
|
|
```zig
|
|
// 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.
|
|
|
|
```zig
|
|
// 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.
|
|
|
|
```zig
|
|
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`
|
|
|
|
```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
|
|
|
|
```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)
|