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>
209 lines
7 KiB
Zig
209 lines
7 KiB
Zig
//! Transparency Demo - Alpha/Opacity Support
|
|
//!
|
|
//! Demonstrates the transparency capabilities of zpdf including:
|
|
//! - Fill opacity for shapes and text
|
|
//! - Stroke opacity for lines and outlines
|
|
//! - Layered transparent objects
|
|
|
|
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 - Transparency Demo\n", .{});
|
|
|
|
var doc = pdf.Pdf.init(allocator, .{});
|
|
defer doc.deinit();
|
|
|
|
doc.setTitle("Transparency Demo");
|
|
doc.setAuthor("zpdf");
|
|
|
|
const page = try doc.addPage(.{});
|
|
|
|
// Title
|
|
try page.setFont(.helvetica_bold, 24);
|
|
page.setFillColor(pdf.Color.rgb(41, 98, 255));
|
|
try page.drawText(50, 780, "Transparency / Alpha");
|
|
|
|
try page.setFont(.helvetica, 11);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(50, 755, "Demonstrating fill and stroke opacity using ExtGState");
|
|
|
|
// =========================================================================
|
|
// Fill Opacity Examples
|
|
// =========================================================================
|
|
try page.setFont(.helvetica_bold, 14);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(50, 710, "Fill Opacity:");
|
|
|
|
// Draw overlapping squares with different opacities
|
|
const base_x: f32 = 80;
|
|
const base_y: f32 = 550;
|
|
const size: f32 = 100;
|
|
|
|
// First layer - red square (fully opaque)
|
|
page.setFillColor(pdf.Color.rgb(255, 0, 0));
|
|
try page.fillRect(base_x, base_y, size, size);
|
|
|
|
// Second layer - green square (75% opacity)
|
|
page.setFillColor(pdf.Color.rgb(0, 255, 0));
|
|
try page.setFillOpacity(0.75);
|
|
try page.fillRect(base_x + 40, base_y + 30, size, size);
|
|
|
|
// Third layer - blue square (50% opacity)
|
|
page.setFillColor(pdf.Color.rgb(0, 0, 255));
|
|
try page.setFillOpacity(0.5);
|
|
try page.fillRect(base_x + 80, base_y + 60, size, size);
|
|
|
|
// Labels
|
|
try page.setOpacity(1.0); // Reset to fully opaque
|
|
try page.setFont(.helvetica, 9);
|
|
page.setFillColor(pdf.Color.dark_gray);
|
|
try page.drawText(base_x, base_y - 15, "Overlapping (100%, 75%, 50%)");
|
|
|
|
// Individual opacity examples
|
|
const opacities = [_]f32{ 1.0, 0.75, 0.5, 0.25, 0.1 };
|
|
var x: f32 = 280;
|
|
|
|
for (opacities) |opacity| {
|
|
try page.setFillOpacity(opacity);
|
|
page.setFillColor(pdf.Color.rgb(128, 0, 128)); // Purple
|
|
try page.fillRect(x, base_y + 30, 60, 60);
|
|
|
|
try page.setOpacity(1.0); // Reset for label
|
|
try page.setFont(.helvetica, 9);
|
|
page.setFillColor(pdf.Color.dark_gray);
|
|
|
|
var buf: [32]u8 = undefined;
|
|
const label = std.fmt.bufPrint(&buf, "{d}%", .{@as(u32, @intFromFloat(opacity * 100))}) catch "??";
|
|
try page.drawText(x + 20, base_y + 10, label);
|
|
|
|
x += 70;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Stroke Opacity Examples
|
|
// =========================================================================
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica_bold, 14);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(50, 500, "Stroke Opacity:");
|
|
|
|
try page.setLineWidth(8);
|
|
page.setStrokeColor(pdf.Color.rgb(220, 20, 60)); // Crimson
|
|
|
|
x = 80;
|
|
for (opacities) |opacity| {
|
|
try page.setStrokeOpacity(opacity);
|
|
try page.drawLine(x, 420, x + 80, 420);
|
|
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica, 9);
|
|
page.setFillColor(pdf.Color.dark_gray);
|
|
|
|
var buf: [32]u8 = undefined;
|
|
const label = std.fmt.bufPrint(&buf, "{d}%", .{@as(u32, @intFromFloat(opacity * 100))}) catch "??";
|
|
try page.drawText(x + 20, 400, label);
|
|
|
|
x += 100;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Combined Fill and Stroke Opacity
|
|
// =========================================================================
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica_bold, 14);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(50, 370, "Combined Fill + Stroke Opacity:");
|
|
|
|
try page.setLineWidth(4);
|
|
|
|
x = 80;
|
|
const fill_opacities = [_]f32{ 1.0, 0.5, 0.25 };
|
|
const stroke_opacities = [_]f32{ 1.0, 0.5, 0.25 };
|
|
|
|
for (fill_opacities, stroke_opacities) |fill_op, stroke_op| {
|
|
page.setFillColor(pdf.Color.rgb(100, 149, 237)); // Cornflower blue
|
|
page.setStrokeColor(pdf.Color.rgb(0, 0, 139)); // Dark blue
|
|
|
|
try page.setFillOpacity(fill_op);
|
|
try page.setStrokeOpacity(stroke_op);
|
|
|
|
try page.drawFilledRect(x, 280, 80, 60);
|
|
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica, 8);
|
|
page.setFillColor(pdf.Color.dark_gray);
|
|
|
|
var buf: [32]u8 = undefined;
|
|
const label = std.fmt.bufPrint(&buf, "f:{d}% s:{d}%", .{
|
|
@as(u32, @intFromFloat(fill_op * 100)),
|
|
@as(u32, @intFromFloat(stroke_op * 100)),
|
|
}) catch "??";
|
|
try page.drawText(x, 265, label);
|
|
|
|
x += 120;
|
|
}
|
|
|
|
// =========================================================================
|
|
// Transparent Text
|
|
// =========================================================================
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica_bold, 14);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(50, 230, "Transparent Text:");
|
|
|
|
// Background rectangle
|
|
page.setFillColor(pdf.Color.rgb(255, 215, 0)); // Gold
|
|
try page.fillRect(80, 130, 450, 70);
|
|
|
|
// Overlapping text with different opacities
|
|
try page.setFont(.helvetica_bold, 48);
|
|
|
|
page.setFillColor(pdf.Color.rgb(255, 0, 0));
|
|
try page.setFillOpacity(1.0);
|
|
try page.drawText(100, 150, "ZPDF");
|
|
|
|
page.setFillColor(pdf.Color.rgb(0, 128, 0));
|
|
try page.setFillOpacity(0.6);
|
|
try page.drawText(150, 160, "ZPDF");
|
|
|
|
page.setFillColor(pdf.Color.rgb(0, 0, 255));
|
|
try page.setFillOpacity(0.3);
|
|
try page.drawText(200, 170, "ZPDF");
|
|
|
|
// =========================================================================
|
|
// Transparent Circles (Venn diagram style)
|
|
// =========================================================================
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica_bold, 14);
|
|
page.setFillColor(pdf.Color.black);
|
|
try page.drawText(350, 230, "Overlapping Circles:");
|
|
|
|
try page.setFillOpacity(0.5);
|
|
|
|
page.setFillColor(pdf.Color.rgb(255, 0, 0));
|
|
try page.fillCircle(420, 170, 50);
|
|
|
|
page.setFillColor(pdf.Color.rgb(0, 255, 0));
|
|
try page.fillCircle(460, 170, 50);
|
|
|
|
page.setFillColor(pdf.Color.rgb(0, 0, 255));
|
|
try page.fillCircle(440, 130, 50);
|
|
|
|
// Footer
|
|
try page.setOpacity(1.0);
|
|
try page.setFont(.helvetica, 9);
|
|
page.setFillColor(pdf.Color.medium_gray);
|
|
try page.drawText(250, 50, "zpdf Transparency Demo");
|
|
|
|
// Save
|
|
const filename = "transparency_demo.pdf";
|
|
try doc.save(filename);
|
|
|
|
std.debug.print("Created: {s} ({d} pages)\n", .{ filename, doc.pageCount() });
|
|
std.debug.print("Done!\n", .{});
|
|
}
|