Generatore di Data URI
Codifica un’immagine, un font o del testo come data: URI, oppure decodificane uno, con Base64 e codifica percentuale messi a confronto. Gira nel browser.
data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%232563eb'%20stroke-width='2'%3E%3Ccircle%20cx='12'%20cy='12'%20r='9'/%3E%3Cpath%20d='M8%2012.5l2.5%202.5%205-6'/%3E%3C/svg%3E
Qui la codifica percentuale è più corta: 255 caratteri contro 272, 17 risparmiati.
Dimensioni
- Byte sorgente
- 174
- URI, in Base64
- 272
- URI, con codifica percentuale
- 255
Un file dentro un indirizzo
Un data URI è un intero file scritto sotto forma di indirizzo. Invece di puntare a una risorsa che il browser deve andare a prendere, porta i byte stessi, così un’icona può vivere dentro il foglio di stile che la usa e una piccola immagine dentro l’HTML che la mostra. L’RFC 2397 ha definito lo schema nel 1998 ed è supportato ovunque da due decenni.
La grammatica è breve. Dopo lo schema arriva un tipo di media facoltativo con parametri facoltativi, poi un contrassegno base64 facoltativo, poi una virgola, poi i dati. Tutto ciò che precede la virgola è l’intestazione e tutto ciò che segue è il payload: ecco perché il browser divide alla prima virgola ed ecco perché una virgola dentro il payload è innocua.
data:[<mediatype>][;base64],<data> data:,hello text/plain;charset=US-ASCII data:text/plain;charset=utf-8,hello the same bytes, spelled out data:image/png;base64,iVBORw0KGgo= binary, Base64 encoded data:image/svg+xml,%3Csvg%20... markup, percent-encoded
Un’intestazione vuota è lecita e significa text/plain;charset=US-ASCII, l’unico valore predefinito che la specifica ti consegna. Questa pagina segnala di averlo applicato invece di mostrare un tipo di media che non hai mai scritto.
Due codifiche, e quale è più corta
L’RFC definisce due modi di scrivere il payload, e la scelta non è una questione di stile: per un dato file una delle due è nettamente più corta, e quale lo sia dipende interamente da che cosa contiene il file.
Base64 riscrive ogni tre byte come quattro caratteri di un alfabeto di 64. Il costo è fisso e prevedibile: esattamente un terzo in più, più il riempimento. Funziona con qualsiasi cosa, ed è per questo che è la forma a cui si ricorre per abitudine.
La codifica percentuale lascia intatto ogni carattere lecito in una URL e spende tre caratteri per ognuno degli altri. Con un payload fatto soprattutto di ASCII semplice — un SVG, un piccolo foglio di stile, un blocco JSON — la maggior parte dei byte passa intatta e il risultato esce più corto del Base64, spesso del venti o trenta per cento. Con un PNG o un font, dove quasi ogni byte va escapato, ci si avvicina al triplo dell’originale e va molto peggio del Base64.
Quanto escapare è a sua volta una decisione, e questa pagina offre entrambe le risposte:
- L’insieme rigoroso escapa ogni byte fuori dai caratteri non riservati dell’RFC 3986: lettere, cifre, trattino, punto, trattino basso e tilde. Il risultato è sicuro in qualunque contesto, al prezzo di escapare segni di punteggiatura che non ne avevano bisogno.
- L’insieme minimo conserva tutto ciò che la grammatica del data URI permette davvero, comprese le barre, i due punti, i segni di uguale, gli apici e le parentesi di cui il markup è pieno. È qui che la codifica percentuale vince, ed è per questo che un SVG scritto con apici singoli attorno agli attributi si codifica molto meglio di uno scritto con virgolette doppie.
- La destinazione aggiunge un’altra regola. Dentro un attributo HTML una e commerciale nuda avvia un riferimento a carattere, quindi scegliere la destinazione img escapa anche quella. Nient’altro cambia: le virgolette doppie, le parentesi angolari e la barra rovesciata sono già fuori dall’insieme permesso e vengono escapate a entrambi i livelli.
- Il segno di percentuale viene sempre escapato, a ogni livello. Introduce una sequenza di escape, quindi una percentuale letterale va scritta %25 o i due caratteri successivi vengono letti come esadecimali.
Invece di lasciarti indovinare, la pagina codifica il payload in entrambi i modi e riporta le due lunghezze e la differenza. Prendi quella che vince, oppure imposta la codifica a mano se hai un motivo.
Il 33% è un numero precedente alla compressione
Quasi ogni discussione sui data URI ripete che Base64 aggiunge un terzo alla dimensione del file. Aritmeticamente è vero e in pratica è fuorviante, perché quel numero descrive i byte prima che raggiungano la rete, e ogni server comprime il testo in uscita.
Base64 non aggiunge informazione; distribuisce la stessa informazione su più caratteri, usando solo 64 dei 256 valori che un byte può assumere. È esattamente il tipo di ridondanza che gzip e Brotli esistono per rimuovere. Su un payload già compresso — un PNG, un JPEG, un font WOFF2 — il compressore non può toccare i dati sottostanti ma può ricomprimere il Base64 fino a qualcosa di molto vicino alla dimensione originale. Il famoso terzo per lo più svanisce.
Perciò questa pagina misura invece di affermare. Comprime tre cose con l’implementazione gzip del browser stesso: il payload come verrebbe servito in un file separato, il documento che lo porta in Base64 e il documento che lo porta con codifica percentuale. Quei tre numeri sono la versione onesta dell’argomento della dimensione, e mostrano spesso che il vero costo dell’incorporazione non è affatto la dimensione.
I costi veri stanno altrove. Un file incorporato non può essere messo in cache per conto suo, quindi viene riscaricato con ogni copia del documento che lo porta e non sarà mai condiviso fra due pagine. Inoltre blocca: un foglio di stile non finisce di essere analizzato finché non ha letto per intero l’URI che gli sta in mezzo. HTTP/2 ha tolto quasi tutta la penalità per richiesta che rendeva attraente incorporare. Per un’icona minuscola presente in ogni pagina resta uno scambio ragionevole; oltre qualche decina di kilobyte di solito no, ed è per questo che questa pagina inizia ad avvisare a trenta.
Il tipo viene dai byte
Un data URI serve solo se il tipo di media è giusto. Sbaglialo e il browser rifiuterà di mostrare l’immagine, applicherà il parser sbagliato oppure — per qualsiasi cosa servita con un tipo che non riconosce — proporrà invece un download.
Quando trascini dentro un file, il browser dichiara un tipo tutto suo, ma quella dichiarazione deriva dall’estensione del file e da nient’altro. Rinomina un JPEG in .png e il browser lo chiamerà PNG. Questa pagina legge invece i primi byte. Quasi ogni formato binario comincia con una firma: PNG inizia con un byte che non può comparire in ASCII seguito dalle lettere PNG, JPEG con tre byte fissi, PDF con un segno di percentuale e la parola PDF, WOFF e WOFF2 con le loro etichette di quattro caratteri. Quando firma ed estensione non concordano, vince la firma e la discordanza viene segnalata.
L’elenco è deliberatamente corto: i formati che la gente incorpora davvero, non tutto ciò che un browser sa fiutare. Se non corrisponde nulla e i byte sono testo valido, il tipo è testo, distinguendo SVG e XML da come apre il markup. Se non corrisponde proprio niente la risposta è application/octet-stream, e il campo resta modificabile, perché un’ipotesi sbagliata è peggio di una ammessa.
Per i payload testuali conta anche il set di caratteri. Il valore predefinito della specifica è US-ASCII, che oggi non è ciò che intende nessuno, perciò un tipo di media testuale viene proposto con charset=utf-8 allegato. Ometterlo non corrompe i byte, ma cambia come vengono riletti.
Rileggerne uno
L’altra metà del lavoro capita più spesso: hai trovato un data: URI in un foglio di stile, in un dump del DOM o in una pagina salvata e vuoi sapere che cos’è. Incollalo e la pagina lo smonta: il tipo di media, i suoi parametri, quale codifica è stata usata, a quanti byte si decodifica rispetto a quanti caratteri costa, e che cosa sono quei byte indipendentemente da ciò che dichiara l’intestazione. Un’immagine viene disegnata, il testo viene mostrato, tutto il resto riceve i suoi primi byte in esadecimale.
La decodifica è severa, perché un URI incollato è input non fidato e una risposta plausibile ma sbagliata è peggio di un errore. Una virgola mancante, un tipo di media malformato, un segno di percentuale non seguito da due cifre esadecimali, un carattere fuori dall’alfabeto Base64: ognuno fallisce indicando la posizione del problema invece di essere riparato in silenzio.
Due cose sono tollerate, perché le tollera ogni browser e perché un URI copiato da un foglio di stile mandato a capo sarebbe altrimenti inutilizzabile. Gli spazi dentro il payload vengono rimossi e il riempimento Base64 mancante viene aggiunto. Entrambe vengono segnalate, così sai che l’URI che hai non è esattamente l’URI che funziona ovunque.
Una cosa che gli somiglia viene rifiutata subito. L’alfabeto Base64 sicuro per URL, che sostituisce il più e la barra con il trattino e il trattino basso, è quello usato dai JSON Web Token e non è quello che accetta un data URI. Accettarlo in silenzio significherebbe decodificare in byte diversi da quelli del browser, perciò viene rifiutato per nome, con la posizione del carattere colpevole.
Dove gira
Tutto avviene nel tuo browser. Il file che scegli viene letto con l’API locale dei file e non viene mai caricato; la codifica, la misura della compressione e la decodifica girano sulla tua macchina, e nulla viene memorizzato o registrato. Qui conta più che nella maggior parte delle pagine, perché i file che si trasformano in data URI sono spesso risorse interne e gli URI che si incollano per ispezionarli vengono da pagine in produzione.
Domande frequenti
- Il mio file viene caricato da qualche parte?
- No. Il file viene letto in locale con l’API dei file del browser, codificato sulla tua macchina e non inviato da nessuna parte. Lo stesso vale per un URI che incolli per decodificarlo.
- Devo usare Base64 o la codifica percentuale?
- Quella più corta per i tuoi dati, ed è ciò che la pagina misura per te. Come regola pratica: codifica percentuale per SVG, CSS, JSON e altro testo, Base64 per immagini, font e qualsiasi cosa già compressa. La differenza è spesso del venti o trenta per cento in un senso o nell’altro.
- Base64 ingrandisce davvero un file del 33%?
- Prima della compressione sì: quattro caratteri ogni tre byte. In rete, per lo più no. Base64 usa solo 64 dei 256 valori possibili di un byte, e quella ridondanza è esattamente ciò che gzip rimuove, quindi la dimensione compressa è di solito vicina alla dimensione compressa del file originale. La pagina misura entrambe perché tu lo veda.
- Quanto può essere grande un data URI?
- I browser moderni non impongono un limite rigido a un URI dentro un documento, anche se le vecchie versioni di Internet Explorer si fermavano a 32 KB. La dimensione è una questione di prestazioni, non di legalità: un file incorporato non può essere messo in cache separatamente e viene riscaricato con ogni copia del documento. Questa pagina codifica fino a un megabyte e avvisa oltre i trenta kilobyte.
- Perché il mio data URI con SVG si rompe in CSS?
- Quasi sempre per un carattere non escapato. Un cancelletto — da un colore come #2563eb — avvia un identificatore di frammento e tronca l’URI in quel punto. Una virgoletta doppia chiude la stringa CSS in cui si trova. Scrivi l’SVG con apici singoli attorno agli attributi e usa l’insieme di escape minimo, che escapa il cancelletto e la virgoletta doppia e lascia corto tutto il resto.
- Posso usare un data URI per uno script o un iframe?
- Puoi, ma trattalo come una questione di sicurezza e non di comodità. Un data URI non eredita origine, e i browser bloccano già la navigazione di primo livello verso uno proprio per questo. Una Content Security Policy che consenta data: in script-src o frame-src rinuncia a gran parte di ciò che la politica proteggeva; consentirlo in img-src o font-src è ordinario.
- Perché il mio Base64 sicuro per URL è stato rifiutato?
- Perché un data URI accetta Base64 standard. L’alfabeto sicuro per URL scambia il più e la barra con il trattino e il trattino basso, che sono caratteri diversi e si decodificano in byte diversi. Accettarlo significherebbe che questa pagina decodifica il tuo URI diversamente dal browser che lo caricherà davvero.
- Il browser dice che il mio file è di un tipo e questa pagina di un altro. Chi ha ragione?
- La pagina. Un browser dichiara il tipo che deduce dall’estensione del file, quindi sbaglia con un file rinominato. Questa pagina legge la firma all’inizio del file, cioè ciò che il formato stesso dichiara. Il campo resta modificabile se hai un motivo per sovrascriverlo.