zcatpdf/examples/template_demo.zig
reugenio 3826cbaed4 Release v1.0 - Feature Complete PDF Generation Library
Major features added since v0.5:
- PNG support with alpha/transparency (soft masks)
- FlateDecode compression via libdeflate-zig
- Bookmarks/Outline for document navigation
- Bezier curves, circles, ellipses, arcs
- Transformations (rotate, scale, translate, skew)
- Transparency/opacity (fill and stroke alpha)
- Linear and radial gradients (Shading Patterns)
- Code128 (1D) and QR Code (2D) barcodes
- TrueType font parsing (metrics, glyph widths)
- RC4 encryption module (40/128-bit)
- AcroForms module (TextField, CheckBox)
- SVG import (basic shapes and paths)
- Template system (reusable layouts)
- Markdown styling (bold, italic, links, headings, lists)

Documentation:
- README.md: Complete API reference with code examples
- FUTURE_IMPROVEMENTS.md: Detailed roadmap for future development
- CLAUDE.md: Updated to v1.0 release status

Stats:
- 125+ unit tests passing
- 16 demo examples
- 46 source files

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 02:01:17 +01:00

225 lines
9.3 KiB
Zig

//! Template Demo - Using predefined document templates
//!
//! Run with: zig build template_demo && ./zig-out/bin/template_demo
const std = @import("std");
const zpdf = @import("zpdf");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("=== zpdf Template Demo ===\n\n", .{});
// Create invoice using template
try createInvoiceFromTemplate(allocator);
// Create letter using template
try createLetterFromTemplate(allocator);
std.debug.print("\nTemplate demo completed successfully!\n", .{});
}
fn createInvoiceFromTemplate(allocator: std.mem.Allocator) !void {
std.debug.print("Creating invoice from template...\n", .{});
// Get the invoice template
var tmpl = try zpdf.Template.invoiceTemplate(allocator);
defer tmpl.deinit();
std.debug.print(" Template: {s}\n", .{tmpl.name});
std.debug.print(" Page size: {d:.0} x {d:.0} points\n", .{ tmpl.page_width, tmpl.page_height });
// Create PDF based on template
var pdf = zpdf.Pdf.init(allocator, .{});
defer pdf.deinit();
pdf.setTitle("Invoice from Template");
var page = try pdf.addPageCustom(tmpl.page_width, tmpl.page_height);
// Use template regions to position content
if (tmpl.getRegion("header")) |region| {
std.debug.print(" Header region: ({d:.0}, {d:.0}) {d:.0}x{d:.0}\n", .{ region.x, region.y, region.width, region.height });
try page.setFont(.helvetica_bold, 20);
try page.drawText(region.x, region.y, "ACME Corporation");
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y - 15, "123 Business Street");
try page.drawText(region.x, region.y - 27, "Tech City, TC 12345");
}
if (tmpl.getRegion("invoice_info")) |region| {
std.debug.print(" Invoice info region: ({d:.0}, {d:.0})\n", .{ region.x, region.y });
try page.setFont(.helvetica_bold, 14);
try page.drawText(region.x, region.y, "INVOICE #2024-001");
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y - 15, "Date: December 9, 2024");
try page.drawText(region.x, region.y - 27, "Due: December 23, 2024");
}
if (tmpl.getRegion("customer")) |region| {
std.debug.print(" Customer region: ({d:.0}, {d:.0})\n", .{ region.x, region.y });
try page.setFont(.helvetica_bold, 12);
try page.drawText(region.x, region.y, "Bill To:");
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y - 15, "Customer Company Ltd.");
try page.drawText(region.x, region.y - 27, "456 Client Avenue");
try page.drawText(region.x, region.y - 39, "Business Town, BT 67890");
}
if (tmpl.getRegion("items")) |region| {
std.debug.print(" Items region: ({d:.0}, {d:.0}) {d:.0}x{d:.0}\n", .{ region.x, region.y, region.width, region.height });
// Draw table header
page.setFillColor(zpdf.Color.hex(0xE0E0E0));
try page.fillRect(region.x, region.y + region.height - 25, region.width, 25);
page.setFillColor(zpdf.Color.black);
try page.setFont(.helvetica_bold, 10);
try page.drawText(region.x + 5, region.y + region.height - 17, "Description");
try page.drawText(region.x + 250, region.y + region.height - 17, "Qty");
try page.drawText(region.x + 320, region.y + region.height - 17, "Price");
try page.drawText(region.x + 420, region.y + region.height - 17, "Total");
// Draw table rows
try page.setFont(.helvetica, 10);
const items = [_]struct { desc: []const u8, qty: []const u8, price: []const u8, total: []const u8 }{
.{ .desc = "Web Development Services", .qty = "40", .price = "$75.00", .total = "$3,000.00" },
.{ .desc = "UI/UX Design", .qty = "20", .price = "$85.00", .total = "$1,700.00" },
.{ .desc = "Server Hosting (1 year)", .qty = "1", .price = "$500.00", .total = "$500.00" },
};
var y_offset: f32 = region.y + region.height - 45;
for (items) |item| {
try page.drawText(region.x + 5, y_offset, item.desc);
try page.drawText(region.x + 250, y_offset, item.qty);
try page.drawText(region.x + 320, y_offset, item.price);
try page.drawText(region.x + 420, y_offset, item.total);
y_offset -= 20;
}
// Draw table border
page.setStrokeColor(zpdf.Color.black);
try page.drawRect(region.x, region.y, region.width, region.height);
}
if (tmpl.getRegion("totals")) |region| {
std.debug.print(" Totals region: ({d:.0}, {d:.0})\n", .{ region.x, region.y });
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y + 60, "Subtotal:");
try page.drawText(region.x + 100, region.y + 60, "$5,200.00");
try page.drawText(region.x, region.y + 45, "Tax (10%):");
try page.drawText(region.x + 100, region.y + 45, "$520.00");
try page.setLineWidth(1);
try page.drawLine(region.x, region.y + 35, region.x + region.width, region.y + 35);
try page.setFont(.helvetica_bold, 12);
try page.drawText(region.x, region.y + 20, "TOTAL:");
try page.drawText(region.x + 100, region.y + 20, "$5,720.00");
}
if (tmpl.getRegion("footer")) |region| {
std.debug.print(" Footer region: ({d:.0}, {d:.0})\n", .{ region.x, region.y });
try page.setFont(.helvetica, 8);
page.setFillColor(zpdf.Color.hex(0x666666));
try page.drawText(region.x, region.y + 20, "Payment Terms: Net 14 days");
try page.drawText(region.x, region.y + 8, "Thank you for your business!");
}
try pdf.save("template_invoice.pdf");
std.debug.print(" Saved: template_invoice.pdf\n", .{});
}
fn createLetterFromTemplate(allocator: std.mem.Allocator) !void {
std.debug.print("\nCreating letter from template...\n", .{});
// Get the letter template
var tmpl = try zpdf.Template.letterTemplate(allocator);
defer tmpl.deinit();
std.debug.print(" Template: {s}\n", .{tmpl.name});
// Create PDF based on template
var pdf = zpdf.Pdf.init(allocator, .{});
defer pdf.deinit();
pdf.setTitle("Letter from Template");
var page = try pdf.addPageCustom(tmpl.page_width, tmpl.page_height);
// Sender
if (tmpl.getRegion("sender")) |region| {
try page.setFont(.helvetica_bold, 11);
try page.drawText(region.x, region.y, "John Smith");
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y - 14, "123 Sender Street");
try page.drawText(region.x, region.y - 26, "City, ST 12345");
try page.drawText(region.x, region.y - 38, "john@example.com");
}
// Date
if (tmpl.getRegion("date")) |region| {
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y, "December 9, 2024");
}
// Recipient
if (tmpl.getRegion("recipient")) |region| {
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y, "Ms. Jane Doe");
try page.drawText(region.x, region.y - 14, "456 Recipient Avenue");
try page.drawText(region.x, region.y - 26, "Town, ST 67890");
}
// Subject
if (tmpl.getRegion("subject")) |region| {
try page.setFont(.helvetica_bold, 11);
try page.drawText(region.x, region.y, "Re: Project Proposal Discussion");
}
// Body
if (tmpl.getRegion("body")) |region| {
try page.setFont(.helvetica, 10);
const line_height: f32 = 14;
var y = region.y + region.height;
try page.drawText(region.x, y, "Dear Ms. Doe,");
y -= line_height * 2;
try page.drawText(region.x, y, "I am writing to follow up on our recent conversation regarding the");
y -= line_height;
try page.drawText(region.x, y, "proposed collaboration between our organizations. I believe there is");
y -= line_height;
try page.drawText(region.x, y, "significant potential for a mutually beneficial partnership.");
y -= line_height * 2;
try page.drawText(region.x, y, "As discussed, I have prepared a detailed proposal outlining the scope");
y -= line_height;
try page.drawText(region.x, y, "of work, timeline, and expected outcomes. I would be happy to schedule");
y -= line_height;
try page.drawText(region.x, y, "a meeting at your earliest convenience to discuss this further.");
y -= line_height * 2;
try page.drawText(region.x, y, "Please do not hesitate to contact me if you have any questions or");
y -= line_height;
try page.drawText(region.x, y, "require additional information.");
y -= line_height * 2;
try page.drawText(region.x, y, "Thank you for your time and consideration.");
}
// Signature
if (tmpl.getRegion("signature")) |region| {
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y + 50, "Sincerely,");
try page.setFont(.helvetica_bold, 10);
try page.drawText(region.x, region.y + 20, "John Smith");
try page.setFont(.helvetica, 10);
try page.drawText(region.x, region.y + 6, "Senior Consultant");
}
try pdf.save("template_letter.pdf");
std.debug.print(" Saved: template_letter.pdf\n", .{});
}