venerdì 24 marzo 2023 #

WPF ed i 0.01 DPI mancanti

Una caratteristica di WPF e' l'indipendenza dalla risoluzione, in particolare le immagini bitmap vengono automaticamente ridimensionate a 96 DPI, valore di default storico di Windows.

Un'immagine 512x512 pixel a 72 DPI verra' quindi ridimensionata a 682.5 x 682.5 pixel circa. Questo succedera' indipendentemente dai DPI impostati nel sistema.

Utilizzando software professionali di editing di immagini come Adobe Photoshop, Gimp, etc.. e' possibile salvare i nostri capolavori con una risoluzione DPI specifica. Questa informazione (DpiX e DpiY) non modifica di fatto la dimensione in pixel dell'immagine, ma e' un attributo che viene salvato nei metadati del file e che puo' essere per esempio utile in fase di stampa... e in WPF.

Soddisfatti della nostra creazione, impostiamo quindi 96 DPI, certi che la nostra immagine non verra' mai e poi mai ridimensionata, ed aggiungiamo il seguente codice XAML alla nostra pagina:


La nostra immagine e' stata inserita in un controllo Viewbox a scopo dimostrativo per evitare ridimensionamenti dovuti a limiti di spazio della Window, selezionando il controllo Image notiamo pero' qualcosa di strano nel pannello delle proprieta' di Visual Studio.


L'immagine e' stata ridimensionata da WPF! Il nostro castello di carte e' cascato dalle fondamenta, manca circa 0.1 pixel per lato!

Questo puo' essere un problema trascurabile dal punto di vista grafico e prestazionale, ma cerchiamo ad ogni modo di capire cosa sta succendo.

Eseguendo il seguente codice C#


scopriamo una triste realta' che stravolgera' presto tutte le nostre certezze. L'immagine e' di fatto a 96.01 DPI!

Adobe e' impazzita? un Easter Eggs di Gimp? Un complotto di Visual Studio?

Vediamo quindi di fare chiarezza, il formato PNG salva la risoluzione in un chunk chiamato Physical pixel dimensions (pHYs) composto da tre campi:

- Pixels per unit, x axis (4 bytes, unsigned integer)
- Pixels per unit, y axis (4 bytes, unsigned integer)
- Unit specifier (1 byte)

dove lo standard definisce come unita' valide solamente il metro o l'unita' indefinita. Il metro e' definito anche dal SI (Sistema Internazionale di unita' di misura), quindi a prima vista ha senso impiegarlo in uno standard al posto dei piedi o di altre unita' meno blasonate.

Utilizzando il metro stiamo quindi parlando di DPM (Dot per Meter). Un DPM equivale a 0.0254 DPI e sfortuna vuola che i campi prevedano solamente valori interi.

3779 DPM equivalgono a circa 95.99 DPI mentre 3780 a circa 96.01 DPI. Non esiste modo di specificare 96 DPI precisi, 0.01 DPI saranno sempre mancanti.

NB: Molti software arrotondano i valori di DPI visualizzati, prestare quindi sempre la massima attenzione.

Questo e' un bel dilemma per WPF, che di default usa proprio 96 DPI per le immagini, anche se a dire il vero non ho visto insurrezioni popolari in questi anni.

Un software utile per analizzare (e modificare) i metadati dei file PNG e' TweakPNG, dove a prima vista i nostri sogni di perfezione DPI-eggianti tornano, per poi svanire all'amara realta' con un doppio click.




NB: Questo problema non affligge il formato TIFF dove l'unita' di risoluzione puo' essere impostata in pollici (inch).

Per motivi di orgoglio piu' che tecnici non vogliamo pero' convertire tutte le nostre icone al formato TIFF, cosa possiamo dunque fare?

La matematica non lascio molto scampo, ma la fantasia ha ancora qualche carta da giocare.

Per risolvere il problema possiamo procedere in due modi:

- cancellare il chunk pHYs (che e' opzionale) se creato dall'app di editing grafico.

- impostare ad "unspecified units" l'unita' di misura. I valori X ed Y verranno ignorati.

Entrambe queste soluzioni forzeranno a 96 DPI esatti la risoluzione dell'immagine in WPF ed eviteranno qualsiasi ridimensionamente.

Personalmente preferisco utilizzare utility come PNGGauntlet che eliminano i chunk opzionali ed ottimizzano la dimensione del file (senza perdita di dati). Molto utile anche per evitare errori "App manifest references .. which is larger than the maximum image file size." durante il packaging di applicazioni UWP.

Avete mai notato che i 96 DPI esatti non esistono nei formati PNG e BMP? Dite la vostra nei commenti ed un saluto a tutti!

NB: Gli stessi concetti posso applicarsi ad altre tecnologie basate su XAML come ad esempio UWP

posted @ lunedì 1 gennaio 0001 00:00 | Feedback (3)