zcatpdf/examples/invoice.zig
reugenio 0e17e8790b Initial commit: zpdf - PDF generation library for Zig
- Pure Zig implementation, zero dependencies
- PDF 1.4 format output
- Standard Type1 fonts (Helvetica, Times, Courier)
- Text rendering with colors
- Graphics primitives (lines, rectangles)
- Hello world and invoice examples

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 16:55:28 +01:00

179 lines
6.3 KiB
Zig

//! Invoice PDF example - Demonstrates a realistic use case
const std = @import("std");
const pdf = @import("zpdf");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
std.debug.print("zpdf - Invoice example\n", .{});
var doc = pdf.Document.init(allocator);
defer doc.deinit();
var page = try doc.addPage(.a4);
// Company header
try page.setFont(.helvetica_bold, 24);
page.setFillColor(pdf.Color{ .r = 41, .g = 98, .b = 255 }); // Blue
try page.drawText(50, 780, "ACME Corporation");
try page.setFont(.helvetica, 10);
page.setFillColor(pdf.Color.gray);
try page.drawText(50, 765, "123 Business Street, City 12345");
try page.drawText(50, 753, "Tel: +34 123 456 789 | Email: info@acme.com");
try page.drawText(50, 741, "CIF: B12345678");
// Invoice title
try page.setFont(.helvetica_bold, 28);
page.setFillColor(pdf.Color.black);
try page.drawText(400, 780, "FACTURA");
try page.setFont(.helvetica, 12);
try page.drawText(400, 760, "No: FAC-2025-0001");
try page.drawText(400, 745, "Fecha: 08/12/2025");
// Separator line
try page.setLineWidth(1);
page.setStrokeColor(pdf.Color.light_gray);
try page.drawLine(50, 720, 545, 720);
// Client info box
page.setFillColor(pdf.Color{ .r = 245, .g = 245, .b = 245 });
try page.fillRect(50, 640, 250, 70);
try page.setFont(.helvetica_bold, 11);
page.setFillColor(pdf.Color.black);
try page.drawText(60, 695, "CLIENTE:");
try page.setFont(.helvetica, 11);
try page.drawText(60, 680, "Empresa Cliente S.L.");
try page.drawText(60, 667, "Calle Principal 45, 2o B");
try page.drawText(60, 654, "08001 Barcelona");
try page.drawText(60, 641, "NIF: B87654321");
// Table header
const table_top: f32 = 610;
const col1: f32 = 50;
const col2: f32 = 300;
const col3: f32 = 370;
const col4: f32 = 430;
const col5: f32 = 490;
const row_height: f32 = 25;
// Header background
page.setFillColor(pdf.Color{ .r = 41, .g = 98, .b = 255 });
try page.fillRect(col1, table_top - row_height, 495, row_height);
// Header text
try page.setFont(.helvetica_bold, 10);
page.setFillColor(pdf.Color.white);
try page.drawText(col1 + 5, table_top - 18, "DESCRIPCION");
try page.drawText(col2 + 5, table_top - 18, "CANT.");
try page.drawText(col3 + 5, table_top - 18, "PRECIO");
try page.drawText(col4 + 5, table_top - 18, "IVA");
try page.drawText(col5 + 5, table_top - 18, "TOTAL");
// Table rows
const items = [_]struct { desc: []const u8, qty: []const u8, price: []const u8, vat: []const u8, total: []const u8 }{
.{ .desc = "Servicio de consultoria", .qty = "10h", .price = "50.00", .vat = "21%", .total = "605.00" },
.{ .desc = "Desarrollo web", .qty = "1", .price = "1500.00", .vat = "21%", .total = "1815.00" },
.{ .desc = "Mantenimiento mensual", .qty = "1", .price = "200.00", .vat = "21%", .total = "242.00" },
.{ .desc = "Hosting anual", .qty = "1", .price = "120.00", .vat = "21%", .total = "145.20" },
};
try page.setFont(.helvetica, 10);
page.setFillColor(pdf.Color.black);
var y = table_top - row_height;
for (items, 0..) |item, i| {
y -= row_height;
// Alternate row background
if (i % 2 == 0) {
page.setFillColor(pdf.Color{ .r = 250, .g = 250, .b = 250 });
try page.fillRect(col1, y, 495, row_height);
}
// Row content
page.setFillColor(pdf.Color.black);
try page.setFont(.helvetica, 10);
try page.drawText(col1 + 5, y + 8, item.desc);
try page.drawText(col2 + 5, y + 8, item.qty);
try page.drawText(col3 + 5, y + 8, item.price);
try page.drawText(col4 + 5, y + 8, item.vat);
try page.drawText(col5 + 5, y + 8, item.total);
// Row border
page.setStrokeColor(pdf.Color.light_gray);
try page.drawLine(col1, y, col1 + 495, y);
}
// Table border
try page.setLineWidth(0.5);
page.setStrokeColor(pdf.Color.gray);
try page.drawRect(col1, y, 495, table_top - y - row_height);
// Vertical lines
try page.drawLine(col2, y, col2, table_top - row_height);
try page.drawLine(col3, y, col3, table_top - row_height);
try page.drawLine(col4, y, col4, table_top - row_height);
try page.drawLine(col5, y, col5, table_top - row_height);
// Totals section
const totals_y = y - 40;
try page.setFont(.helvetica, 11);
page.setFillColor(pdf.Color.black);
try page.drawText(380, totals_y, "Subtotal:");
try page.drawText(480, totals_y, "2,320.00");
try page.drawText(380, totals_y - 18, "IVA (21%):");
try page.drawText(480, totals_y - 18, "487.20");
// Total line
try page.setLineWidth(1);
page.setStrokeColor(pdf.Color.black);
try page.drawLine(380, totals_y - 30, 545, totals_y - 30);
try page.setFont(.helvetica_bold, 14);
try page.drawText(380, totals_y - 48, "TOTAL:");
try page.drawText(475, totals_y - 48, "2,807.20 EUR");
// Payment info
const payment_y = totals_y - 100;
page.setFillColor(pdf.Color{ .r = 245, .g = 245, .b = 245 });
try page.fillRect(50, payment_y - 50, 300, 70);
try page.setFont(.helvetica_bold, 10);
page.setFillColor(pdf.Color.black);
try page.drawText(60, payment_y + 5, "FORMA DE PAGO:");
try page.setFont(.helvetica, 10);
try page.drawText(60, payment_y - 10, "Transferencia bancaria");
try page.drawText(60, payment_y - 25, "IBAN: ES12 1234 5678 9012 3456 7890");
try page.drawText(60, payment_y - 40, "Vencimiento: 30 dias");
// Footer
try page.setLineWidth(0.5);
page.setStrokeColor(pdf.Color.light_gray);
try page.drawLine(50, 80, 545, 80);
try page.setFont(.helvetica, 8);
page.setFillColor(pdf.Color.gray);
try page.drawText(50, 65, "Esta factura ha sido generada electronicamente y es valida sin firma.");
try page.drawText(50, 55, "ACME Corporation - Inscrita en el Registro Mercantil de Madrid, Tomo 12345, Folio 67, Hoja M-123456");
// Page number
try page.drawText(500, 55, "Pagina 1/1");
// Save
const filename = "invoice.pdf";
try doc.saveToFile(filename);
std.debug.print("Created: {s}\n", .{filename});
std.debug.print("Done!\n", .{});
}