Anteprime, decompressione LZW e contenuto dei disegni

Aggiunge tre capacita' al lettore, tutte senza dipendenze esterne.

Anteprima incorporata (preview.py)
    Ogni file contiene una miniatura JPEG dell'ultimo salvataggio: il
    render del pezzo nei modelli, l'immagine della tavola nei disegni.
    Non e' referenziata dall'indice, quindi va cercata per firma: ogni
    candidato viene validato percorrendone i segmenti JPEG, cosi' i byte
    che iniziano per FFD8FF per caso non passano. Sui file campione il
    risultato e' esattamente una immagine per file.

Decompressione compress(1) (lzw.py)
    Creo comprime alcuni blocchi nel vecchio formato .Z. Rispetto a un
    LZW generico va riprodotto l'allineamento a gruppi di otto codici:
    senza, la decompressione produce qualche centinaio di byte corretti
    e poi diverge silenziosamente.

Contenuto dei disegni (drawing.py)
    Un .drw non ha la tabella parametri del modello ma contiene la
    rappresentazione vettoriale della tavola. Ne estraiamo i testi:
    cartiglio, note, tolleranze, quote. Le tavole diventano cosi'
    ricercabili per contenuto. Nel disegno i valori compaiono gia'
    risolti come testo, compreso il peso, mentre nel .prt sono ancora
    in codifica binaria.

I blocchi oltre l'indice sono ora interpretati da ugc.iter_blocks, che
decomprime quando serve: lo stesso blocco puo' essere memorizzato
compresso in un file e in chiaro in un altro, quindi la scelta va fatta
guardando i byte e non il nome. Cercare soltanto gli stream compressi
faceva perdere i testi su un terzo dei disegni.

Sulla codifica dei numeri: sono double IEEE big-endian con i byte bassi
omessi, preceduti da un byte-tag. Lo dimostrano i disegni, dove size_x e
size_y valgono 420,0 x 297,0 (un A3 esatto). La mappatura del byte-tag
resta pero' incerta, quindi PESO e DENSITA continuano a essere riportati
come encoded_not_decoded: un valore plausibile ma sbagliato sarebbe
peggio di un valore assente.

La geometria 3D resta fuori portata, e ora e' verificato: in 200 KB di
blocchi geometrici non compare una sola costante 1.0 in nessuna codifica
in virgola mobile. Quei blocchi sono compressi con un algoritmo che non
espone firme note.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-06 14:51:39 +02:00
co-authored by Claude Opus 5
parent bc84407a6f
commit b59380fcab
9 changed files with 648 additions and 22 deletions
+84 -15
View File
@@ -37,6 +37,7 @@ Opzioni principali:
| `--all-versions` | elabora tutte le versioni (`.prt.1`, `.prt.2`, …) invece della sola più recente |
| `--features` | include i parametri delle feature (fori, lavorazioni) oltre a quelli di modello |
| `--system` | include i parametri generati da Creo (`PTC_*`, `SMT_*`) |
| `--preview [DEST]` | salva l'anteprima incorporata come JPEG |
| `--quiet` | non stampa la tabella |
Codici di uscita: `0` estrazione riuscita, `1` nessun file trovato, `2` nessun
@@ -48,6 +49,63 @@ spazio = confermato in due rappresentazioni indipendenti, `?` = trovato una
volta sola, `~` = valore binario non decodificato, `!` = valori discordanti,
`-` = parametro atteso ma assente.
## Anteprima incorporata
Ogni file contiene una miniatura JPEG dell'ultimo salvataggio: il render
ombreggiato del pezzo nei modelli, l'immagine della tavola nei disegni. È la
stessa che Creo mostra nella finestra "Apri".
```bash
python3 -m creoparams 9258400201.prt.12 --preview # accanto all'originale
python3 -m creoparams 9258400201.prt.12 --preview foto.jpg # nome esplicito
python3 -m creoparams . --preview anteprime/ # tutte in una cartella
```
Le dimensioni compaiono nell'intestazione della tabella e in `preview` nel
JSON; i byte dell'immagine restano fuori dal record, si ottengono con
`read_preview()`.
La miniatura non è referenziata dall'indice delle sezioni, quindi va cercata
per firma. Per non scambiare dati binari qualsiasi per un'immagine, ogni
candidato viene validato percorrendone i segmenti JPEG: sui file campione
questo produce esattamente un risultato per file, e il test
`test_una_sola_anteprima_per_file` lo verifica.
Attenzione: l'anteprima fotografa **l'ultimo salvataggio**, non lo stato
corrente del modello. Se un pezzo è stato modificato e salvato da un CAD che
non rigenera la miniatura, l'immagine può essere più vecchia dei parametri.
## Contenuto dei disegni (`.drw`)
Un disegno non contiene la tabella parametri del modello, ma contiene la
**rappresentazione vettoriale della tavola**, in blocchi compressi con
`compress(1)` (il vecchio `.Z` Unix). Il programma li decomprime ed estrae
tutti i testi:
```bash
python3 -m creoparams 9258400205.drw.10
```
```
118 testi nella tavola (68 unici). I parametri del modello stanno nel .prt.
CODICE ... STAMPIGLIATURA ... PESO FINITO ... DISEGNATO ... SCALA
9258400205 ... 0.197 ... 9/02/2026 ... 1:2 ... Grilli
```
Questo rende le tavole **ricercabili per contenuto**: voci del cartiglio,
note, tolleranze, quote. Da notare che nel disegno i valori compaiono
**già risolti come testo** — compreso il peso — mentre nel `.prt` sono
numeri in codifica binaria.
Attenzione: i testi sono estratti in ordine di comparsa, **non associati
alla rispettiva etichetta**. Accoppiare `PESO FINITO` al suo valore richiede
le coordinate di ogni testo, che non sono ancora decodificate (vedi sotto).
Un disegno riporta inoltre lo stato all'ultima rigenerazione, non
necessariamente quello attuale del modello.
Nel JSON tutto questo sta sotto `drawing`, insieme all'elenco delle primitive
grafiche presenti (`prim_text`, `prim_arc`, `prim_multiline`, …).
## Come funziona
Un file nativo Creo è un container con header ASCII in chiaro, un indice delle
@@ -94,22 +152,30 @@ ancora al file da cui proviene.
## Limiti noti
**Parametri numerici non decodificati.** `PESO` e `DENSITA` usano una codifica
binaria a lunghezza variabile (78 byte osservati) che non è un double IEEE
lineare. Non vengono inventati valori: lo stato è `encoded_not_decoded` e i byte
grezzi sono conservati in `raw`, così da poter essere interpretati in seguito
senza rileggere l'archivio. Per decifrare la codifica servono alcuni valori di
riferimento letti da Creo.
**Parametri numerici non decodificati.** `PESO` e `DENSITA` restano
`encoded_not_decoded`, con i byte grezzi in `raw`. La codifica è però ora in
gran parte capita: sono **double IEEE big-endian con i byte bassi omessi**,
preceduti da un byte-tag. La prova viene dai disegni, dove `size_x` = `2f 7a 40`
e `size_y` = `2f 72 90` corrispondono a 420,0 × 297,0 — un A3 esatto — e dove
le coordinate di una polilinea danno differenze regolari (9,72 / 6,48: un
tratteggio). Applicando la stessa regola, `DENSITA` risulta **7,8e-06**, la
densità dell'acciaio, identica in tutti i file.
**Disegni.** I `.drw` vengono riconosciuti e ne viene letto l'header, ma non
contengono la tabella parametri del modello: espongono note e cartiglio, con una
struttura diversa non ancora implementata. Il campo `holds_model_parameters`
lo dichiara esplicitamente.
Quello che manca è la mappatura del byte-tag iniziale: sui pesi produce due
candidati, uno plausibile e uno assurdo, e su un file nessuno dei due convince.
Finché la regola non è certa il programma **non pubblica alcun valore**: un
peso plausibile ma sbagliato è peggio di un peso assente. Per chiudere servono
due o tre valori di `PESO` letti da Creo.
**Copertura verificata.** Il lettore è stato validato su file `PART` e
`PART/SHEETMETAL` scritti da **Creo 9.0.3.0**. Non è stato provato su assiemi,
family table, né su file di versioni Creo precedenti. Prima di usarlo
sull'archivio storico, va verificato su un campione di file più vecchi.
Nel frattempo i disegni offrono una via alternativa: nel `.drw` il peso compare
**già risolto come testo** nel cartiglio.
**Copertura verificata.** Il lettore è stato validato su file `PART`,
`PART/SHEETMETAL` e `DRAWING` scritti da **Creo 9.0.3.0**. Gli **assiemi
(`.asm`) non sono mai stati provati**: nessun file campione era disponibile.
Il codice li gestisce come i part, ma è una previsione, non una verifica.
Idem per family table e versioni Creo precedenti: prima di usare il lettore
sull'archivio storico va provato su un campione di file più vecchi.
**Family table.** Le istanze non hanno un file proprio: vivono nel generic. Su
un generic con family table il lettore restituirebbe i valori del generic, non
@@ -132,7 +198,10 @@ file con Creo.
| File | Contenuto |
|---|---|
| [creoparams/ugc.py](creoparams/ugc.py) | header e indice delle sezioni del container |
| [creoparams/ugc.py](creoparams/ugc.py) | header, indice delle sezioni e blocchi del container |
| [creoparams/params.py](creoparams/params.py) | riconoscimento dei record parametro nel binario |
| [creoparams/lzw.py](creoparams/lzw.py) | decompressione compress(1) dei blocchi interni |
| [creoparams/drawing.py](creoparams/drawing.py) | testi e primitive delle tavole |
| [creoparams/preview.py](creoparams/preview.py) | anteprima JPEG incorporata |
| [creoparams/extract.py](creoparams/extract.py) | aggregazione, confidenza, record di output |
| [creoparams/cli.py](creoparams/cli.py) | riga di comando ed esportazioni |