8. Espacio de nombres fix:: — normalización
← codes:: · Índice · Siguiente: data:: →
19 operaciones que modifican el PDF y guardan un archivo nuevo. El original no se altera nunca.
8.1 Cómo se usa
fix:: es el único espacio de nombres que escribe, así que se ejecuta con un
comando propio:
pdfl fix entrada.pdf script.pdfl --output corregido.pdf
Opciones:
| Opción | Qué hace |
|---|---|
--output <archivo> |
PDF de salida (obligatorio) |
--dry-run |
Lista las operaciones sin guardar nada |
--report json|csv|html|pdf |
Formato del informe |
--report-file <archivo> |
Escribe el informe en un archivo |
En pdfl run, cualquier llamada a fix:: da un error que indica el comando
correcto: así nadie aplica correcciones creyendo que solo está validando.
Cómo funcionan las operaciones
// Este script NO necesita checks: son comandos, ejecutados en orden.
fix::set_trim_box(8.5, 8.5, 586.5, 833.5)
fix::add_page_numbers()
fix::add_watermark("BORRADOR")
Cada llamada se valida en el momento (página inexistente, rotación inválida,
archivo ausente) y solo después se aplica. El informe trae el campo fixes con
lo que se hizo:
"fixes": [
"TrimBox set to [8.5, 8.5, 586.5, 833.5]",
"page numbering added",
"watermark \"BORRADOR\" added"
]
Nada impide mezclar validación y corrección en el mismo script:
// Valida antes de corregir: si la precondición falla, sale en el informe
check "Precondiciones" {
require doc.page_count > 0
assert !struct::check_encryption(), "archivo cifrado, no se puede corregir"
}
fix::add_page_numbers()
8.2 Cajas de página
fix::set_page_size(anchura, altura)
Define la MediaBox de todas las páginas.
// A4 en puntos — o usa unidades y deja la conversión al lenguaje
fix::set_page_size(595, 842)
fix::set_page_size(210mm, 297mm) // idéntico, y más legible
fix::set_crop_box(x0, y0, x1, y1), set_trim_box, set_bleed_box
Definen la caja correspondiente en todas las páginas. Coordenadas en puntos, de la esquina inferior izquierda a la superior derecha.
// El archivo llegó de la editorial sin las cajas de producción:
// TrimBox = área final; BleedBox = con 3 mm de sangrado alrededor
fix::set_trim_box(8.5, 8.5, 586.5, 833.5)
fix::set_bleed_box(0, 0, 595, 842)
8.3 Páginas
fix::rotate_page([pagina,] grados)
Rota 90, 180 o 270 grados. Sin el número de página, las rota todas.
fix::rotate_page(90) // todas las páginas
fix::rotate_page(3, 180) // solo la página 3
fix::delete_page(n) y fix::duplicate_page(n)
fix::delete_page(1) // quita la portada de borrador
fix::duplicate_page(1) // duplica la portada (la copia entra justo después)
Eliminar la única página del documento se rechaza con un mensaje claro.
fix::reorder_pages([nuevo, orden])
Nuevo orden de las páginas. La lista debe usar cada página exactamente una vez.
// Documento de 4 páginas con la portada al final: la trae al principio
fix::reorder_pages([4, 1, 2, 3])
fix::split_document(desde, hasta, "salida.pdf")
Guarda un intervalo de páginas en otro archivo. El documento en edición sigue intacto.
// Separa el interior de la cubierta para enviarlos a proveedores distintos
fix::split_document(1, 2, "cubierta.pdf")
fix::split_document(3, 50, "interior.pdf")
fix::merge_documents("otro.pdf")
Añade las páginas de otro PDF al final.
fix::merge_documents("anexos/certificado_de_garantia.pdf")
fix::merge_documents("anexos/tabla_de_medidas.pdf")
8.4 Contenido
fix::add_watermark("texto")
Marca de agua diagonal gris, en todas las páginas.
fix::add_watermark("BORRADOR — NO IMPRIMIR")
fix::add_stamps("texto")
Sello en rojo en la esquina superior derecha de cada página.
fix::add_stamps("APROBADO 02/08/2026")
fix::add_page_numbers()
Numeración n / total en el pie de cada página.
fix::add_page_numbers()
fix::remove_annotations() y fix::remove_attachments()
Eliminan las anotaciones (comentarios, marcas de revisión) y los archivos adjuntos.
// Antes de mandarlo a la imprenta: los comentarios de revisión no pueden
// aparecer, y los adjuntos solo engordan el archivo
fix::remove_annotations()
fix::remove_attachments()
fix::flatten_layers()
Elimina la estructura de capas opcionales (OCG) y deja todo el contenido permanentemente visible.
// Las capas con la "versión en inglés" apagada pueden reactivarse por error
// en la imprenta; aplanarlas elimina el riesgo
fix::flatten_layers()
8.5 Optimización
Las operaciones de esta sección solo guardan si el archivo encoge. Si la reescritura da un archivo mayor, se conserva el original.
fix::remove_unused_resources()
Descarta los objetos a los que no se llega desde el tráiler.
fix::remove_unused_resources()
fix::downsample_images([dpi])
Remuestrea las imágenes por encima del DPI objetivo (300 por defecto). El DPI se calcula por el tamaño impreso real de la imagen en la página.
// La versión para aprobación por correo no necesita 300 DPI
fix::downsample_images(96)
// Versión para impresión digital
fix::downsample_images(200)
Las imágenes CMYK se conservan. Remuestrearlas exigiría convertirlas a RGB, lo que destruiría las separaciones de preimpresión. En archivos de imprenta, la ganancia viene de las imágenes RGB.
fix::compress_images([calidad])
Recodifica las imágenes en JPEG con la calidad indicada (de 1 a 100, 85 por defecto).
fix::compress_images(70)
No disponibles
subset_fonts y linearize_document no existen como operaciones de fix::
y dan error de función desconocida:
- subset_fonts: se implementó y se midió. Los generadores profesionales ya
incrustan solo los glifos usados, así que la ganancia medida fue del 0,5% en
el mejor caso y nula en el resto: no compensa el riesgo de corromper fuentes.
Para comprobar si las fuentes están en subconjunto, usa
prepress::subset_fonts(). - linearize_document: exige generar hint tables (§7.14 de la especificación PDF). Ninguna biblioteca de Rust lo hace, y una versión parcial no la reconocerían los lectores como «Fast Web View».
8.6 Ejemplos completos
Preparar el archivo de la editorial para la imprenta
// preparar_para_imprenta.pdfl
// Uso: pdfl fix editorial.pdf preparar_para_imprenta.pdfl --output imprenta.pdf
check "Precondiciones" {
require doc.page_count > 0
assert !struct::check_encryption(),
"archivo cifrado — pide la versión abierta a la editorial"
}
// Cajas de producción que la editorial no definió
fix::set_trim_box(8.5, 8.5, 586.5, 833.5)
fix::set_bleed_box(0, 0, 595, 842)
// Limpieza: los comentarios de revisión y los adjuntos no van a imprenta
fix::remove_annotations()
fix::remove_attachments()
fix::flatten_layers()
fix::remove_unused_resources()
Versión ligera para aprobación por correo
// version_correo.pdfl
// Uso: pdfl fix final.pdf version_correo.pdfl --output aprobacion.pdf
fix::downsample_images(96)
fix::compress_images(70)
fix::add_watermark("PRUEBA — NO ES LA VERSIÓN FINAL")
fix::add_page_numbers()
Comprobando el resultado con el propio pdfl:
pdfl fix final.pdf version_correo.pdfl --output aprobacion.pdf
pdfl inspect aprobacion.pdf # tamaño, DPI y avisos del archivo generado
Separar un libro en cubierta e interior
// separar.pdfl
// Uso: pdfl fix libro.pdf separar.pdfl --output libro_procesado.pdf
check "Estructura esperada" {
assert doc.page_count > 4,
"libro con solo #{doc.page_count} páginas — estructura inesperada"
}
fix::split_document(1, 2, "salida/cubierta.pdf")
fix::split_document(3, doc.page_count, "salida/interior.pdf")