//! Invoice PDF example - Demonstrates a realistic use case const std = @import("std"); const pdf = @import("zcatpdf"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); std.debug.print("zcatpdf - 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.rgb(41, 98, 255)); // Blue try page.drawText(50, 780, "ACME Corporation"); try page.setFont(.helvetica, 10); page.setFillColor(pdf.Color.medium_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.rgb(245, 245, 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.rgb(41, 98, 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.rgb(250, 250, 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.medium_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.rgb(245, 245, 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.medium_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", .{}); }