Formats9 min di lettura

Come funziona la modifica del testo in un PDF: stream di contenuto, codifiche dei font e perché si modifica una riga alla volta

Una pagina PDF non ha paragrafi né caselle di testo, solo istruzioni per disegnare glifi con un font in una posizione. Modificare una riga cancella le vecchie istruzioni e ne scrive di nuove nello stesso punto, ed è questo a decidere cosa si può modificare e cosa no.

PDF123 · Updated 2026-10-14
Come funziona la modifica del testo in un PDF: stream di contenuto, codifiche dei font e perché si modifica una riga alla volta

Una pagina PDF non ha paragrafi né caselle di testo. Ha un elenco di istruzioni: in questa posizione, con questo font e questa dimensione, disegna questi glifi. Cambiare il testo significa cancellare le istruzioni che disegnano quella riga e scriverne di nuove nella stessa posizione, con lo stesso font, la stessa dimensione e lo stesso colore. Per questo Modifica PDF modifica una riga alla volta e non sa mandare il testo a capo: è una conseguenza del modo in cui il testo viene memorizzato.

Che aspetto ha una riga di testo nel file

Il contenuto di una pagina sta in uno stream di contenuto, un piccolo programma fatto di operatori. Quattro operatori svolgono la maggior parte del lavoro per il testo: BT e ET racchiudono un blocco di testo, Tf sceglie il font e la dimensione, Td si sposta alla posizione successiva e Tj disegna una stringa. Con un font standard il caso più semplice è questo:

BT /F1 18 Tf 20 150 Td (Hello World) Tj ET

Significa: scegli il font F1 a 18 punti, spostati a x 20, y 150 e disegna Hello World. Un PDF stampato da Chrome di solito è diverso: le parentesi non contengono più caratteri ma numeri di glifo del font, e Tm imposta la posizione una sola volta. Qui sotto c'è la riga Hello World from Georgia di una pagina esportata da Chrome, dove ogni quattro cifre esadecimali sono un numero di glifo:

BT /F4 24 Tf 1 0 0 -1 30 52 Tm <002b0048004f004f00520003003a00520055004f0047000300490055005200500003002a004800520055004a004c0044> Tj ET

002b è H, 0048 è e, 004f è l, 0003 è uno spazio, 003a è W, e così via. Questi numeri hanno significato solo all'interno di quel singolo font; non sono Unicode. Quando copi il testo, il visualizzatore riconverte i numeri in caratteri con una tabella di corrispondenza memorizzata altrove nel file.

Ne seguono due cose. Primo, nulla nello stream di contenuto dice «questo è un paragrafo»: un'andata a capo è solo un altro Td o Tm che sposta la posizione alla riga successiva, e quante righe abbia un paragrafo va dedotto dalle posizioni. Secondo, per scrivere un carattere nuovo in una riga serve il numero di quel carattere in quel font, e il font spesso contiene soltanto i glifi usati quando il file è stato scritto. È il risultato del subsetting dei font.

Puoi espandere gli stream con qpdf:

qpdf --qdf --object-streams=disable in.pdf out.pdf

Apri out.pdf in un editor di testo e cerca Tj per vedere ogni stringa disegnata sulla pagina. Per sapere che cos'altro contiene un PDF, vedi Cosa c'è dentro un PDF: oggetti, stream e la tabella cross-reference.

Come l'editor ricostruisce una «riga» a partire dai glifi

L'editor deve prima raggruppare i glifi sparsi in una riga su cui l'utente possa fare clic. I glifi con lo stesso font, la stessa dimensione e lo stesso colore, la cui distanza dal glifo precedente non supera una dimensione del font, formano un'unica sequenza (un gruppo di glifi adiacenti); un'andata a capo, un font nuovo o un colore nuovo la interrompe. Il testo che scorre da destra a sinistra, o in verticale, non viene raggruppato e non può essere aperto per la modifica.

Due conseguenze si osservano direttamente. Una riga che mescola due font, come una riga in cinese con una parola inglese, viene divisa in due sequenze adiacenti su cui si fa clic separatamente. Dopo una modifica succede lo stesso: se il testo nuovo usa un altro font, la riga diventa due sequenze, e modificarne una lascia l'altra invariata.

Modificare una riga: cancellare il vecchio testo, poi scrivere il nuovo

La cancellazione usa l'oscuramento limitato al testo: i glifi dentro l'area della riga vengono rimossi dallo stream di contenuto, immagini e linee restano al loro posto e nessun riquadro colorato viene disegnato sopra il vecchio testo, così copia e ricerca non lo trovano più. Cambia solo il contenuto della pagina; se lo stesso testo compare anche in un'annotazione o nelle proprietà del documento, queste non vengono toccate.

La scrittura aggiunge una nuova istruzione di testo alla fine dello stream di contenuto della pagina, a partire dalla posizione della linea di base della riga originale e riutilizzandone dimensione e colore. Dopo aver cambiato la riga qui sopra in Hello World 2, ciò che viene aggiunto in fondo alla pagina è:

q 1 0 0 1 22.5 148.92 cm 0 0 0 rg
/Span <</ActualText <feff00480065006c006c006f00200057006f0072006c006400200032>>> BDC
BT /F4 18 Tf 0 0 Td <002b0048004f004f00520003003a00520055004f00470003> Tj ET
BT /F9 18 Tf 102.18 0 Td (2) Tj ET
EMC
Q

Il primo BT usa il font originale F4 e i numeri di glifo originali, quindi Hello World viene riutilizzato esattamente com'era. Il «2» non è nel subset del font originale, perciò il secondo BT avvia un nuovo font Helvetica standard (F9) per disegnarlo. q e Q confinano la trasformazione delle coordinate e il colore di questo blocco al blocco stesso; l'editor racchiude anche il contenuto originale in una coppia q/Q, in modo che uno stato rimasto sbilanciato alla fine della pagina originale non possa influire sul testo nuovo. Questo è l'aspetto di una sequenza; i numeri variano da file a file.

L'aggiunta in fondo ha tre conseguenze:

  • Il testo nuovo viene dipinto per ultimo, sopra tutto il resto della pagina. Il testo che stava sotto un'immagine o un blocco colorato compare sopra dopo una modifica.
  • Uno strumento che estrae il testo nell'ordine dello stream di contenuto (come pdftotext -raw) legge la riga modificata per ultima in quella pagina, mentre l'estrazione per posizione (pdftotext -layout) non mostra alcun cambiamento. La pagina appare uguale, ma l'ordine di lettura è cambiato.
  • L'editor associa un ActualText al testo nuovo, che dice al visualizzatore quali caratteri reali rappresentano i glifi. Un glifo può corrispondere a più caratteri, e cercarlo partendo dal solo numero di glifo a volte restituisce un carattere di compatibilità (per esempio leggere 文 come il radicale Kangxi ⽂); ActualText garantisce che ciò che copi sia ciò che hai digitato.

Quale font disegna il testo nuovo

Riutilizzare il font originale è l'opzione più sicura, perché forma dei glifi, peso e larghezza coincidono con quanto c'è accanto. Se sia riutilizzabile dipende dal fatto che l'editor sappia quale codice ha un carattere in quel font:

  • Un font composito come quello sopra (Type0, numeri di glifo a due byte, codifica Identity-H): si cerca il carattere nel font per ottenere il suo numero di glifo e lo si usa se viene trovato. Se non viene trovato, il carattere non è nel subset.
  • Un font semplice a un byte (TrueType, Type1) con codifica WinAnsi o MacRoman: la corrispondenza tra carattere e byte è fissa e le larghezze vengono dalla tabella delle larghezze nel file.
  • Un font con codifica personalizzata (Differences) o che si affida alla codifica incorporata del font: non esiste una corrispondenza affidabile, quindi l'editor non tira a indovinare e passa a un font di ripiego, altrimenti il testo uscirebbe illeggibile.

Quando un carattere non è nel font originale, si usa un font di ripiego. Le lettere latine semplici usano il più vicino tra Helvetica, Times e Courier, font standard che ogni visualizzatore ha, quindi non serve incorporare nulla. Tutto il resto, come caratteri cinesi, kana, hangul, thailandese, lettere latine accentate, cirillico e greco, usa un font Noto open source: il server prende i caratteri della richiesta e ritaglia solo quei glifi dal font completo con la libreria di subsetting open source HarfBuzz, di solito pochi KB, e il browser li incorpora nel tuo file. La forma regionale di un carattere cinese segue la lingua dell'interfaccia: cinese semplificato, tradizionale, giapponese o coreano.

I glifi vengono incorporati invece di scrivere soltanto il nome di un font perché un font richiamato solo per nome viene sostituito da qualunque ripiego scelga ciascun visualizzatore, e il peso può differire da un visualizzatore all'altro; una volta incorporati, ogni visualizzatore mostra le stesse forme.

Perché una sola riga alla volta

L'editor non ha un motore di impaginazione. Ogni posizione di glifo è fissata nel file; il testo nuovo viene semplicemente disposto verso destra dal punto di partenza usando le larghezze del font, senza alcuna logica di «a capo al margine», e nulla di ciò che segue viene spostato. Se allunghi una riga, i caratteri in più proseguono verso destra, e ciò che supera il bordo della pagina non si vede. Riscrivere un paragrafo o aggiungere righe a una tabella richiede una nuova impaginazione, il che significa tornare al file sorgente da cui il PDF è stato creato.

Le larghezze sono inoltre soltanto le larghezze di avanzamento del font (di quanto avanza la posizione di scrittura dopo ogni glifo), senza kerning né sostituzione dei glifi. Il testo che non ha bisogno di shaping (la scelta e il posizionamento dei glifi in base al contesto: latino, cirillico, greco e caratteri cinesi) viene disposto correttamente. I segni di tono del thailandese richiedono il posizionamento dei glifi per stare nel punto giusto, cosa che l'editor non fa, quindi possono risultare spostati. L'arabo richiede forme dei glifi che dipendono dal contesto e impaginazione da destra a sinistra, l'ebraico richiede impaginazione da destra a sinistra e le scritture indiche richiedono che consonanti e segni vocalici si combinino in glifi; tutto questo richiede uno shaping completo del testo, che l'editor ora non fa, perciò digitarli viene rifiutato invece di produrre caratteri sbagliati.

Altri due limiti vengono dal file stesso. Il contenuto di una pagina scansionata è un'unica immagine senza operatori di testo, quindi non c'è nulla da cancellare o cambiare. Dopo la modifica di un file con firma digitale, il contenuto originale che la firma proteggeva è cambiato e la firma non è più valida.

Verificalo tu stesso

Puoi vedere i cambiamenti descritti sopra in un file scaricato con tre comandi:

pdftotext -raw edited.pdf -      # estrae nell'ordine dello stream di contenuto: il vecchio testo non c'è più, la riga modificata viene per ultima
pdffonts edited.pdf              # elenco dei font: i font originali riutilizzati e il subset di font appena incorporato
qpdf --qdf --object-streams=disable edited.pdf edited.qdf   # espande lo stream di contenuto; il blocco BT ... ET aggiunto è in fondo

Continua a leggere

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool