zcatpdf/docs/PLAN_MAESTRO_ZPDF.md
reugenio 2996289953 feat: v0.2 - Complete text system (cell, multiCell, alignment)
Phase 1 - Refactoring:
- Modular architecture: fonts/, graphics/, objects/, output/
- Fixed Zig 0.15 API changes (ArrayListUnmanaged)
- Fixed memory issues in render()

Phase 2 - Text System:
- cell() with borders, fill, alignment
- cellAdvanced() with position control
- multiCell() with automatic word wrap
- ln() for line breaks
- getStringWidth() for text width calculation
- Page margins (setMargins, setCellMargin)
- Align enum (left, center, right)
- Border packed struct

New features:
- New Pdf API (cleaner than legacy Document)
- Document metadata (setTitle, setAuthor, setSubject)
- Color: RGB, CMYK, Grayscale support
- 52 unit tests passing
- New example: text_demo.zig

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 19:46:30 +01:00

326 lines
8.7 KiB
Markdown

# PLAN MAESTRO: zpdf - La Mejor Librería PDF en Zig
**Fecha inicio:** 2025-12-08
**Objetivo:** Crear la mejor librería PDF para Zig, basada en fpdf2 (Python)
**Filosofía:** Sin prisa, hacerlo perfecto
---
## DECISIÓN ARQUITECTÓNICA
### Fuente Principal: fpdf2 (Python)
**Repositorio:** https://github.com/py-pdf/fpdf2
**Documentación:** https://py-pdf.github.io/fpdf2/
**Por qué fpdf2:**
1. Arquitectura moderna y refinada (evolución de 20+ años de FPDF)
2. 1300+ tests = especificación ejecutable
3. UTF-8 nativo desde el diseño
4. Código Python limpio, fácil de traducir a Zig
5. Documentación exhaustiva
6. Features completos para documentos comerciales
**Descartados:**
- go-pdf/fpdf: Arrastra diseño antiguo del PHP original
- UniPDF: Comercial, no podemos estudiar el código
- lopdf (Rust): Muy bajo nivel, más para manipular que crear
---
## FASES DE IMPLEMENTACIÓN
### FASE 0: Estudio y Documentación (ACTUAL)
- [ ] Clonar fpdf2
- [ ] Leer y analizar fpdf.py completo
- [ ] Documentar arquitectura interna
- [ ] Identificar clases y métodos principales
- [ ] Mapear tipos Python → Zig
- [ ] Documentar el "core mínimo" necesario
### FASE 1: Core PDF Engine
**Objetivo:** Generar PDF válido mínimo
Componentes:
- [ ] PDFObject: Representación de objetos PDF (dict, array, stream, etc.)
- [ ] Document: Contenedor principal
- [ ] Page: Páginas individuales
- [ ] ContentStream: Comandos de dibujo
- [ ] Writer: Serialización a bytes PDF
- [ ] CrossReference: Tabla xref correcta
Entregable: PDF vacío válido que abre en cualquier lector
### FASE 2: Sistema de Texto
**Objetivo:** Texto con fuentes Type1 y posicionamiento
Componentes:
- [ ] Font: Gestión de fuentes Type1 (14 estándar)
- [ ] TextState: Estado actual (fuente, tamaño, color)
- [ ] Cell(): Celda rectangular con texto
- [ ] MultiCell(): Texto con saltos de línea automáticos
- [ ] Write(): Texto fluido
- [ ] Text(): Texto en posición absoluta
- [ ] Alineación: left, center, right, justify
Entregable: PDF con texto formateado, múltiples fuentes
### FASE 3: Sistema de Gráficos
**Objetivo:** Líneas, formas, colores
Componentes:
- [ ] Color: RGB, grayscale, CMYK
- [ ] Line(): Líneas
- [ ] Rect(): Rectángulos (stroke, fill, both)
- [ ] Circle/Ellipse(): Círculos y elipses
- [ ] Polygon(): Polígonos
- [ ] Bezier curves
- [ ] SetLineWidth, SetLineCap, SetLineJoin
- [ ] Transformaciones: translate, rotate, scale
Entregable: PDF con gráficos vectoriales
### FASE 4: Sistema de Imágenes
**Objetivo:** Embeber imágenes en PDF
Componentes:
- [ ] JPEG: Embebido directo (DCTDecode)
- [ ] PNG: Con y sin alpha (FlateDecode)
- [ ] Image(): Posicionar y escalar imágenes
- [ ] Aspect ratio automático
- [ ] Caché de imágenes (no duplicar)
Entregable: PDF con imágenes embebidas
### FASE 5: Layout y Tablas
**Objetivo:** Helpers de alto nivel para documentos
Componentes:
- [ ] Table: Helper para crear tablas
- [ ] Columns: Sistema de columnas
- [ ] SetMargins, SetAutoPageBreak
- [ ] Header/Footer callbacks
- [ ] Numeración de páginas
- [ ] Word wrap inteligente
Entregable: Facturas completas con tablas
### FASE 6: Features Avanzados
**Objetivo:** Completar la librería
Componentes:
- [ ] Links internos y externos
- [ ] Bookmarks/Outline
- [ ] Metadata (título, autor, etc.)
- [ ] Compresión streams (zlib)
- [ ] UTF-8 con fuentes TrueType embebidas
- [ ] Encriptación básica (opcional)
Entregable: Librería completa nivel producción
---
## ARQUITECTURA ZPDF (Diseño Preliminar)
```
zpdf/
├── src/
│ ├── root.zig # Exports públicos
│ ├── document.zig # Document principal
│ ├── page.zig # Página individual
│ ├── objects.zig # Tipos PDF (dict, array, stream, etc.)
│ ├── writer.zig # Serialización PDF
│ ├── content_stream.zig # Comandos gráficos
│ ├── fonts/
│ │ ├── font.zig # Interfaz Font
│ │ ├── type1.zig # Fuentes Type1 estándar
│ │ └── metrics.zig # Métricas de caracteres
│ ├── graphics/
│ │ ├── color.zig # Colores RGB/CMYK/Gray
│ │ ├── path.zig # Paths vectoriales
│ │ └── transform.zig # Transformaciones
│ ├── text/
│ │ ├── state.zig # Estado de texto
│ │ ├── layout.zig # Word wrap, alineación
│ │ └── cell.zig # Cell, MultiCell, Write
│ ├── image/
│ │ ├── jpeg.zig # Parser/embebido JPEG
│ │ └── png.zig # Parser/embebido PNG
│ └── util/
│ ├── buffer.zig # Buffer de bytes
│ └── encoding.zig # Encoding texto PDF
├── examples/
│ ├── hello.zig
│ ├── invoice.zig
│ ├── table.zig
│ └── images.zig
├── tests/
│ └── ... (muchos tests)
└── docs/
├── PLAN_MAESTRO_ZPDF.md # Este archivo
├── ARQUITECTURA_FPDF2.md # Análisis de fpdf2
└── API.md # Documentación API
```
---
## API OBJETIVO (Inspirada en fpdf2)
```zig
const std = @import("std");
const pdf = @import("zpdf");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Crear documento
var doc = try pdf.Document.init(allocator, .{
.orientation = .portrait,
.unit = .mm,
.format = .a4,
});
defer doc.deinit();
// Metadata
doc.setTitle("Factura #001");
doc.setAuthor("ACME Corp");
// Nueva página
var page = try doc.addPage();
// Márgenes
page.setMargins(10, 10, 10);
// Fuente
try page.setFont(.helvetica_bold, 24);
// Colores
page.setTextColor(pdf.Color.rgb(0, 100, 200));
// Texto
try page.cell(.{
.width = 0, // Hasta el margen
.height = 10,
.text = "FACTURA",
.align = .right,
});
// Salto de línea
page.ln(10);
// Línea
page.setDrawColor(pdf.Color.gray);
try page.line(10, page.getY(), 200, page.getY());
// Imagen
try page.image("logo.png", .{
.x = 10,
.y = 10,
.width = 40,
});
// Tabla
try page.table(.{
.x = 10,
.y = 100,
.columns = &.{
.{ .header = "Descripción", .width = 80, .align = .left },
.{ .header = "Cant.", .width = 20, .align = .center },
.{ .header = "Precio", .width = 30, .align = .right },
.{ .header = "Total", .width = 30, .align = .right },
},
.rows = &.{
&.{ "Producto A", "2", "10.00", "20.00" },
&.{ "Producto B", "1", "25.00", "25.00" },
},
});
// Guardar
try doc.save("factura.pdf");
}
```
---
## MAPEO TIPOS PYTHON → ZIG
| Python (fpdf2) | Zig (zpdf) |
|----------------|------------|
| `class FPDF` | `pub const Document = struct` |
| `str` | `[]const u8` |
| `float` | `f32` |
| `int` | `i32` o `u32` |
| `list` | `std.ArrayList` o slice |
| `dict` | `std.StringHashMap` o struct |
| `bytes` | `[]u8` |
| `Optional[T]` | `?T` |
| `Union[A, B]` | `union(enum)` |
| Exception | `error` union |
| `with open()` | `std.fs.File` |
| `io.BytesIO` | `std.ArrayList(u8)` |
---
## COMANDOS
```bash
# Zig
ZIG=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
# Build
$ZIG build
# Tests
$ZIG build test
# Ejemplos
$ZIG build hello
$ZIG build invoice
# Ver PDF generado
evince hello.pdf
```
---
## REFERENCIAS
### Especificación PDF
- PDF 1.4: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf
- PDF 1.7 (ISO 32000): https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/PDF32000_2008.pdf
### Librerías de Referencia
- fpdf2 (Python): https://github.com/py-pdf/fpdf2
- go-pdf/fpdf (Go): https://codeberg.org/go-pdf/fpdf
- FPDF original (PHP): https://github.com/Setasign/FPDF
### Documentación fpdf2
- Tutorial: https://py-pdf.github.io/fpdf2/Tutorial.html
- API Reference: https://py-pdf.github.io/fpdf2/fpdf/
---
## NOTAS DE DESARROLLO
*Se irán añadiendo conforme avance el proyecto*
### 2025-12-08 - Inicio del proyecto
- Decisión: usar fpdf2 como fuente principal
- Razón: arquitectura más moderna, mejor documentación, más tests
- Primer paso: clonar y estudiar fpdf2
---
## SI ESTA CONVERSACIÓN SE CORTA
1. Leer este documento completo
2. Leer CLAUDE.md del proyecto
3. Continuar desde donde se quedó según las fases
4. El código de fpdf2 estará clonado en: `/mnt/cello2/arno/re/recode/zig/zpdf/reference/fpdf2/`
5. El análisis de arquitectura estará en: `docs/ARQUITECTURA_FPDF2.md`
---
**Recuerda:** Sin prisa, lo importante es hacerlo perfecto.