Salta ai contenuti
getnextpdf.com

I font: la parte difficile

I font sono il punto in cui un PDF può sembrare del tutto corretto e restare comunque silenziosamente difettoso. Una pagina può disegnare i glifi giusti pur risultando impossibile da cercare, impossibile da copiare come testo e non conforme a un profilo di archiviazione. Tutto questo può accadere allo stesso tempo, senza alcun segnale visibile a indicarlo. Questa pagina tratta delle tre cose che devono funzionare correttamente — incorporazione, subsetting, codifica — e di ciò che NextPDF fa per ciascuna.

«Sembra a posto» è la frase più pericolosa quando si lavora con i PDF, ed è con i font che fa più danni. Tre elementi indipendenti devono reggere:

  1. Incorporazione — il programma del font viaggia dentro il file, così viene reso allo stesso modo su una macchina in cui il font non è installato.
  2. Subsetting — vengono trasportati solo i glifi effettivamente utilizzati, così un font CJK da 20 MB non appesantisce ogni documento.
  3. Codifica — esiste una corrispondenza corretta che riporta all’Unicode i codici dei caratteri presenti nella pagina, così il testo può essere cercato, copiato, indicizzato e letto dalle tecnologie assistive.

Il rendering visivo dimostra solo in parte il primo punto. Un documento può mostrare glifi perfetti e fallire completamente sul terzo: il testo è un’immagine di parole, non parole. È il tipo di guasto che supera ogni revisione basata sul «sembra a posto» e poi fa perdere un audit di conformità o una richiesta di produzione documentale.

  • Un font in un PDF è un dizionario e, di solito, un flusso di programma del font incorporato.
  • Il subsetting riscrive quel programma affinché contenga solo i glifi utilizzati. Il nome di un font sottoposto a subsetting riceve un tag di sei lettere maiuscole e un +, così i lettori lo trattano come distinto.
  • La codifica è il problema separato della mappatura dei codici dei caratteri sull’Unicode. Una CMap /ToUnicode è ciò che rende il testo ricercabile e copiabile — ed è indipendente dal fatto che i glifi appaiano corretti.
  • Un testo dall’aspetto corretto senza /ToUnicode (o con una /ToUnicode errata) è il classico guasto silenzioso: perfetto sullo schermo, non ricercabile nella pratica.
  • NextPDF applica il subsetting ai font TrueType, preserva l’identità dei glifi per un rendering corretto ed emette una CMap /ToUnicode affinché l’estrazione funzioni — e può imporre la regola di incorporazione di PDF 2.0 anziché limitarsi ad avvertire.

Subsetting. FontSubsetter (src/Typography/FontSubsetter.php) analizza la directory delle tabelle TrueType originale e legge la cmap per mappare i codepoint Unicode sugli ID dei glifi. Gestisce sia il formato 4 del BMP sia il formato 12 a Unicode completo, necessario per il CJK. Poi compie il passo che i subsetter ingenui saltano: risolve le dipendenze tra glifi compositi tramite chiusura transitiva. Un glifo accentato costruito a partire da una lettera di base più un segno combinante fa riferimento ad altri glifi come componenti. Se quei componenti vengono eliminati, il glifo viene reso in modo errato. Il subsetter percorre quel grafo finché non compare più alcun nuovo componente, con una protezione dai cicli affinché un font malformato non possa iterare all’infinito.

Due scelte ingegneristiche in quel file meritano di essere esplicitate. Primo, gli ID dei glifi sono preservati, non rimappati — gli slot inutilizzati vengono riempiti di zeri in glyf/loca, così gli indici di glifo originali del flusso di contenuto restano validi sotto CIDToGIDMap /Identity. La rimappatura produrrebbe un file più piccolo, ma richiederebbe di riscrivere ogni riferimento a un glifo. Preservare l’identità è corretto per costruzione. Secondo, l’attraversamento è ordinato (per ID di glifo crescente), così il sottoinsieme è deterministico a livello di byte — lo stesso font e gli stessi glifi utilizzati producono gli stessi byte di sottoinsieme, che è ciò che richiedono le build riproducibili. Se il subsetting facesse risparmiare meno di circa il 10% del file, viene restituito l’originale invariato. L’onere non vale un guadagno marginale.

Incorporazione. Una policy esplicita decide se un programma del font venga trasportato o meno — mai per congettura. Pdf20FontEmbeddingPolicy (src/Writer/Pdf20FontEmbeddingPolicy.php) ha due modalità. Sotto il profilo PDF 2.0, Strict rifiuta un riferimento a un font Type 1 standard non incorporato («Base14») con un’eccezione tipizzata — il comportamento conforme. AllowBase14 conserva il percorso storico di semplice avviso. Durante una finestra di migrazione, emette il descrittore del font minimo che lo standard ancora richiede e invia un avviso anziché sollevare un’eccezione. È il chiamante a compiere la scelta esplicitamente sul documento; non viene mai dedotta dal font.

Codifica. Per i font compositi (Type 0), EmbeddedTtfFontDictBuilder (src/Writer/EmbeddedTtfFontDictBuilder.php) emette il discendente CIDFontType2, il genitore Type0 e un flusso di CMap /ToUnicode, così i codici dei caratteri si risolvono nuovamente in Unicode. Il flusso /ToUnicode è legittimamente assente in un solo caso: quando una CMap CJK predefinita e autodescrittiva fornisce già al lettore la mappatura da carattere a Unicode. In quel caso la CMap è la codifica, perciò il profilo semplice omette un flusso /ToUnicode ridondante per risparmiare byte. Al di fuori di quel caso, il flusso /ToUnicode è ciò che mantiene il testo come testo.

AspettoCiò che garantisceCiò che non garantisceGuasto silenzioso in caso di errore
IncorporazioneStesso rendering senza il font installatoChe il testo sia ricercabileFont sostituito; metriche errate su un’altra macchina
SubsettingFile piccolo; solo i glifi utilizzatiAlcunché sulla codificaComponenti compositi mancanti → glifi accentati rotti
Codifica (/ToUnicode)Testo ricercabile, copiabile, accessibileChe i glifi vengano resi correttamentePagina dall’aspetto perfetto, non ricercabile / illeggibile alla copia

I tre aspetti dei font sono indipendenti. Incorporazione e subsetting riguardano aspetto e dimensione; la codifica riguarda il significato. Una pagina può superare i primi due e fallire il terzo senza nulla di visibile a mostrarlo.

Ecco le due metà di un font composito correttamente incorporato, sottoposto a subsetting e ricercabile. Il tag di sottoinsieme rispetta la regola delle sei lettere dello standard; il riferimento /ToUnicode mantiene il testo estraibile.

% The Type 0 (composite) font dictionary
20 0 obj
<< /Type /Font /Subtype /Type0
/BaseFont /ABCDEF+NotoSans % six-letter subset tag + '+'
/Encoding /Identity-H
/DescendantFonts [21 0 R]
/ToUnicode 23 0 R >> % the map that makes text searchable
endobj
% The descendant CIDFontType2 (carries the subsetted program)
21 0 obj
<< /Type /Font /Subtype /CIDFontType2
/BaseFont /ABCDEF+NotoSans
/CIDToGIDMap /Identity % glyph IDs preserved, not remapped
/FontDescriptor 22 0 R >>
endobj

Il /ToUnicode 23 0 R dell’oggetto 20 è la differenza tra un documento ricercabile e un’immagine di documento. Rimuoverlo (al di fuori del caso della CMap predefinita) e ogni glifo continuerà a disegnarsi perfettamente, eppure una ricerca di una qualsiasi parola nella pagina non troverà nulla.

La trappola, detta in modo semplice: che i glifi vengano resi correttamente non dice nulla sul fatto che il testo sia testo. Il rendering segue il percorso da codifica a glifo. La ricerca e la copia seguono il percorso da codice a Unicode (/ToUnicode). Sono meccanismi diversi che leggono parti diverse del dizionario del font. Un documento può quindi avere un output visivo impeccabile e una /ToUnicode assente o errata. Il risultato è una pagina che appare autorevole ed è funzionalmente non ricercabile — il guasto che sopravvive a ogni revisione visiva, perché per definizione non c’è nulla da vedere.

Una trappola correlata: dare per scontato che «il font è incorporato, quindi siamo a posto per l’archiviazione». L’incorporazione è necessaria ma non sufficiente. Un profilo come PDF/A si aspetta anche sottoinsiemi denominati secondo la regola delle sei lettere e una codifica corretta. Incorporato ma non ricercabile continua a fallire.

Il subsetter di NextPDF è specificamente un subsetter TrueType. Richiede le tabelle TrueType essenziali e restituisce il font originale invariato quando queste mancano o il guadagno è inferiore alla soglia di circa il 10%. Il subsetting e una CMap /ToUnicode rendono il testo estraibile, ma non possono salvare un font di origine privo dell’informazione necessaria per ricondurre un glifo a un carattere dotato di significato. Là dove non è possibile determinare alcun valore Unicode, nessuna emissione di CMap potrà inventarne uno.

Questa pagina riguarda la produzione di una struttura del font corretta nei documenti che NextPDF scrive. Non è uno strumento di riparazione dei font per PDF in ingresso arbitrari. E l’emissione di un sottoinsieme e di una codifica conformi non certifica di per sé un documento rispetto a un profilo di archiviazione completo — questa è una verifica separata e più ampia.

Perché il tag di sei lettere — perché non il nome del font? Perché un lettore possa distinguere due sottoinsiemi diversi dello stesso font e unire documenti senza far collidere i loro insiemi di glifi. Sottoinsiemi diversi, tag diversi, per regola.

Quando è accettabile non avere alcuna /ToUnicode? Quando una CMap CJK predefinita e autodescrittiva fornisce già la mappatura da carattere a Unicode. In quel caso la CMap è la codifica. Una /ToUnicode separata sarebbe ridondante. Al di fuori di ciò, la sua assenza è un difetto.

Il subsetting può mai nuocere? Solo se eseguito male. Eliminare i componenti dei glifi compositi rompe i glifi accentati. Rimappare gli ID dei glifi senza riscrivere i riferimenti rompe il rendering. NextPDF evita entrambe le cose risolvendo la chiusura dei componenti e preservando l’identità dei glifi.

  • Flussi e filtri — i programmi dei font incorporati sono oggetti flusso filtrati, con un proprio contratto di decodifica.
  • Cos’è davvero un PDF — il modello a oggetti in cui vivono i dizionari dei font e i flussi di programma.
  • PDF 2.0: cosa è cambiato — comprese le aspettative più stringenti della base 2.0 sull’incorporazione dei font.
  • Programma del font incorporato — il file di font vero e proprio (TrueType/CFF/Type 1) trasportato all’interno del PDF come flusso, così il rendering non dipende dai font installati del lettore.
  • Subsetting — la riscrittura di un programma del font affinché contenga solo i glifi utilizzati dal documento, per ridurne la dimensione.
  • Tag di sottoinsieme — il prefisso obbligatorio di sei lettere maiuscole seguito da + nel nome di un font sottoposto a subsetting (per esempio, ABCDEF+NotoSans).
  • /ToUnicode — un flusso di CMap che mappa i codici dei caratteri su valori Unicode; ciò che rende il testo di un PDF ricercabile, copiabile e accessibile.
  • Glifo composito — un glifo costruito facendo riferimento ad altri glifi come componenti; i suoi componenti devono essere conservati durante il subsetting.
  • CIDToGIDMap /Identity — la modalità in cui gli indici di glifo del flusso di contenuto sono gli ID di glifo propri del font, invariati; NextPDF preserva l’identità dei glifi per mantenerla valida.
  • Base14 — i quattordici font Type 1 standard; PDF 2.0 si aspetta che i font siano incorporati anziché referenziati per nome.