Skill PDF
Crea PDFs a partir de especificaciones estructuradas, construye y rellena formularios AcroForm (con validación de diseño y superposiciones visuales), extrae texto/tablas/metadatos, fusiona/divide/rota/marca de agua/sella páginas, exporta imágenes de páginas, gestiona metadatos y adjuntos, y cifra/descifra — usando pypdf, reportlab y pdfplumber. Dos capacidades adicionales están en references/ (lee el archivo correspondiente antes de esas tareas):
- PDFs escaneados/solo imagen y OCR (ruta rápida con pymupdf, ruta de calidad con marker-pdf, scripts/extract_pymupdf.py + scripts/extract_marker.py):
references/ocr-extraction.md - Editar texto dentro de un PDF existente mediante indicaciones en lenguaje natural (CLI nano-pdf):
references/nano-pdf-editing.md
Cuándo Usarlo
- Generar un informe, factura o documento de varias páginas como PDF.
- Construir un formulario AcroForm rellenable (texto/casilla de verificación/radio/desplegable) a partir de una especificación JSON, validando el diseño primero.
- Extraer texto, tablas (JSON/CSV), metadatos o valores de campos de formulario de un PDF.
- Fusionar, dividir, rotar, extraer subconjuntos de páginas, marcar de agua, sellar texto/imágenes en coordenadas, añadir marcadores o comprimir PDFs.
- Exportar páginas como PNG para revisión visual o para pasar a OCR; establecer/borrar metadatos del documento; añadir/extraer archivos adjuntos.
- Rellenar o aplanar formularios AcroForm; cifrar o descifrar con contraseñas.
- NO para PDFs escaneados/solo imagen (usa
references/ocr-extraction.md) y NO para renderización precisa de HTML a PDF (usa un navegador sin interfaz gráfica).
Prerrequisitos
- Python 3.10+ con
pypdf,reportlab,pdfplumber:python -m pip install pypdf reportlab pdfplumber - Opcional, para rasterización de páginas (
pdf_page_image.py, renderización de superposiciones):python -m pip install pypdfium2, o poppler conpdftoppmen PATH. Los scripts recurren a pypdfium2 → pdftoppm e informan{"rendered": false, "missing": [...]}(código de salida 0) cuando ninguno existe. - Cada script auxiliar verifica las importaciones de forma diferida e imprime una sugerencia de instalación si falta una dependencia.
Cómo Ejecutar
Todos los auxiliares están en scripts/ y son CLIs con argparse — ejecútalos con la herramienta terminal; todos soportan --help. Leen/escriben JSON estrictamente como UTF-8, imprimen resultados JSON en stdout y salen con código distinto de cero en caso de error.
python scripts/pdf_create.py spec.json -o out.pdf # construir PDF desde especificación JSON
python scripts/pdf_make_form.py formspec.json -o form.pdf # construir formulario AcroForm rellenable desde especificación JSON
python scripts/pdf_form_layout.py formspec.json # validar diseño del formulario ANTES de construir
python scripts/pdf_form_layout.py formspec.json --render-overlay boxes.png [--pdf form.pdf]
python scripts/pdf_read.py doc.pdf --text # texto por página (JSON)
python scripts/pdf_read.py doc.pdf --tables --csv-dir t/ # tablas a archivos JSON + CSV
python scripts/pdf_read.py doc.pdf --meta # metadatos, tamaños de página, indicadores de cifrado/escaneado
python scripts/pdf_read.py form.pdf --fields # campos del formulario: nombre, tipo, valor
python scripts/pdf_merge.py a.pdf b.pdf -o merged.pdf [--bookmarks]
python scripts/pdf_split.py doc.pdf --pages 1-3,7 -o part.pdf [--rotate 90]
python scripts/pdf_fill_form.py form.pdf --fields-json values.json -o filled.pdf [--flatten]
python scripts/pdf_secure.py doc.pdf --encrypt -o enc.pdf --user-password tu-contraseña
python scripts/pdf_secure.py enc.pdf --decrypt -o dec.pdf --password tu-contraseña
python scripts/pdf_watermark.py doc.pdf --stamp mark.pdf -o stamped.pdf [--under]
python scripts/pdf_stamp.py doc.pdf -o out.pdf --text "BORRADOR" --x 150 --y 400 \
--font-size 60 --rotation 45 --opacity 0.3 --color "#cc0000" [--pages 1-3]
python scripts/pdf_stamp.py doc.pdf -o out.pdf --image firma.png --x 400 --y 60 --width 120
python scripts/pdf_page_image.py doc.pdf --pages 1-3 --dpi 150 --out-dir imgs/
python scripts/pdf_meta.py doc.pdf --set-meta --title "T" --author "A" -o out.pdf
python scripts/pdf_meta.py doc.pdf --attach datos.csv -o out.pdf
python scripts/pdf_meta.py doc.pdf --list-attachments | --extract-attachments dir/
Referencia Rápida
| Tarea | Herramienta | Comando / API |
|---|---|---|
| Crear documento (encabezados, tablas, imágenes) | reportlab platypus | pdf_create.py spec.json -o out.pdf |
| Construir formulario rellenable | reportlab acroForm | pdf_make_form.py formspec.json -o form.pdf |
| Validar diseño del formulario / imagen de superposición | python puro + PIL | pdf_form_layout.py formspec.json [--render-overlay o.png] |
| Texto por página | pdfplumber | pdf_read.py f.pdf --text |
| Tablas → JSON/CSV | pdfplumber | pdf_read.py f.pdf --tables |
| Metadatos / tamaños / cifrado / escaneado | pypdf + pdfplumber | pdf_read.py f.pdf --meta |
| Fusionar (+ esquema) | pypdf | pdf_merge.py a.pdf b.pdf -o m.pdf |
| Dividir / extraer / rotar | pypdf | pdf_split.py f.pdf --pages 2-5 --rotate 90 |
| Listar / rellenar / aplanar formulario | pypdf | pdf_read.py --fields, pdf_fill_form.py |
| Cifrar / descifrar (AES-256) | pypdf | pdf_secure.py --encrypt/--decrypt |
| Marca de agua / sello en página PDF | pypdf | pdf_watermark.py f.pdf --stamp w.pdf |
| Sellar texto/imagen en coordenadas | reportlab + pypdf | pdf_stamp.py f.pdf --text "Firme aquí" --x 400 --y 60 |
| Páginas → PNG (revisión / paso a OCR) | pypdfium2 o pdftoppm | pdf_page_image.py f.pdf --pages 1-3 --out-dir imgs/ |
| Establecer/borrar metadatos, adjuntos | pypdf | pdf_meta.py --set-meta / --attach / --extract-attachments |
| Comprimir flujos de contenido | pypdf | pdf_split.py f.pdf --pages 1-N --compress |
Procedimiento
- Inspecciona primero. Ejecuta
pdf_read.py file.pdf --meta. Verificaencrypted(si es verdadero, descifra primero conpdf_secure.py --decrypt) ylikely_scanned_pages. Si las páginas son solo imagen, expórtalas conpdf_page_image.py --pages <escaneadas> --dpi 300 --out-dir imgs/y entrega los PNG al skillreferences/ocr-extraction.md— no informes texto vacío como "sin contenido". - Crear. Escribe una especificación JSON con
write_file(elementos:heading,paragraph,table,image,pagebreak; opcionalmente metadatostitle/author; los números de página se añaden automáticamente), luego ejecutapdf_create.py. Verifica visualmente convision_analyzeen una imagen de página renderizada si el diseño es importante. - Extraer.
--textda una lista JSON de cadenas por página;--tablesda arreglos de filas por página y también puede generar archivos CSV. Lee los resultados conread_file; nunca examines un PDF binario directamente. - Manipular.
pdf_merge.pyconcatena y puede añadir un marcador por archivo fuente;pdf_split.pymaneja rangos de páginas (base 1, ej.1-3,5,9-), rotación en pasos de 90°, y--compress. Aplica marca de agua preparando un PDF de sello de una página (ej. conpdf_create.py) y superponiéndolo conpdf_watermark.py; para sellos simples ("firme aquí", BORRADOR diagonal, etiquetas de esquina) usapdf_stamp.pycon texto o una imagen en coordenadas explícitas. - Construir formularios. Escribe un JSON de especificación de formulario (campos con
label_box/entry_boxen puntos PDF — consultareferences/forms.md), valídalo conpdf_form_layout.pyy corrige cada problema reportado, opcionalmente revisa el PNG--render-overlayconvision_analyze, luego construye conpdf_make_form.pyy confirma conpdf_read.py --fields. - Rellenar formularios. Lista los campos (
--fields) para conocer los nombres y tipos exactos, escribe un JSON UTF-8 de{"NombreCampo": "valor"}conwrite_file(las casillas de verificación aceptantrue/false; los valores de radio/opción deben coincidir con las opciones de exportación del campo), luego ejecutapdf_fill_form.py. Vuelve a leer con--fieldspara confirmar que los valores se aplicaron. - Metadatos y adjuntos.
pdf_meta.py --set-metaescribe Título/Autor/Asunto/PalabrasClave (DocInfo);--clear-metalos elimina;--attach/--list-attachments/--extract-attachmentsgestionan archivos incrustados. - Seguridad. Cifra con contraseñas de usuario y propietario distintas y AES-256. Para eliminar una contraseña conocida,
--decryptescribe una copia sin cifrar. - Verifica (ver abajo) antes de informar éxito.
Dificultades
- PDFs escaneados:
extract_text()vacío más imágenes de página significa que no hay capa de texto. Enruta areferences/ocr-extraction.md; no inventes texto. - Límites del aplanado:
pdf_fill_form.py --flattenusa el soporte de aplanado de pypdf, que convierte las apariencias de los widgets en contenido de página. Es fiable para campos de texto simples y casillas de verificación, pero puede eliminar o renderizar incorrectamente widgets exóticos (texto enriquecido, flujos de apariencia personalizados, algunos grupos de radio). Verifica la salida aplanada visualmente convision_analyze; para un aplanado a prueba de balas usa un renderizador externo (ej. Ghostscript opdftoppm+reensamblaje) como alternativa. - NeedAppearances: después de rellenar, los visores solo renderizan los valores si existen flujos de apariencia. El script de relleno establece la bandera
NeedAppearancesde AcroForm para que los visores conformes los regeneren; algunos visores mínimos la ignoran — aplanado si la fidelidad de visualización es importante. - Valores de formulario no latinos: los valores se almacenan correctamente (UTF-16), pero la fuente predeterminada del campo puede carecer de glifos, por lo que un visor puede mostrar espacios en blanco aunque los datos se conserven. Verifica con
--fields, no solo visualmente. - Expectativas de compresión:
--compresssolo desinfla los flujos de contenido. El ahorro típico es del 0 al 20%; no hace nada para PDFs dominados por imágenes o flujos ya comprimidos. No sustituye al submuestreo de imágenes (territorio de Ghostscript). - Las banderas de permiso no se aplican: los bits de permiso de la contraseña de propietario (sin imprimir, sin copiar) son solicitudes corteses que los visores pueden respetar; cualquier biblioteca (incluida pypdf) puede leerlos y eliminarlos. Solo la contraseña de usuario realmente protege el contenido mediante cifrado. Nunca presentes las banderas de permiso como seguridad.
- La extracción de tablas es heurística: pdfplumber detecta tablas a partir de líneas de regla/alineación de palabras; las tablas sin bordes o con celdas fusionadas pueden necesitar ajustes en
table_settingso limpieza manual. - Indexación de páginas: los CLIs auxiliares usan páginas base 1; las API de pypdf son base 0. Los scripts convierten — no conviertas dos veces.
- Extracción de texto de sellos rotados: la agrupación de líneas de pdfplumber desordena los glifos rotados (un "BORRADOR" a 45° se extrae como letras sueltas); verifica los sellos rotados con
extract_text()de pypdf o una imagen renderizada. - Grupos de radio: reportlab necesita ≥2 widgets
radio()por grupo, los rellenos necesitan el valor de exportación con barra ("/red"), y la fidelidad del aplanado es peor para radios — consultareferences/forms.md. - Alcance de metadatos:
pdf_meta.pyescribe solo el diccionario clásico DocInfo; los metadatos XMP incrustados (si los hay) quedan intactos y pueden mostrar valores diferentes en algunos visores. - PDF/A está fuera del alcance: pypdf/reportlab no pueden producir o validar PDF/A conforme. Si se requiere conformidad de archivo, ejecuta Ghostscript mediante la herramienta
terminal(ej.gs -dPDFA=2 -dPDFACompatibilityPolicy=1 -sColorConversionStrategy=UseDeviceIndependentColor -sDEVICE=pdfwrite -o out.pdf in.pdfcon un perfil ICC adecuado) y valida con veraPDF — ambas son instalaciones externas, y el resultado aún necesita validación, no suposición. - La rotación debe ser múltiplo de 90; las entradas cifradas deben descifrarse antes de cualquier otra operación.
Verificación
- Después de crear/fusionar/dividir:
pdf_read.py out.pdf --meta— confirmapage_count, yrotationpor página cuando hayas rotado. - Después de extraer: verifica que el JSON no esté vacío y comprueba una cadena o celda conocida.
- Bucle de diseño de formularios:
pdf_form_layout.py spec.jsondebe salir con código 0; luego--render-overlay boxes.png --pdf form.pdfy revisa el PNG convision_analyze(rojo = cuadros de entrada con nombres de campo, azul = cuadros de etiqueta) preguntando sobre superposiciones, desalineaciones y etiquetas separadas de sus campos. Itera especificación → validación → superposición hasta que esté limpio. - Después de construir un formulario:
pdf_read.py form.pdf --fieldslista cada campo de la especificación con el tipo y las opciones correctas. - Después de rellenar un formulario:
pdf_read.py filled.pdf --fieldsy compara los valores (coincidencia exacta, incluidos caracteres no ASCII). - Después de sellar: vuelve a extraer el texto (pypdf para sellos rotados) o renderiza la página con
pdf_page_image.pye inspecciona convision_analyze. - Después de ediciones de metadatos/adjuntos:
pdf_read.py --meta/pdf_meta.py --list-attachments, y vuelve a extraer un adjunto para comparar byte a byte. - Después de cifrar:
--metamuestra"encrypted": truey abrir sin contraseña falla; después de descifrar, la extracción de texto coincide con el original. - Para cualquier elemento visual (marcas de agua, formularios aplanados), renderiza e inspecciona con
vision_analyze.