Si può misurare con Python la larghezza di una scritta?

In Tkinter c’è una funzione che permette di misurare la larghezza di un testo. Peccato che il risultato non coincide necessariamente con quello che uno si aspetta. Il fatto è che qui stiamo entrando nel settore della misura del corpo del carattere, che è completamente incomprensibile ai non addetti ai lavori.

La teoria è semplice: nell’interprete di Python importiamo tkinter e il modulo font (Tkinter e TkFont, nelle vecchie versioni del linguaggio). Dopo avere creato una radice (tkinter.tk()), scegliamo il carattere (carattere=font.Font(Family=”Courier New”, size=96) e stampiamo la misura di un testo (ad esempio la scritta “Ciao”: print(carattere.measure(“Ciao”)).

Viene fuori un risultato, 308. Il problema è che io non so che farmene di questo numero. Nel senso che a occhio e croce dovrebbe essere una misura in punti tipografici. Visto che in informatica si usa il punto PostScript, da 0.352 millimetri circa, basterebbe moltiplicare per questa cifra il risultato ottenuto per avere la larghezza della scritta in millimetri. Quindi la parola “Ciao”, in un documento, dovrebbe essere larga 308*0.352= 108mm circa, ossia 10 cm e 8. In realtà in OpenOffice mi viene tra gli 8 e gli 8.2 cm.

Andiamo a vedere nel file: l’em è fissato a 2048 unità. L’altezza della x è 866 unità, pari al 42%. Se l’em coincide col corpo allora la x dovrebbe essere larga il 42% di 96 punti moltiplicato per 0,352. Cioè di 33,7. Quindi 14,1 mm.

Lo misuro rapidamente dentro OpenOffice e ottengo approssimativamente 14,2. Ci siamo quasi, il metodo è valido.

Il Courier è un monospace. Tutte le lettere hanno la stessa larghezza, e non c’è kerning. Ogni lettera è larga 1229 unità, ossia il 60% dell’em. Quindi la larghezza di una qualsiasi parola di 4 lettere sarebbe corpo*4*0,60. Ossia 81,1 mm. Che coincide con la misurazione che ho fatto prima.

Insomma, ragionando in punti, mi sarei aspettato che la funzione measure restituisse 230, non 308. Una discrepanza fin troppo consistente. Quale è il problema?

Una spiegazione chiara non l’ho trovata, però tra le discussioni non ufficiali ho trovato scritto che passando un valore positivo viene interpretato in punti, mentre in negativo sarebbero pixels. Perché mai punti e pixel dovrebbero avere proporzioni differenti non viene spiegato. Senonché, se quando vado a definire il carattere gli passo un valore negativo (carattere=font.Font(family="Courier New", size=-96)) incredibilmente la funzione measure mi restituisce il valore 232, ossia quasi il 230 che mi aspettavo io! Che sarebbe la misura giusta, se non fosse che ora tra le proprietà del carattere viene scritto size:72.

Proviamo a fare una prova in Times? Ok. Qui le lettere hanno larghezze diverse. La parola “Ciao” (nessun kerning scatta in questo caso) sarebbe lunga 3868 unità, ossia il 188% della em. Quindi scrivendo la parola “Ciao” in Times New Roman corpo 96 sarebbe larga 96*0,352*1,88=63,5 mm. Controllando visivamente in OpenOffice ci dovremmo essere. Adesso andiamo a eseguire la formula in Python. Col valore in positivo il risultato è 242 (che se fossero punti corrisponderebbe a 85 mm). Col valore in negativo (-96) il risultato è 182, ossia 64,0 ecc. Abbastanza vicino a quel risultato che avevo ottenuto io con parecchi arrotondamenti (evitando di arrotondare il rapporto tra le unità il risultato diventa 63,8, forse con la misura corretta del punto tipografico il gap si ridurrebbe ulteriormente).

Insomma la risposta alla domanda iniziale, se si può stimare la larghezza di un testo preciso in centimetri conoscendone il corpo e usando tkinter in python è: sì, ma a condizione di impostare il valore del corpo in negativo. Chissà perché.

Possibile che in positivo si ottengano i pixel? No. Ho fatto l’esperimento, sempre con Python (e la libreria PIL, stavolta): Scrivendo la parola “Ciao”, in Times New Roman 96, in un’immagine larga 242 pixel resta parecchio spazio dopo la o finale. Quando l’immagine è larga 182 pixel, la scritta ci entra giusta giusta. Insomma, anche per calcolare la larghezza di una scritta in pixel è fondamentale che il valore sia in negativo. E allora il valore positivo a cosa serve?

Commenti

Post più popolari