//! zpdf - PDF generation library for Zig //! //! A pure Zig library for creating PDF documents with zero dependencies. //! Based on fpdf2 (Python) architecture. //! //! ## Quick Start //! //! ```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"); //! } //! ``` const std = @import("std"); // ============================================================================= // Module Re-exports // ============================================================================= /// Main PDF document facade pub const pdf = @import("pdf.zig"); pub const Pdf = pdf.Pdf; /// Page representation pub const page = @import("page.zig"); pub const Page = page.Page; pub const Align = page.Align; pub const Border = page.Border; pub const CellPosition = page.Page.CellPosition; /// Content stream (low-level PDF operators) pub const content_stream = @import("content_stream.zig"); pub const ContentStream = content_stream.ContentStream; pub const RenderStyle = content_stream.RenderStyle; pub const LineCap = content_stream.LineCap; pub const LineJoin = content_stream.LineJoin; pub const TextRenderMode = content_stream.TextRenderMode; /// Graphics (colors, etc.) pub const graphics = @import("graphics/mod.zig"); pub const Color = graphics.Color; /// Fonts pub const fonts = @import("fonts/mod.zig"); pub const Font = fonts.Font; pub const FontFamily = fonts.FontFamily; pub const FontState = fonts.FontState; /// Objects (base types, page sizes, units) pub const objects = @import("objects/mod.zig"); pub const PageSize = objects.PageSize; pub const Orientation = objects.Orientation; pub const Unit = objects.Unit; /// Output (PDF generation) pub const output = @import("output/mod.zig"); pub const OutputProducer = output.OutputProducer; /// Images (JPEG, PNG) pub const images = @import("images/mod.zig"); pub const ImageInfo = images.ImageInfo; pub const ImageFormat = images.ImageFormat; // ============================================================================= // Backwards Compatibility - Old API (Document) // ============================================================================= /// Legacy Document type (use Pdf instead for new code). /// Provided for backwards compatibility with existing code. pub const Document = struct { inner: Pdf, const Self = @This(); /// Creates a new empty PDF document. pub fn init(allocator: std.mem.Allocator) Self { return .{ .inner = Pdf.init(allocator, .{}), }; } /// Frees all resources. pub fn deinit(self: *Self) void { self.inner.deinit(); } /// Adds a new page with a standard size. pub fn addPage(self: *Self, size: PageSize) !*Page { return try self.inner.addPage(.{ .size = size }); } /// Adds a new page with custom dimensions (in points). pub fn addPageCustom(self: *Self, width: f32, height: f32) !*Page { return try self.inner.addPageCustom(width, height); } /// Renders the document to a byte buffer. pub fn render(self: *Self, allocator: std.mem.Allocator) ![]u8 { _ = allocator; // Use inner allocator return try self.inner.render(); } /// Saves the document to a file. pub fn saveToFile(self: *Self, path: []const u8) !void { return try self.inner.save(path); } }; // ============================================================================= // Tests // ============================================================================= test "zpdf re-exports" { // Test that all types are accessible _ = Pdf; _ = Page; _ = ContentStream; _ = Color; _ = Font; _ = PageSize; _ = Document; } test "Document backwards compatibility" { const allocator = std.testing.allocator; var doc = Document.init(allocator); defer doc.deinit(); var pg = try doc.addPage(.a4); try pg.setFont(.helvetica_bold, 24); try pg.drawText(50, 750, "Hello"); try pg.drawLine(50, 740, 200, 740); const data = try doc.render(allocator); defer allocator.free(data); try std.testing.expect(std.mem.startsWith(u8, data, "%PDF-1.4")); } test "new Pdf API" { const allocator = std.testing.allocator; var zpdf_doc = Pdf.init(allocator, .{ .page_size = .a4, .orientation = .portrait, }); defer zpdf_doc.deinit(); zpdf_doc.setTitle("Test Document"); zpdf_doc.setAuthor("zpdf"); var pg = try zpdf_doc.addPage(.{}); try pg.setFont(.helvetica_bold, 24); pg.setFillColor(Color.blue); try pg.drawText(50, 750, "Hello zpdf!"); pg.setStrokeColor(Color.red); try pg.setLineWidth(2); try pg.drawLine(50, 740, 200, 740); pg.setFillColor(Color.light_gray); try pg.fillRect(50, 600, 150, 100); const data = try zpdf_doc.output(); defer allocator.free(data); try std.testing.expect(std.mem.startsWith(u8, data, "%PDF-1.4")); try std.testing.expect(std.mem.indexOf(u8, data, "/Title (Test Document)") != null); } test "Color types" { const red = Color.rgb(255, 0, 0); const floats = red.toRgbFloats(); try std.testing.expectApproxEqAbs(@as(f32, 1.0), floats.r, 0.01); try std.testing.expectApproxEqAbs(@as(f32, 0.0), floats.g, 0.01); try std.testing.expectApproxEqAbs(@as(f32, 0.0), floats.b, 0.01); const hex_color = Color.hex(0xFF8000); try std.testing.expectEqual(@as(u8, 255), hex_color.rgb_val.r); try std.testing.expectEqual(@as(u8, 128), hex_color.rgb_val.g); try std.testing.expectEqual(@as(u8, 0), hex_color.rgb_val.b); } test "Font metrics" { const font = Font.helvetica; try std.testing.expectEqualStrings("Helvetica", font.pdfName()); const width = font.stringWidth("Hello", 12.0); try std.testing.expect(width > 0); } test "ContentStream operators" { const allocator = std.testing.allocator; var cs = ContentStream.init(allocator); defer cs.deinit(); try cs.saveState(); try cs.setLineWidth(2.0); try cs.setStrokeColorRgb(1.0, 0.0, 0.0); try cs.moveTo(100, 200); try cs.lineTo(300, 200); try cs.stroke(); try cs.restoreState(); const content = cs.getContent(); try std.testing.expect(std.mem.indexOf(u8, content, "q\n") != null); try std.testing.expect(std.mem.indexOf(u8, content, "Q\n") != null); try std.testing.expect(std.mem.indexOf(u8, content, "1.000 0.000 0.000 RG") != null); } // Import all module tests comptime { _ = @import("content_stream.zig"); _ = @import("page.zig"); _ = @import("pdf.zig"); _ = @import("graphics/color.zig"); _ = @import("fonts/type1.zig"); _ = @import("objects/base.zig"); _ = @import("output/producer.zig"); _ = @import("images/mod.zig"); _ = @import("images/image_info.zig"); _ = @import("images/jpeg.zig"); _ = @import("images/png.zig"); }