Patu

Un numero di qualità è una bugia: cosa misura ssimulacra2 al suo posto

Ogni encoder di immagini ha una manopola di qualità: -q 80, -quality 90, un cq-level. Sembra una promessa: portala a 80 e ogni immagine esce “buona all'80%”. Non è così. Il numero fissa un parametro di compressione, non un risultato, e il risultato dipende interamente dall’immagine.

Possiamo mostrare esattamente quanto mente.

La stessa impostazione, qualità radicalmente diversa

Abbiamo codificato 1.998 fotografie reali in JPEG con un -q 80 fisso (libjpeg-turbo) e valutato ciascuna con ssimulacra2, una metrica percettiva dove un valore più alto significa più vicino all’originale.

vips -q 80 su 1.998 foto ssimulacra2
immagine peggiore 58
percentile 10 74
mediana 77
percentile 90 80
immagine migliore 87

Un’unica impostazione. Uno scarto di 29 punti nella qualità reale. A -q 80, una foto esce a 58: visibilmente degradata, con blocchi e impasto, mentre un’altra arriva a 87, indistinguibile dalla fonte e con byte che non le servivano. Il numero sulla manopola non diceva nulla su nessuna delle due.

Peggiora tra un encoder e l’altro. -q 80 in JPEG non è -q 80 in WebP, né è cq-level 30 in AVIF: ogni scala è definita dal proprio encoder, quindi le stesse cifre significano cose diverse. Un numero di qualità non è nemmeno confrontabile con se stesso in uno strumento diverso.

Perché il contenuto di una foto decide la sua qualità

Un’impostazione di qualità sceglie con quale aggressività scartare il dettaglio. Un cielo piatto o un ritratto morbido hanno poco dettaglio da perdere, quindi le impostazioni aggressive fanno poco danno: il punteggio è alto. Una foto di fogliame, ghiaia o tessuto non è altro che dettaglio fine, quindi la stessa impostazione la distrugge: il punteggio è basso. L’encoder ha applicato la stessa regola identica; le immagini avevano quantità molto diverse da perdere.

Ecco perché “usa semplicemente qualità 80” ti consegna in silenzio due fallimenti insieme: alcune immagini degradate oltre il punto in cui un utente se ne accorge, e alcune immagini il 30% più grandi del necessario. Non lo vedi nelle impostazioni, solo nell’output.

Cosa usare come target al suo posto

Punta al risultato, non al parametro. ssimulacra2 è costruito per questo: è calibrato in unità di differenza percepita (all’incirca, “differenze appena percettibili” rispetto all’originale), quindi un punteggio target significa la stessa cosa su ogni immagine e in ogni formato.

Scegli un target, poi lascia che la qualità dell’encoder venga cercata immagine per immagine per raggiungerlo. La foto di fogliame riceve un’impostazione di qualità più alta perché ne ha bisogno; il cielo piatto ne riceve una più bassa perché può permetterselo. Ogni immagine arriva alla stessa qualità percepita, ciascuna con il minor numero di byte che la raggiungono. Nessuna immagine viene rovinata in silenzio, nessuna viene gonfiata in silenzio.

È ciò che fa Patu su ogni immagine: una ricerca per immagine sulla qualità dell’encoder per raggiungere un target ssimulacra2, invece di un -q fisso che significa qualcosa di diverso su ogni foto.

curl -X POST "https://patu.dev/v1/compress?target=85" \
  -H "X-Api-Key: $PATU_KEY" \
  --data-binary @photo.jpg -o photo.avif

La metrica fa il lavoro che un numero di qualità finge di fare: descrivere l’immagine che ottieni davvero.


Metodo e dati: l’harness di benchmark di Patu sulla categoria foto (1.998 fotografie reali); libjpeg-turbo tramite vips; valutato con ssimulacra2 tramite l’implementazione rust-av. I percentili riguardano tutte le immagini valutate con l’impostazione fissa.