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>
416 lines
12 KiB
Markdown
416 lines
12 KiB
Markdown
# zpdf - Generador PDF para Zig
|
|
|
|
> **Ultima actualizacion**: 2025-12-08
|
|
> **Lenguaje**: Zig 0.15.2
|
|
> **Estado**: v0.2 - Sistema de texto completo (cell, multiCell, alignment)
|
|
> **Fuente principal**: fpdf2 (Python) - https://github.com/py-pdf/fpdf2
|
|
|
|
## Descripcion del Proyecto
|
|
|
|
**zpdf** es una libreria pura Zig para generacion de documentos PDF. Sin dependencias externas, compila a un binario unico.
|
|
|
|
**Filosofia**:
|
|
- Zero dependencias (100% Zig puro)
|
|
- API simple y directa inspirada en fpdf2
|
|
- Enfocado en generacion de facturas/documentos comerciales
|
|
- Soporte para texto, tablas, imagenes y formas basicas
|
|
- Calidad open source (doc comments, codigo claro)
|
|
|
|
**Objetivo**: Ser el pilar para generar PDFs en Zig con codigo 100% propio, replicando funcionalidad de librerias maduras como fpdf2/gofpdf.
|
|
|
|
---
|
|
|
|
## Estado Actual del Proyecto
|
|
|
|
### Implementacion v0.2 (Sistema de Texto Completo)
|
|
|
|
| Componente | Estado | Archivo |
|
|
|------------|--------|---------|
|
|
| **Pdf (API Nueva)** | | |
|
|
| Pdf init/deinit | OK | `src/pdf.zig` |
|
|
| setTitle, setAuthor, setSubject | OK | `src/pdf.zig` |
|
|
| addPage (with options) | OK | `src/pdf.zig` |
|
|
| output() / render() | OK | `src/pdf.zig` |
|
|
| save() | OK | `src/pdf.zig` |
|
|
| **Document (Legacy)** | | |
|
|
| Document init/deinit | OK | `src/root.zig` |
|
|
| addPage (standard sizes) | OK | `src/root.zig` |
|
|
| render() / saveToFile() | OK | `src/root.zig` |
|
|
| **Page** | | |
|
|
| Page init/deinit | OK | `src/page.zig` |
|
|
| setFont / getFont / getFontSize | OK | `src/page.zig` |
|
|
| setFillColor / setStrokeColor / setTextColor | OK | `src/page.zig` |
|
|
| setLineWidth | OK | `src/page.zig` |
|
|
| setXY / setX / setY / getX / getY | OK | `src/page.zig` |
|
|
| setMargins / setCellMargin | OK | `src/page.zig` |
|
|
| drawText | OK | `src/page.zig` |
|
|
| writeText | OK | `src/page.zig` |
|
|
| **cell()** | OK | `src/page.zig` |
|
|
| **cellAdvanced()** | OK | `src/page.zig` |
|
|
| **multiCell()** | OK | `src/page.zig` |
|
|
| **ln()** | OK | `src/page.zig` |
|
|
| **getStringWidth()** | OK | `src/page.zig` |
|
|
| **getEffectiveWidth()** | OK | `src/page.zig` |
|
|
| drawLine | OK | `src/page.zig` |
|
|
| drawRect / fillRect / drawFilledRect | OK | `src/page.zig` |
|
|
| rect (with RenderStyle) | OK | `src/page.zig` |
|
|
| **Types** | | |
|
|
| PageSize enum (A4, Letter, A3, A5, Legal) | OK | `src/objects/base.zig` |
|
|
| Orientation enum (portrait, landscape) | OK | `src/objects/base.zig` |
|
|
| Font enum (14 Type1 fonts) | OK | `src/fonts/type1.zig` |
|
|
| Color struct (RGB, CMYK, Grayscale) | OK | `src/graphics/color.zig` |
|
|
| **Align enum (left, center, right)** | OK | `src/page.zig` |
|
|
| **Border packed struct** | OK | `src/page.zig` |
|
|
| **CellPosition enum** | OK | `src/page.zig` |
|
|
| ContentStream | OK | `src/content_stream.zig` |
|
|
| OutputProducer | OK | `src/output/producer.zig` |
|
|
|
|
### Tests
|
|
|
|
| Categoria | Tests | Estado |
|
|
|-----------|-------|--------|
|
|
| root.zig (integration) | 8 | OK |
|
|
| page.zig (Page operations) | 18 | OK |
|
|
| content_stream.zig | 6 | OK |
|
|
| graphics/color.zig | 5 | OK |
|
|
| fonts/type1.zig | 5 | OK |
|
|
| objects/base.zig | 5 | OK |
|
|
| output/producer.zig | 5 | OK |
|
|
| **Total** | **52** | OK |
|
|
|
|
### Ejemplos
|
|
|
|
| Ejemplo | Descripcion | Estado |
|
|
|---------|-------------|--------|
|
|
| hello.zig | PDF minimo con texto y formas | OK |
|
|
| invoice.zig | Factura completa realista | OK |
|
|
| **text_demo.zig** | Demo sistema de texto (cells, tables, multiCell) | OK |
|
|
|
|
---
|
|
|
|
## Arquitectura Modular
|
|
|
|
```
|
|
zpdf/
|
|
├── CLAUDE.md # Este archivo - estado del proyecto
|
|
├── build.zig # Sistema de build
|
|
├── src/
|
|
│ ├── root.zig # Exports publicos + Document legacy
|
|
│ ├── pdf.zig # Pdf facade (API nueva)
|
|
│ ├── page.zig # Page + sistema de texto
|
|
│ ├── content_stream.zig # Content stream (operadores PDF)
|
|
│ ├── fonts/
|
|
│ │ ├── mod.zig # Exports de fonts
|
|
│ │ └── type1.zig # 14 fuentes Type1 + metricas
|
|
│ ├── graphics/
|
|
│ │ ├── mod.zig # Exports de graphics
|
|
│ │ └── color.zig # Color (RGB, CMYK, Gray)
|
|
│ ├── objects/
|
|
│ │ ├── mod.zig # Exports de objects
|
|
│ │ └── base.zig # PageSize, Orientation, Unit
|
|
│ └── output/
|
|
│ ├── mod.zig # Exports de output
|
|
│ └── producer.zig # OutputProducer (serializa PDF)
|
|
├── examples/
|
|
│ ├── hello.zig # Ejemplo basico
|
|
│ ├── invoice.zig # Factura ejemplo
|
|
│ └── text_demo.zig # Demo sistema de texto
|
|
└── docs/
|
|
├── PLAN_MAESTRO_ZPDF.md
|
|
├── ARQUITECTURA_FPDF2.md
|
|
└── ARQUITECTURA_ZPDF.md
|
|
```
|
|
|
|
---
|
|
|
|
## Roadmap
|
|
|
|
### Fase 1 - Core + Refactoring (COMPLETADO)
|
|
- [x] Estructura documento PDF 1.4
|
|
- [x] Paginas (A4, Letter, A3, A5, Legal, custom)
|
|
- [x] Texto basico (14 fuentes Type1 built-in)
|
|
- [x] Lineas y rectangulos
|
|
- [x] Colores RGB, CMYK, Grayscale
|
|
- [x] Serializacion correcta
|
|
- [x] Refactoring modular (separar en archivos)
|
|
- [x] Arreglar errores Zig 0.15 (ArrayListUnmanaged)
|
|
|
|
### Fase 2 - Sistema de Texto (COMPLETADO)
|
|
- [x] cell() - celda con bordes, relleno, alineacion
|
|
- [x] cellAdvanced() - cell con control de posicion
|
|
- [x] multiCell() - texto con word wrap automatico
|
|
- [x] ln() - salto de linea
|
|
- [x] getStringWidth() - ancho de texto
|
|
- [x] Alineacion (left, center, right)
|
|
- [x] Bordes configurables (Border packed struct)
|
|
- [x] Margenes de pagina
|
|
- [x] 18 tests para sistema de texto
|
|
|
|
### Fase 3 - Imagenes (PENDIENTE)
|
|
- [ ] JPEG embebido
|
|
- [ ] PNG embebido (con alpha)
|
|
- [ ] Escalado y posicionamiento
|
|
- [ ] Aspect ratio preservation
|
|
|
|
### Fase 4 - Utilidades (PENDIENTE)
|
|
- [ ] Helper para tablas
|
|
- [ ] Numeracion de paginas
|
|
- [ ] Headers/footers automaticos
|
|
- [ ] Links/URLs
|
|
|
|
### Fase 5 - Avanzado (FUTURO)
|
|
- [ ] Fuentes TTF embebidas
|
|
- [ ] Compresion de streams (zlib)
|
|
- [ ] Bookmarks/outline
|
|
- [ ] Forms (campos rellenables)
|
|
|
|
---
|
|
|
|
## API Actual
|
|
|
|
### API Nueva (Pdf)
|
|
|
|
```zig
|
|
const zpdf = @import("zpdf");
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
defer _ = gpa.deinit();
|
|
const allocator = gpa.allocator();
|
|
|
|
// Crear documento
|
|
var doc = zpdf.Pdf.init(allocator, .{
|
|
.page_size = .a4,
|
|
.orientation = .portrait,
|
|
});
|
|
defer doc.deinit();
|
|
|
|
// Metadatos
|
|
doc.setTitle("Mi Documento");
|
|
doc.setAuthor("zpdf");
|
|
|
|
// Agregar pagina
|
|
var page = try doc.addPage(.{});
|
|
|
|
// Configurar fuente y posicion
|
|
try page.setFont(.helvetica_bold, 24);
|
|
page.setXY(50, 800);
|
|
page.setMargins(50, 50, 50);
|
|
|
|
// cell() - celda simple
|
|
try page.cell(0, 30, "Titulo", zpdf.Border.none, .center, false);
|
|
page.ln(35);
|
|
|
|
// Tabla con cells
|
|
try page.setFont(.helvetica, 12);
|
|
page.setFillColor(zpdf.Color.light_gray);
|
|
try page.cell(150, 20, "Columna 1", zpdf.Border.all, .center, true);
|
|
try page.cell(150, 20, "Columna 2", zpdf.Border.all, .center, true);
|
|
page.ln(null);
|
|
|
|
// multiCell - texto con word wrap
|
|
const texto_largo = "Este es un texto largo que se ajustara automaticamente...";
|
|
try page.multiCell(400, null, texto_largo, zpdf.Border.all, .left, false);
|
|
|
|
// Guardar
|
|
try doc.save("documento.pdf");
|
|
}
|
|
```
|
|
|
|
### API Legacy (Document)
|
|
|
|
```zig
|
|
const pdf = @import("zpdf");
|
|
|
|
var doc = pdf.Document.init(allocator);
|
|
defer doc.deinit();
|
|
|
|
var page = try doc.addPage(.a4);
|
|
try page.setFont(.helvetica_bold, 24);
|
|
try page.drawText(50, 750, "Titulo");
|
|
|
|
try doc.saveToFile("documento.pdf");
|
|
```
|
|
|
|
### Sistema de Texto
|
|
|
|
```zig
|
|
// cell(width, height, text, border, align, fill)
|
|
// width=0 extiende hasta margen derecho
|
|
// width=null ajusta al ancho del texto
|
|
try page.cell(100, 20, "Hello", Border.all, .left, false);
|
|
try page.cell(0, 20, "Full width", Border.none, .center, true);
|
|
|
|
// cellAdvanced - control de posicion despues de la celda
|
|
try page.cellAdvanced(100, 20, "A", Border.all, .left, false, .right); // mover a la derecha
|
|
try page.cellAdvanced(100, 20, "B", Border.all, .left, false, .next_line); // nueva linea
|
|
try page.cellAdvanced(100, 20, "C", Border.all, .left, false, .below); // debajo (mismo X)
|
|
|
|
// multiCell - word wrap automatico
|
|
try page.multiCell(200, 15, "Texto largo que se ajusta automaticamente al ancho especificado.", Border.all, .left, true);
|
|
|
|
// ln(height) - salto de linea
|
|
page.ln(20); // salto de 20 puntos
|
|
page.ln(null); // salto del tamano de fuente actual
|
|
|
|
// getStringWidth - ancho del texto
|
|
const width = page.getStringWidth("Hello World");
|
|
```
|
|
|
|
### Bordes
|
|
|
|
```zig
|
|
const Border = packed struct {
|
|
left: bool,
|
|
top: bool,
|
|
right: bool,
|
|
bottom: bool,
|
|
};
|
|
|
|
Border.none // sin bordes
|
|
Border.all // todos los bordes
|
|
Border{ .left = true, .bottom = true } // bordes especificos
|
|
Border.fromInt(0b1111) // desde entero (LTRB)
|
|
```
|
|
|
|
### Alineacion
|
|
|
|
```zig
|
|
const Align = enum { left, center, right };
|
|
|
|
try page.cell(100, 20, "Left", Border.all, .left, false);
|
|
try page.cell(100, 20, "Center", Border.all, .center, false);
|
|
try page.cell(100, 20, "Right", Border.all, .right, false);
|
|
```
|
|
|
|
### Colores
|
|
|
|
```zig
|
|
// Predefinidos
|
|
zpdf.Color.black
|
|
zpdf.Color.white
|
|
zpdf.Color.red
|
|
zpdf.Color.green
|
|
zpdf.Color.blue
|
|
zpdf.Color.light_gray
|
|
zpdf.Color.medium_gray
|
|
|
|
// RGB (0-255)
|
|
zpdf.Color.rgb(41, 98, 255)
|
|
|
|
// Hex
|
|
zpdf.Color.hex(0xFF8000)
|
|
|
|
// CMYK (0.0-1.0)
|
|
zpdf.Color.cmyk(0.0, 1.0, 1.0, 0.0)
|
|
|
|
// Grayscale (0.0-1.0)
|
|
zpdf.Color.gray(0.5)
|
|
```
|
|
|
|
---
|
|
|
|
## Comandos
|
|
|
|
```bash
|
|
# Zig path
|
|
ZIG=/mnt/cello2/arno/re/recode/zig/zig-0.15.2/zig-x86_64-linux-0.15.2/zig
|
|
|
|
# Compilar
|
|
$ZIG build
|
|
|
|
# Tests
|
|
$ZIG build test
|
|
|
|
# Ejecutar ejemplos
|
|
$ZIG build && ./zig-out/bin/hello
|
|
$ZIG build && ./zig-out/bin/invoice
|
|
$ZIG build && ./zig-out/bin/text_demo
|
|
```
|
|
|
|
---
|
|
|
|
## Fuentes Type1 Built-in
|
|
|
|
PDF incluye 14 fuentes estandar que no necesitan embeber:
|
|
|
|
| Familia | Variantes |
|
|
|---------|-----------|
|
|
| Helvetica | helvetica, helvetica_bold, helvetica_oblique, helvetica_bold_oblique |
|
|
| Times | times_roman, times_bold, times_italic, times_bold_italic |
|
|
| Courier | courier, courier_bold, courier_oblique, courier_bold_oblique |
|
|
| Otros | symbol, zapf_dingbats |
|
|
|
|
---
|
|
|
|
## Tamanos de Pagina
|
|
|
|
| Nombre | Puntos | Milimetros |
|
|
|--------|--------|------------|
|
|
| A4 | 595 x 842 | 210 x 297 |
|
|
| A3 | 842 x 1191 | 297 x 420 |
|
|
| A5 | 420 x 595 | 148 x 210 |
|
|
| Letter | 612 x 792 | 216 x 279 |
|
|
| Legal | 612 x 1008 | 216 x 356 |
|
|
|
|
---
|
|
|
|
## Equipo y Metodologia
|
|
|
|
### Normas de Trabajo Centralizadas
|
|
|
|
**IMPORTANTE**: Todas las normas de trabajo estan en:
|
|
```
|
|
/mnt/cello2/arno/re/recode/TEAM_STANDARDS/
|
|
```
|
|
|
|
### Control de Versiones
|
|
|
|
```bash
|
|
# Remote
|
|
git remote: git@git.reugenio.com:reugenio/zpdf.git
|
|
|
|
# Branches
|
|
main # Codigo estable
|
|
```
|
|
|
|
---
|
|
|
|
## Historial de Desarrollo
|
|
|
|
### 2025-12-08 - v0.2 (Sistema de Texto Completo)
|
|
- Refactoring modular completo (fonts/, graphics/, objects/, output/)
|
|
- Arreglados errores Zig 0.15 (ArrayListUnmanaged API)
|
|
- Sistema de texto completo:
|
|
- cell() con bordes, relleno, alineacion
|
|
- cellAdvanced() con control de posicion
|
|
- multiCell() con word wrap automatico
|
|
- ln() para saltos de linea
|
|
- getStringWidth() para calcular anchos
|
|
- Margenes de pagina configurables
|
|
- Nueva API Pdf (mas limpia que Document legacy)
|
|
- 52 tests unitarios pasando
|
|
- Nuevo ejemplo: text_demo.zig
|
|
|
|
### 2025-12-08 - v0.1 (Core Funcional)
|
|
- Estructura inicial del proyecto
|
|
- Document, Page, Color, Font, PageSize types
|
|
- Texto con 14 fuentes Type1 standard
|
|
- Graficos: lineas, rectangulos (stroke, fill, both)
|
|
- Colores RGB
|
|
- Serializacion PDF 1.4 correcta
|
|
- 6 tests unitarios pasando
|
|
- Ejemplos: hello.zig, invoice.zig funcionales
|
|
|
|
---
|
|
|
|
## Referencias
|
|
|
|
- **fpdf2 (Python)**: https://github.com/py-pdf/fpdf2 - Fuente principal
|
|
- **PDF 1.4 Spec**: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.4.pdf
|
|
- **pdf-nano (Zig)**: https://github.com/GregorBudweiser/pdf-nano
|
|
|
|
---
|
|
|
|
**zpdf - Generador PDF para Zig**
|
|
*v0.2 - 2025-12-08*
|