| name | siae-jasper-from-pdf |
| sdlc_phase | 4. Implementation |
| description | Use when reverse-engineering a PDF into a JasperReports JRXML template pixel-perfect. Iterazione automatica: estrae font, bbox, layout dal PDF, genera JRXML, renderizza, confronta pixel-per-pixel, corregge fino a soglia <2% diff. Trigger: "jrxml da pdf", "ricostruisci jasper", "pdf to jrxml", "genera template jasper", "replica pdf in jasper", "jasper from pdf", "crea jrxml dal pdf", "reverse engineering pdf jasper", "JasperReports da pdf".
|
SIAE Jasper From PDF — Ricostruzione JRXML da Reference PDF
+==============================================================+
| ███████╗██╗ █████╗ ███████╗ ██████╗ ███████╗██╗ ██╗ |
| ██╔════╝██║██╔══██╗██╔════╝ ██╔══██╗██╔════╝██║ ██║ |
| ███████╗██║███████║█████╗ ██║ ██║█████╗ ██║ ██║ |
| ╚════██║██║██╔══██║██╔══╝ ██║ ██║██╔══╝ ╚██╗ ██╔╝ |
| ███████║██║██║ ██║███████╗ ██████╔╝███████╗ ╚████╔╝ |
| ╚══════╝╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚══════╝ ╚═══╝ |
| Jasper From PDF |
| "Il codice si forgia. Il developer cresce." |
+==============================================================+
Tipo: Rigid | Fase SDLC: 4. Implementation
Panoramica
Reverse-engineering di template JasperReports (JRXML) da PDF di riferimento. Usa pdfplumber come strumento primario per estrarre coordinate, font, colori, rettangoli con precisione sub-punto. Itera automaticamente con convergenza pixel-per-pixel.
Principio fondamentale: Il PDF reference e' la verita'. Misura, non stimare. Itera fino a convergenza.
LA LEGGE DI FERRO
IL PDF DI RIFERIMENTO E' LA VERITA' ASSOLUTA. OGNI PIXEL CONTA.
Violare la lettera di questa regola significa violare lo spirito della regola.
Stai per dichiarare "fatto" o "completato"?
Hai evidenza numerica dal pixel-diff (< 2% per OGNI pagina)?
- NO → FERMATI. Torna al loop di convergenza (Fase 3).
- SI → Procedi alla validazione finale (Fase 4).
Stai pensando "e' abbastanza simile", "il diff e' trascurabile", "solo il footer e' diverso"?
Stai razionalizzando. Il PDF reference e' l'unica verita'. Misura, non stimare.
ZERO ASSUNZIONI: estrai TUTTO dal PDF (font, coordinate, colori, dimensioni).
NON indovinare font sizes, NON stimare posizioni, NON approssimare larghezze.
Ogni valore nel JRXML deve essere DERIVATO da una misurazione oggettiva del PDF
(pdfplumber chars, rects, curves, images).
ITERA FINO AL RAGGIUNGIMENTO. Non fermarti a "abbastanza simile".
Se una iterazione non migliora il diff, CAMBIA STRATEGIA, non ripetere lo stesso approccio.
Quando si Applica
Sempre:
- L'utente fornisce un PDF di riferimento e chiede di generare JRXML
- L'utente ha JRXML esistenti da allineare a un PDF reference
- Qualsiasi richiesta di reverse-engineering PDF → JasperReports
NON usare se:
- Il target non e' JRXML/JasperReports
- Il PDF e' protetto/crittografato
- L'utente chiede solo un'analisi del PDF senza generazione JRXML
Istruzioni
FASE 0 — Setup Ambiente e Dipendenze
QUESTA FASE E' BLOCCANTE. Se una dipendenza critica non si installa, FERMA TUTTO e segnala
all'utente con il messaggio esplicito dalla tabella sotto. NON procedere alla Fase 1 senza
aver verificato TUTTE le dipendenze.
Step 0.1 — Verifica dipendenze di sistema
Esegui TUTTI questi check in parallelo:
which java && java -version 2>&1 | head -1
which mvn && mvn -v 2>&1 | head -1
which pdftoppm && pdftoppm -v 2>&1 | head -1
which magick && magick -version 2>&1 | head -1
which xmllint
python3 --version 2>&1
Step 0.2 — Installa dipendenze mancanti (sistema) e Step 0.3 — Setup ambiente Python
Tabelle complete (dipendenze sistema + librerie Python, ruolo/criticità/
installazione/check/fallback) e Gestione Errori Installazione: vedi
references/dependencies.md.
Comandi rapidi:
brew install openjdk maven poppler imagemagick mupdf-tools
python3 -m venv tools/venv
tools/venv/bin/pip install pdfplumber pymupdf fonttools Pillow numpy scipy diff-pdf-visually
tools/venv/bin/python3 -c "import pdfplumber, fitz, numpy; from PIL import Image; print('OK')"
Se una dipendenza BLOCCANTE (Java, Maven, poppler, pdfplumber, pymupdf,
Pillow, numpy) non si installa → mostra il messaggio STOP esplicito da
references/dependencies.md e FERMA la skill. Se una dipendenza OPZIONALE
(ImageMagick, mupdf-tools, fonttools, scipy, diff-pdf-visually) non si
installa → mostra il messaggio DEGRADATO e continua.
Step 0.4 — Setup renderer JasperReports
-
Crea tools/renderer/pom.xml con dipendenze:
net.sf.jasperreports:jasperreports:6.21.3
org.apache.xmlgraphics:batik-bridge:1.17
org.apache.xmlgraphics:batik-transcoder:1.17
-
Scarica dipendenze: mvn -q dependency:copy-dependencies -DoutputDirectory=lib
-
Se Maven fallisce:
DEGRADATO: Maven dependency resolution fallita. Errore: {errore}.
Il rendering di test non sara' possibile in questa sessione.
Puoi comunque generare i JRXML e testarli su un ambiente con JasperReports.
Per fixare: verifica connessione internet e proxy Maven (~/.m2/settings.xml).
-
Crea tools/renderer/src/main/java/Renderer.java (compila JRXML, riempie parametri, esporta PDF)
-
Estrai font del reference e configura font extension:
pdffonts reference.pdf → identifica font usati
- Cerca font nel sistema (
/System/Library/Fonts/, /Library/Fonts/)
- Se
mutool disponibile: mutool extract reference.pdf per estrarre font embedded
- Crea
fonts/fonts.xml + fonts/jasperreports_extension.properties
-
Compila: javac -d classes -cp "lib/*" src/main/java/Renderer.java
FASE 1 — Analisi del PDF Reference con pdfplumber
Questo e' il passo piu' importante. Da qui derivano TUTTE le coordinate del JRXML.
Step 1.1 — Estrazione completa con pdfplumber
Per OGNI pagina del PDF, estrai:
import pdfplumber
pdf = pdfplumber.open("reference.pdf")
for page in pdf.pages:
page.chars
page.extract_words(extra_attrs=["fontname", "size"])
page.rects
page.curves
page.images
Output critico di questa fase:
- Font ESATTI:
{fontname: size} per ogni blocco di testo
- Coordinate ESATTE:
(x, y, width, height) per ogni elemento
- Colori ESATTI: fill e stroke per rettangoli e curve
- Dimensioni tabella: posizione separatori, larghezza colonne
Step 1.2 — Confronto metriche font (se fonttools disponibile)
from fontTools.ttLib import TTFont
Step 1.3 — Analisi complementare (poppler)
pdfinfo reference.pdf
pdffonts reference.pdf
pdftotext -layout ref.pdf
pdftoppm -r 150 -png ref.pdf out/ref
Il producer del PDF e' informazione critica:
Skia/PDF o Chrome → generato da browser, floor tecnico ~5-10% con JasperReports
iText o JasperReports → stesso engine, convergenza a <1% possibile
- Altro → valutare caso per caso
FASE 2 — Generazione JRXML basata su pdfplumber
Per OGNI pagina del PDF, genera il JRXML usando SOLO dati misurati:
-
Report setup:
- pageWidth/pageHeight da
pdfinfo
- margins = 0
- style default: fontName dal font piu' usato (da
page.chars)
-
Rettangoli e forme (da page.rects + page.curves):
- Per ogni rect con fill non-bianco →
<rectangle> con x, y, width, height, backcolor
- Per ogni curve con molti punti (>10) →
<rectangle radius="14"> (bordi arrotondati)
- Colori: converti da (r,g,b) float a hex
#RRGGBB
-
Blocchi di testo (da page.extract_words):
- Raggruppa parole per y-proximity (stessa riga) e fontname/size
- Per ogni blocco:
<staticText> o <textField> con:
- x, y = coordinate pdfplumber (arrotondati a int)
- width = xMax_blocco - xMin_blocco (+ padding 5pt)
- height = righe * line_height
- fontSize =
size da pdfplumber (ESATTO, non stimato)
- isBold = "Bold" in fontname
-
Tabelle (da pattern rects + words):
- Identifica separatori orizzontali (rects sottili, stessa y, fill grigio)
- Calcola colonne dalla x dei separatori verticali
<jr:table> con column widths = distanza tra separatori
-
Immagini (da page.images):
<image> con coordinate esatte da pdfplumber
FASE 3 — Loop di Convergenza
REPEAT:
1. Render JRXML → PDF (Renderer.java o fallback manuale)
2. Rasterizza output a 150dpi (pdftoppm)
3. Calcola pixel diff per pagina (threshold 30, Python + PIL)
4. SE diff < 2% per TUTTE le pagine → STOP (successo)
5. SE diff non migliora per 3 iterazioni consecutive → CAMBIA STRATEGIA
6. Analizza con pdfplumber ANCHE l'output corrente
7. Calcola delta per-elemento: pdfplumber(reference) vs pdfplumber(output)
8. Per ogni elemento con delta > 1pt:
a. Font size sbagliato? → Correggi con valore esatto da pdfplumber
b. Posizione Y sbagliata? → Applica offset dal delta
c. Posizione X sbagliata? → Correggi x nel reportElement
d. Width sbagliata (wrapping diverso)? → Correggi width
e. Testo troncato (height insufficiente)? → Aumenta height
f. Elemento mancante? → Aggiungi
9. Applica TUTTE le correzioni in un batch
10. GOTO 1
| 🟡 MEDIO (reversibile) — DevForge · siae-jasper-from-pdf |
|---|
Iterazione convergenza · diff pixel attuale: XX% → target: <2% |
| Azione: Applica N correzioni batch al JRXML |
| Se il diff aumenta: revert e analizza |
IRON RULE DEL LOOP:
- Ogni iterazione DEVE ridurre il diff OPPURE cambiare strategia
- Log il diff % ad ogni iterazione con tabella progressiva
- Se il diff AUMENTA → revert immediato e diagnosi
- Escalation a 10 iterazioni (vedi Strategie di Escalation). Hard stop a 20
FASE 4 — Validazione Finale
REQUIRED SUB-SKILL: siae-verification
xmllint --noout *.jrxml per validare XML
- Render con dati di test edge-case (nomi lunghi, importi grandi)
- Verifica
pdffonts output.pdf → font embedded
- Pixel-diff finale con evidenza numerica
- Report convergenza:
=== REPORT CONVERGENZA ===
Pagina 1: XX.XX% → YY.YY% (N iterazioni)
Pagina 2: XX.XX% → YY.YY% (N iterazioni)
Font: [lista font embedded]
Parametri: [lista parametri]
Producer reference: [Chrome/Jasper/altro]
Soglia raggiunta: SI/NO
Floor tecnico documentato: [se applicabile]
Tabella Anti-Razionalizzazione
| Pensiero | Realta' |
|---|
| "E' abbastanza simile" | "Abbastanza" non supera il gate del 2%. Misura. |
| "Solo il footer e' diverso" | Un footer diverso e' un pixel diff. Correggi. |
| "I font sono quasi uguali" | "Quasi" = hinting diverso = cascata di differenze. Usa il font esatto. |
| "Conosco gia' le coordinate" | Le conosci? pdfplumber le ha confermate? |
| "Una iterazione in piu' non serve" | Se il diff e' > 2%, serve. Non decidere tu, decide il numero. |
| "Stimo la font size a occhio" | L'occhio sbaglia di 1-2pt. pdfplumber no. |
| "Il rendering JasperReports non puo' fare meglio" | Documenta il floor tecnico con evidenza, non con opinione. |
| "Il PDF originale e' fatto male" | Il reference e' la verita'. Replica, non giudicare. |
| "Compilo e vedo se sembra ok" | "Sembra ok" non e' una metrica. pixel-diff lo e'. |
| "Manca poco, dichiaro completato" | <2% per OGNI pagina, o non e' completato. |
Classificazione Rischio Operazioni
| Operazione | Livello | Card |
|---|
| Lettura/analisi PDF reference | SICURO | No |
| Installazione brew packages | SICURO | No |
| Creazione venv Python + pip install | SICURO | No |
| Rasterizzazione PDF (pdftoppm) | SICURO | No |
| Creazione/modifica JRXML | SICURO | No |
| Rendering JRXML → PDF | SICURO | No |
| Pixel diff (Python/magick) | SICURO | No |
| Iterazione batch correzioni | MEDIO | Si |
| Copia font di sistema | MEDIO | Verifica licenza |
| Pubblicazione su repo | ALTO | Chiedi conferma |
Strategie di Escalation
Se dopo 10 iterazioni il diff e' ancora > 2%:
-
Floor tecnico engine diverso: se pdfinfo mostra producer Chrome/Skia/WeasyPrint:
- Il text shaper di JasperReports/iText (Java AWT) differisce da HarfBuzz/Skia
- Anche con font identici (verificato con fonttools), il posizionamento sub-pixel diverge
- Floor tipico: ~5-10% per pagine dense, ~3-5% per pagine semplici
- Azione: documenta con evidenza, proponi soglia alternativa
-
Fine-tuning per-elemento:
- Usa pdfplumber su ENTRAMBI i PDF (reference + output)
- Calcola delta per-parola (non per-blocco)
- Applica offset Y individuali per gli elementi con delta > 1pt
-
Cambio engine: se il reference e' HTML→PDF:
- Converti layout in HTML+CSS template
- Genera PDF con Puppeteer/Playwright (stesso engine del reference)
- Mantieni JRXML come fallback per sistemi JasperReports
Vincoli
- Font: usa SOLO font presenti nel sistema o embedded nel PDF reference. NON scaricare font da internet.
- Coordinate: SEMPRE in punti PDF (1pt = 1/72 inch). pdfplumber e JRXML usano la stessa unita'.
- PDF/A: disabilita per rendering di test. Riabilita nel JRXML finale se richiesto.
- Parametri: ogni valore dinamico →
$P{nome_parametro}.
- Encoding: UTF-8 everywhere. Identity-H per font CID TrueType.
- NO hallucination: se non riesci a estrarre un valore dal PDF, chiedi all'utente. NON inventare.
Strumenti
Tabelle Obbligatori/Opzionali (stesso contenuto di Step 0.2/0.3, vista
"strumento → uso/installazione/check") + Gestione Errori Installazione
(recovery pip/brew/Maven): vedi
references/dependencies.md.
Permission Denied Handling
Se l'utente nega un tool:
brew install negato → mostra comando esatto, chiedi di eseguire manualmente con ! brew install ...
pip install negato → mostra il pip install completo per copia manuale
- Rendering negato → fornisci i comandi esatti da eseguire fuori dalla sessione
- Scrittura file negata → mostra il contenuto JRXML per copia manuale