programmazione,

Programmare l'inutilità

Sabino Maggi Sabino Maggi Segui 23-Nov-2015 · 13 minuti di lettura
Condividi

Come tanti ricevo ogni giorno una o più email che mi propongono di visitare questo o quel sito. Non è sempre tempo perso, spesso si trovano delle vere e proprie gemme.

Altre volte però scopro siti o applicazioni la cui utilità è perlomeno dubbia.

img2css

La palma del programma più inutile degli ultimi mesi vorrei assegnarla a img2css, una applicazione web scritta in JavaScript che converte una immagine bitmap (in formato png, jpg o simili) in un file CSS, che può qundi essere inserito direttamente in una pagina web.

In teoria l’idea è ottima, perché permette di integrare un’immagine in una pagina web senza bisogno di collegamenti a file esterni, ma nella pratica fallisce miseramente.

Anche con immagini semplicissime il file CSS generato diventa di dimensioni abnormi, ed è molto più pesante da gestire e da trasmettere in rete rispetto all’immagine originale.

Proviamo img2css

Proviamo ad usare img2css con una immagine semplicissima composta da un quadrato di 10x10 pixel con bordo nero e interno bianco. L’immagine si può creare da Terminale tramite convert, uno dei comandi più potenti di ImageMagick, in grado non solo (come dice il nome) di convertire le immagini da un formato grafico all’altro, ma anche di generare delle immagini ex-novo in praticamente qualunque formato conosciuto.

Il comando

	$ convert -size 10x10 xc:white -fill white \
	-stroke black -draw "rectangle 0,0 9,9" square_10x10.png

produce l’immagine square_10x10, che occupa esattamente 127 byte (per maggiore chiarezza l’immagine è visualizzata al doppio della dimensione originale).

Convertendo l’immagine con img2css, il codice CSS corrispondente

<div style="height:1px;width:1px;box-shadow:#000 0 0, #000 1px 0, #000 2px 0, #000 3px 0, #000 4px 0, #000 5px 0, #000 6px 0, #000 7px 0, #000 8px 0, #000 9px 0, #000 0 1px, #000 1px 1px, #000 2px 1px, #000 3px 1px, #000 4px 1px, #000 5px 1px, #000 6px 1px, #000 7px 1px, #000 8px 1px, #000 9px 1px, #000 0 2px, #000 1px 2px, #fff 2px 2px, #fff 3px 2px, #fff 4px 2px, #fff 5px 2px, #fff 6px 2px, #fff 7px 2px, #000 8px 2px, #000 9px 2px, #000 0 3px, #000 1px 3px, #fff 2px 3px, #fff 3px 3px, #fff 4px 3px, #fff 5px 3px, #fff 6px 3px, #fff 7px 3px, #000 8px 3px, #000 9px 3px, #000 0 4px, #000 1px 4px, #fff 2px 4px, #fff 3px 4px, #fff 4px 4px, #fff 5px 4px, #fff 6px 4px, #fff 7px 4px, #000 8px 4px, #000 9px 4px, #000 0 5px, #000 1px 5px, #fff 2px 5px, #fff 3px 5px, #fff 4px 5px, #fff 5px 5px, #fff 6px 5px, #fff 7px 5px, #000 8px 5px, #000 9px 5px, #000 0 6px, #000 1px 6px, #fff 2px 6px, #fff 3px 6px, #fff 4px 6px, #fff 5px 6px, #fff 6px 6px, #fff 7px 6px, #000 8px 6px, #000 9px 6px, #000 0 7px, #000 1px 7px, #fff 2px 7px, #fff 3px 7px, #fff 4px 7px, #fff 5px 7px, #fff 6px 7px, #fff 7px 7px, #000 8px 7px, #000 9px 7px, #000 0 8px, #000 1px 8px, #000 2px 8px, #000 3px 8px, #000 4px 8px, #000 5px 8px, #000 6px 8px, #000 7px 8px, #000 8px 8px, #000 9px 8px, #000 0 9px, #000 1px 9px, #000 2px 9px, #000 3px 9px, #000 4px 9px, #000 5px 9px, #000 6px 9px, #000 7px 9px, #000 8px 9px, #000 9px 9px;"></div>

occupa 1259 byte, circa 10 volte in più del file png di partenza. Le cose peggiorano rapidamente se si usano immagini più complesse. Questa immagine da 20x20 pixel concentric_color, composta da alcuni rettangoli concentrici colorati e generata tramite

$ convert -size 20x20 xc:white -fill white \
-stroke black  -draw "rectangle 0,0 19,19" \
-stroke red    -draw "rectangle 2,2 17,17" \
-stroke green  -draw "rectangle 4,4 15,15" \
-stroke blue   -draw "rectangle 6,6 13,13" \
-stroke yellow -draw "rectangle 8,8 11,11" concentric_color.png

occupa solo 481 byte in formato png, che diventano ben 6.491 byte quando di converte l’immagine in CSS con img2css.

Con immagini reali a colori, o peggio ancora fotografie (ad esempio questa), le immagini CSS possono diventare anche 150-200 volte più grandi di quella originale, mettendo in ginocchio il browser (e il computer!) durante il processo di conversione o quando si copia il file CSS ottenuto in una pagina web.

Provare per credere, ma se poi il Mac si pianta non prendetevela con me.

Dentro il codice

Il programma img2css è molto semplice ed è composto poche centinaia di linee di codice JavaScript. Ma è perfino troppo lungo per quello che fa.

In fondo si tratta solo di determinare il codice RGB di ogni pixel dell’immagine, convertirlo in formato esadecimale ed associarlo alle coordinate orizzonantali e verticali del pixel considerato.

Ogni pixel viene quindi convertito nella sequenza #AAA Xpx Ypx, dove #AAA indica il colore in esadecimale (la stringa può essere composta da 3 o 6 numeri a seconda del colore RGB determinato) e Xpx Ypx indicano le coordinate orizzonantali e verticali del pixel.

Tutto questo si può fare tranquillamente da Terminale, con poche righe di codice ben piazzate.

img2css da Terminale

Per convertire un file grafico in una sequenza di colori RGB si può usare ancora convert di ImageMagick,

$ convert square_10x10.png -compress none square_10x10.ppm

ottenendo un file in formato ppm, in cui ciascun pixel dell’immagine è rappresentato da tre numeri interi decimali, corrispondenti ai tre colori RGB del pixel stesso (il formato grafico ppm è molto inefficiente, ma è utilissimo dal punto di vista didattico perché mostra chiaramente come è fatto un file grafico).

Le sequenze di tre numeri decimali sono disposte per righe orizzontali a partire dalla quarta riga del file. Le prime tre righe contengono rispettivamente il numero magico che definisce il tipo di file, le dimensioni dell’immagine in pixel e il valore massimo del colore RGB del file.

La rappresentazione in formato ppm del quadrato di 10x10 pixel con bordo nero e interno bianco mostrato sopra è

P3
10 10
255
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

Sequenze di dati come questa possono essere facilmente analizzate e trasformate tramite awk, uno dei tanti potenti strumenti specifici disponibili nei sistemi operativi basati su Unix.

Basta uno script awk di poche righe per convertire le informazioni RGB decimali contenute nel file ppm in formato esadecimale

#!/usr/bin/awk -f

/^255/  { while (getline == 1)
          { for (i = 1; i <= NF; i += 3)
              printf "0x%02X%02X%02X ", $i, $(i+1), $(i+2);
              printf "\n"
          }
        }

Eseguendo lo script img2css.awk sul file ppm precedente si ottiene

$ ./img2css.awk square_10x10.ppm 
0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 
0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0xFFFFFF 0x000000 0x000000 
0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 
0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 0x000000 

Per riprodurre l’output prodotto da img2css, è sufficiente modificare leggermente il modo in cui lo script stampa i valori dei colori RGB, aggiungere la stampa della le coordinate di ciascun pixel e inserire le parti iniziali e finali del tag <div>, ottenendo

#!/usr/bin/awk -f

BEGIN   { out = sprintf("<div></div>");
          print out;
        }

che produce un output equivalente a quello di img2css

$ ./img2css_v2.awk square_10x10.ppm
<div style="height:1px;width:1px;box-shadow:#000000 0 0px, #000000 1px 0px, #000000 2px 0px, #000000 3px 0px, #000000 4px 0px, #000000 5px 0px, #000000 6px 0px, #000000 7px 0px, #000000 8px 0px, #000000 9px 0px, #000000 0 1px, #000000 1px 1px, #000000 2px 1px, #000000 3px 1px, #000000 4px 1px, #000000 5px 1px, #000000 6px 1px, #000000 7px 1px, #000000 8px 1px, #000000 9px 1px, #000000 0 2px, #000000 1px 2px, #FFFFFF 2px 2px, #FFFFFF 3px 2px, #FFFFFF 4px 2px, #FFFFFF 5px 2px, #FFFFFF 6px 2px, #FFFFFF 7px 2px, #000000 8px 2px, #000000 9px 2px, #000000 0 3px, #000000 1px 3px, #FFFFFF 2px 3px, #FFFFFF 3px 3px, #FFFFFF 4px 3px, #FFFFFF 5px 3px, #FFFFFF 6px 3px, #FFFFFF 7px 3px, #000000 8px 3px, #000000 9px 3px, #000000 0 4px, #000000 1px 4px, #FFFFFF 2px 4px, #FFFFFF 3px 4px, #FFFFFF 4px 4px, #FFFFFF 5px 4px, #FFFFFF 6px 4px, #FFFFFF 7px 4px, #000000 8px 4px, #000000 9px 4px, #000000 0 5px, #000000 1px 5px, #FFFFFF 2px 5px, #FFFFFF 3px 5px, #FFFFFF 4px 5px, #FFFFFF 5px 5px, #FFFFFF 6px 5px, #FFFFFF 7px 5px, #000000 8px 5px, #000000 9px 5px, #000000 0 6px, #000000 1px 6px, #FFFFFF 2px 6px, #FFFFFF 3px 6px, #FFFFFF 4px 6px, #FFFFFF 5px 6px, #FFFFFF 6px 6px, #FFFFFF 7px 6px, #000000 8px 6px, #000000 9px 6px, #000000 0 7px, #000000 1px 7px, #FFFFFF 2px 7px, #FFFFFF 3px 7px, #FFFFFF 4px 7px, #FFFFFF 5px 7px, #FFFFFF 6px 7px, #FFFFFF 7px 7px, #000000 8px 7px, #000000 9px 7px, #000000 0 8px, #000000 1px 8px, #000000 2px 8px, #000000 3px 8px, #000000 4px 8px, #000000 5px 8px, #000000 6px 8px, #000000 7px 8px, #000000 8px 8px, #000000 9px 8px, #000000 0 9px, #000000 1px 9px, #000000 2px 9px, #000000 3px 9px, #000000 4px 9px, #000000 5px 9px, #000000 6px 9px, #000000 7px 9px, #000000 8px 9px, #000000 9px 9px;"></div>

perfettamente funzionante, come si può verificare inserendo pari pari il tag <div> ottenuto in un documento html (come questo):

Conclusioni

È chiaro che usare convert ed awk non risolve il problema di fondo, le immagini CSS generate rimangono comunque molto più grosse di quelle originali, ma almeno sono prodotte con poche righe di codice ed usando solo degli strumenti standard di Unix.

Alcuni anni fa si parlava in senso negativo di bloatware, di quei programmi inutilmente grossi e tanto poco ottimizzati da richiedere grosse risorse hardware anche per svolgere funzioni relativamente semplici.

A volte i programmatori dimenticano due concetti fondamentali della buona programmazione, cercare la semplicità e usare lo strumento più adatto per il compito specifico, e si perdono in inutili (e stucchevoli) esercitazioni di stile. Succede a chi propone banalmente di usare file CSS enormi al posto di semplici immagini grafiche, ma succede anche in tanti altri casi ben peggiori.

A parte questo, il post è stato anche un’occasione per parlare di awk, uno strumento poco conosciuto ma molto otente, in particolare quando si tratta di analizzare e trasformare dati contenuti in file di testo.

Uno strumento che è diventato parte integrante da anni della mia routine di lavoro quotidiana. Sarebbe bello poterne riparlare.

Sabino Maggi
Pubblicato da Sabino Maggi Segui
Commenti

Aggiungi un commento