Conoscere il formato PDF

Lo scopo di queste note è quello proporre una breve analisi di un documento PDF, evidenziandone la struttura e gli elementi costitutivi e affrontando quindi le problematiche relative alla gestione dei font, della grafica vettoriale e delle immagini raster.

Per brevità, non affronteremo il problema della compressione dei dati, della revisione o modifica di un file creato in precedenza, né vedremo come realizzare le miniature o la struttura ad indice del documento. Il contenuto di questa pagina NON E’ NECESSARIO per utilizzare la libreria, ma può essere utile per ampliarne le funzioni.

Gli elementi di base

Un file PDF è sostanzialmente un file di testo, inteso come sequenza di caratteri e separatori di linea (ASCII 13 o ASCII 10), di tipo strutturato, ovvero in cui le informazioni assumono un particolare significato in quanto inserite in strutture che rispettano una particolare sintassi.

Gli elementi di base sono gli oggetti “obj”, che all’occorrenza possono contenere sequenze “stream”, dizionari “dictonary” o altro. Un oggetto può rappresentare una pagina, un’immagine, una sequenza grafica, ecc.

Ogni oggetto, racchiuso tra le parole chiavi obj e endobj è identificato da un numero e da una revisione. Visto che non prenderemo in considerazione le modifiche di file creati in precedenza, tutti i nostri oggetti avranno come numero di revisione 0 (zero).

2 0 obj
.. .. .. .. ..
endobj

Gli oggetti non devono necessariamente presentarsi in ordine numerico ed è possibile fare riferimento ad un oggetto “futuro”, ovvero non ancora definito; ciò risulta particolarmente utile e forse indispensabile in alcuni casi (ad esempio quando nel file è necessario indicare la lunghezza di un testo prima che il testo stesso sia stato inserito). Quando è necessario effettuare un riferimento ad un oggetto, basta indicare il suo numero e la revisione seguiti dalla lettera “R”.

.. .. 
/Parent 3 0 R 
.. ..

In generale, ogni qualvolta si renda necessario utilizzare più volte lo stesso oggetto in più punti del documento, sia esso una immagine o una generica risorsa, ai fini dell’occupazione di memoria e della velocità di visualizzazione, conviene creare un oggetto che contenga la risorsa e utilizzare riferimenti a questo in tutti i punti in cui ricorre.

Le sequenze di dati sono racchiuse tra le parole chiave stream e endstream. Possono contenere qualsiasi sequenza di caratteri (anche quelli non stampabili) e servono a descrivere un testo, un’immagine o altro.

stream
.. sequenza di caratteri ..
endstream

I dizionari sono coppie variabile/valore racchiuse tra i delimitatori « e ». Vengono utilizzati per caratterizzare particolari oggetti, definendone gli attributi. Un valore può essere espresso con una costante numerica (la parte decimale prevede il punto e non la virgola), una stringa alfanumerica (delimitata da una coppia di parentesi tonde), con un ulteriore dizionario, con un riferimento ad un oggetto o con un array (delimitato da una coppia di parentesi quadre).

<< /Type /Page
/Parent 3 0 R
/Resources << 
  /ProcSet 6 0 R >>
  /MediaBox [0 0 612 792]
.. .. ..
>>

Un file PDF non è altro che una opportuna sequenza di oggetti, costruiti rispettando una sintassi abbastanza semplice (facendo attenzione a maiuscole e minuscole), legati fra loro da riferimenti specifici, corredato da quanto necessario all’applicativo che legge il file (ad esempio Acrobat Reader) per sapere dove recuperare le informazioni ed in quale ordine.

Struttura di un file PDF

La struttura fisica di file PDF può essere riassunta nel seguente schema.

HEADER
BODY
CROSS-REFERENCE TABLE
TRAILER

La sezione HEADER contiene informazioni utili al software Reader per identificare il tipo di file e lo standard PDF utilizzato.
E’ rappresentata dalla prima riga del file ed è del tipo

%PDF-1.3

ove il simbolo % indica in genere una riga di commento e 1.3 indica che per leggere correttamente le informazioni contenute nel file è necessario Acrobat Reader 4.0 (piuttosto che 1.4 per il quale è necessario Acrobat Reader 5.0, piuttosto che 1.5 per Acrobat Reader 6.0 e così via).
Nel seguito, noi considereremo di operare sempre con formati compatibili con Acrobat Reader 4.0 ovvero con una specifica %PDF-1.3.

La sezione BODY contiene gli oggetti che saranno rappresentati sulle pagine e sui quali ci soffermeremo in seguito.

La sezione CROSS-REFERENCE TABLE è una tabella che riporta un riferimento ad ogni oggetto presente nella sezione BODY e alla sua eventuale revisione; in particolare indica la posizione del primo carattere della definizione di un oggetto rispetto all’inizio del file e il numero di revisione a cui si riferisce.

xref
0 23
0000000019 65535 f
0000000009 00000 n
.. .. ..
0000000300 00000 n
0000000384 00000 n

La sezione TRAILER indica al Reader quanti oggetti sono presenti nella sezione BODY (/Size), qual è l’oggetto iniziale (/Root), quale oggetto contiene le informazioni generali del documento quali autore, titolo, data di creazione (/Info), dove trovare la CROSS-REFERENCE TABLE ed inoltre segna la fine del file (%%EOF).

trailer
<< /Size 7
/Root 1 0 R
/Info 2 0 R
>>
startxref
408
%%EOF

Struttura logica di un documento PDF

La struttura logica di un documento PDF può essere riassunta nel seguente schema.

L’oggetto CATALOG rappresenta la radice dell’intero documento e deve essere quello a cui punta il riferimento /Root presente nella sezione TRAILER.

1 0 obj
<< /Type /Catalog
/Pages 3 0 R
/Outlines 20 0 R
>>
endobj

A sua volta, contiene un riferimento alla radice delle pagine (/Pages) e un riferimento alla radice della struttura ad albero che fa da indice (/Outlines), quella che, quando si apre un documento con Acrobat Reader, appare di solito a sinistra della pagina e permette di muoversi velocemente nel documento, e che noi per semplicità non analizzeremo.

L’oggetto PAGES rappresenta la radice delle pagine, indica il numero complessivo delle pagine del documento (/Count) e riporta un riferimento all’oggetto che contiene ogni pagina (/Kids).

3 0 obj
<< /Type /Pages
/Count 3
/Kids [4 0 R 8 0 R 10 0 R]
>>
endobj

L’oggetto PAGE riporta un riferimento alla propria radice (/Parent), un elenco delle risorse utilizzate nella pagina (/Resources, vedremo in seguito cosa sono), un array con le dimensioni del formato di stampa previsto (/MediaBox) ed infine un riferimento all’oggetto che contiene gli elementi da rappresentare sulla pagina (/Contents).

4 0 obj
<< /Type /Page
/Parent 3 0 R
/Resources << /ProcSet [/PDF /Text] >>
/MediaBox [0 0 595.2 842]
/Contents 5 0 R
>>
endobj

Se nel documento si vogliono riportare informazioni relative all’autore, all’applicativo che ha generato il file o la data di creazione, si può utilizzare il seguente oggetto (facendo attenzione alle parentesi che fanno parte della sintassi). Queste informazioni appaiono se dal Reader si visualizzano le proprietà del documento.

2 0 obj
<< /Title (titolo_del_documento)
/Author (autore_del_documento)
/Creator (applicativo_generatore)
/Producer (info_copyright)
/CreationDate (D:yyyymmddhhmmss+01'00')
>>

Il sistema di coordinate

Il sistema di coordinate predefinite in documento PDF ha come unità di misura il punto, definito come 1/72 di pollice. L’origine degli assi è posta nell’angolo in basso a sinistra. In questo sistema, il normale foglio A4 (21×29.7 cm) ha dimensione 595.2 x 842 punti. Per default tutte le immagini, a meno di una esplicita traslazione/scalatura/rotazione, hanno dimensione 1×1 e sono poste con lo spigolo inferiore sinistro nell’origine (0,0).

Gli operatori

Per la definizione degli elementi contenuti in ogni pagina, la sintassi dello standard PDF prevede l’uso di alcuni operatori. Di seguito sono elencati solo alcuni, rimandando ai testi in bibliografia per una descrizione più dettagliata. In particolare, bisogna tener conto che gli operatori grafici descrivono solo un percorso (path) che verrà tracciato fisicamente soltanto quando verrà utilizzato un apposito operatore e che le componenti di colore vanno da 0 a 1 e non da 0 a 255.

OperatoreDescrizione
X Y mMuove il punto di inserimento grafico alle coordinate (X,Y)
X Y lAggiunge una linea dal punto corrente al punto (X,Y) alla path
X wImposta la larghezza della linea a X punti
hChiude un path
nTermina un path
fColora la regione delimitata
r g b RGImposta il colore per i contorni
r g b rgImposta il colore per le aree
gray GImposta un tono di grigio per i contorni
gray gImposta un tono di grigio per le aree
x1 y1 x2 y2 x3 y3 c  Aggiunge una curva Bezier al path
x y width height re Aggiunge un rettangolo al path
W 0 0 H X Y cmMatrice di trasformazione grafica di coordinate
STraccia la path
sChiude e traccia la path
BTraccia la path e colora la regione
BTInizia una sequenza di testo
ETTermina una sequenza di testo
space TcImposta la spaziatura tra caratteri in millesimi di punto
space TwImposta la spaziatura tra parole in millesimi di punto
scale TzImposta la scalatura percentuale dei caratteri
space TLImposta l’interlinea
X Y TdImposta il punto di inserimento del testo
fontname size TfImposta il font e la dimensione del carattere
string TjVisualizza la stringa con il font corrente
/name DoEsegue l’oggetto name

I path (percorsi)

I path rappresentano dei tracciati invisibili, che diventano visibili solo a seguito di un opportuno comando. Spieghiamo meglio questo concetto con un esempio. In un normale contesto grafico, se voglio tracciare una spezzata, costituta quindi da più linee, traccio fisicamente il primo tratto, poi il secondo, e cosi via. In un documento PDF, invece, preparo il primo tratto (ovvero costruisco un percorso invisibile che lo descrive), poi il secondo e così via e dopo l’ultimo tratto lancio un operatore che traccia fisicamente l’intera spezzata. Questo modo di operare è dovuto al fatto che il percorso (path) descritto potrebbe essere utilizzato non per tracciare fisicamente sulla pagina una spezzata, ma magari per delimitare (clippare) un’altra porzione di grafica successiva, racchiudere un testo, ecc.. .

Gli elementi di uso comune – (Font e testo)

Uno dei primi oggetti che analizziamo è l’oggetto necessario a descrivere un font. In questa fase vedremo come utilizzare uno dei 14 fonti TYPE1 predefiniti nel linguaggio PDF, ovvero font che il Reader conosce già e che non necessitano di particolari informazioni (viceversa, per altri tipi di font TrueType occorre fornire informazioni dettagliate, come ad esempio la larghezza in punti di ogni singolo carattere).

I 14 font predefiniti TYPE1 sono :

  • CourierNew (.Italic, .Bold, .BoldItalic)  
  • Arial (.Italic, .Bold, .BoldItalic)  
  • TimesNewRoman (.Italic, .Bold, .BoldItalic)  
  • ZapfDingbats  
  • Symbol

Per poterne utilizzare uno, occorre creare un oggetto che lo contenga. Nell’esempio che segue, l’oggetto 7 contiene il font Arial con attributi Grassetto e Corsivo, al font viene dato il nome Fn1 e come tabella caratteri viene indicata quella ANSI.

7 0 obj
<< /Type /Font
/Subtype /Type1
/Name /Fn1
/BaseFont /Arial.BoldItalic
/Encoding /WinAnsiEncoding
>>
endobj

Quindi volendo scrivere il classico “Hello World” alla posizione di coordinate (100,400) con il font definito in precedenza di nome Fn1, basterà inserire in un oggetto la sequenza

% Scrive Hello World in Arial Bold Italic 24 punti
BT
/Fn1 24 Tf
100 400 Td
(Hello World) Tj
ET

Gli elementi di uso comune – (Grafica vettoriale)

Se vogliamo inserire degli elementi grafici, basterà inserire una sequenza del tipo

% Traccia un rettangolo rosso pieno con contorno blue
.5 .75 1 rg
1 0 0 RG
200 300 50 75 re
B

\  % Traccia una linea con spessore 2 punti
2 w
150 250 m
150 350 l
S

Gli elementi di uso comune – (Immagini raster)

Un altro oggetto di uso comune è quello necessario per rappresentare delle immagini di tipo raster (BMP). Per le immagini è possibile optare per due modalità: creare un oggetto che può essere richiamato ogni volta che la stessa immagine deve essere visualizzata, anche se con dimensioni diverse (ed è questo il caso che noi analizzeremo) o definire l’immagine all’interno della pagina senza la possibilità di poterla riutilizzare.

Ad esempio, se si definisce una immagine Img1, 10 pixel per 5, 24 bit colore (8 x 3 componenti colore RGB), utilizzando una rappresentazione esadecimale, sono necessari 150 elementi, ovvero 10 x 5 x 3.

12 0 obj
<< /Type /XObject
/Subtype /Image
/Name /Img1
/Width 10
/Height 5
/BitsPerComponent 8
/ColorSpace /DeviceRGB
/Filter /ASCIIHexDecode"
/Length 13 0 R
>>
stream
80 A1 2F .. .. %150 campioni esadecimali
endstream
endobj

13 0 obj
150
endobj

Notare come al posto della lunghezza dello stream è stato utilizzato un riferimento ad un oggetto (13 0) che contiene (solo) il valore 150.

Se vogliamo visualizzare l’immagine con l’angolo inferiore sinistro nel punto (100, 80), con una dimensione orizzontale 200 e una verticale di 300, sarà sufficiente inserire la sequenza

q                         % salva lo stato grafico corrente
200 0 0 300 100 80 cm     % matrice di trasformazione di coordinate
                          % per spostare/ingrandire l’immagine
/Img1 Do                  % visualizza l’immagine Img1
Q                         % ripristina lo stato grafico precedente

Analogamente la sequenza

.. ..
/BitsPerComponent 8
/ColorSpace /DeviceGray
/Length 50
>>
stream
$-#etT .. .. %50 byte
endstream
endobj

individua un’immagine in toni di grigio (1 sola componente colore), rappresentata con una sequenza di 50 byte (10x5x1)

Gli elementi di uso comune – (Le Form)

Capita spesso che porzioni di documenti, vadano riprodotte più volte, come ad esempio le intestazioni, i piè di pagina, i watermark (quelle scritte oblique sotto al testo tipo bozza, uso interno,…). Lo standard PDF prevede l’uso di un particolare oggetto, appunto le form, che, chiariamo subito, non hanno nulla a che fare con le form di Visual Basic. Ad esempio tutto ciò che è contenuto nello stream dell’oggetto 13 con nome Frm1,

13 0 obj
<< /Type /XObject
/Subtype /Form
/FormType 1
/Name /Frm1
/BBox [0 0 595.2 842]
/Matrix [1 0 0 1 0 0]
/Length 14 0 R >>
stream
.. .. .. .. ..
endstream
endobj

può essere riprodotto, ovunque, con la sequenza

/Frm1 Do

L’idea di base: la struttura tipo del documento generato

Come abbiamo visto, gli elementi principali di un documento PDF sono gli oggetti. Abbiamo la necessità quindi di costruire un meccanismo che ci permetta di gestire la scrittura dell’oggetto e contestualmente la gestione della sezione CROSS-REFERENCE TABLE, in cui, come già detto, va scritto un riferimento all’oggetto creato. Non bisogna dimenticarsi inoltre che ci sono alcuni oggetti che in un ordine logico andrebbero prima di altri, per esempio la radice delle pagine /Pages, anche se contengono riferimenti, alle pagine, che sono noti solo dopo che tutti gli oggetti sono stati costruiti. Per risolvere i problemi evidenziati, si è pensato di utilizzare una struttura ed una numerazione degli oggetti tale che i riferimenti fossero conosciuti a priori. Così facendo, il documento viene costruito in modo tale che l’oggetto /Pages, ed in modo simile gli altri, ha sempre lo stesso numero di riferimento, anche se viene fisicamente costruito dopo gli altri. In altre parole, la struttura tipo del documento generato è la seguente

1 0 obj Info
2 0 obj Catalog
3 0 obj Encoding
6 0 obj (//disponibile//)
7 0 obj (//disponibile//)
.. .. .. ..
.. .. .. .. ..
n-1 0 obj (//disponibile//)
n 0 obj (//disponibile//)
4 0 obj Pages
5 0 obj Resource

in questo modo il riferimento agli oggetti intermedi, ad esempio il /Parent presente in ogni oggetto /Page, è sempre noto, mentre gli altri possono essere costruiti a mano a mano che gli oggetti vengono creati e inseriti alla fine nella definizione degli oggetti 4 e 5.

L’oggetto Resources

Nella prima parte abbiamo accennato che ogni oggetto /Page contiene un riferimento ad un oggetto /Resources, un dictionary che descrive sostanzialmente il contenuto e le risorse utilizzate nel documento, ovvero l’elenco dei Font utilizzati e gli oggetti Form, e descrive il contenuto del documento. Ad esempio

4 0 obj
<< /Type /Pages
/Resources 5 0 R
.. ..
>>
endobj

5 0 obj
<< /Font <</Fnt1 6 0 R /Fnt2 7 0 R >>
/ProcSet %%[/%%PDF /Text /ImageB /ImageC /ImageI]
/XObject <</Img1 8 0 R /Frm1 9 0 R >>
>>
endobj

l’oggetto 5 0 precisa che il documento utilizza due font (Fnt1 e Fnt2) rappresentati rispettivamente dagli oggetti 6 0 e 7 0, un oggetto immagine Img1 (oggetto 8 0) ed un oggetto form (oggetto 9 0). Inoltre indica che all’interno del documento ci sono degli operatori standard (/PDF), degli oggetti di tipo testo (/Text), delle immagini in scala di grigio (/ImageB), delle immagini a colori RGB (/ImageC) e delle immagini a tavolozza indicizzata (/ImageI).

Le unità di misura

L’unità di misura dello standard PDF è 72 punti per pollice. Ovviamente con le opportune conversioni, è possibile utilizzarne altre (centimetri, millimetri e pollici). Per quanto riguarda le cifre decimali, lo standard prevede 3 cifre sul valore assoluto in unità di misura standard, e non dovrebbe essere necessario andare oltre.

Grafica vettoriale

Prima di utilizzare gli operatori tipo linea, arco o altro, ricordarsi di settare sempre il punto di inizio del tracciato con l’operatore MoveTo. Nel caso di tracciati composti da più tratti elementari, si consiglia di utilizzare solo sull’ultimo tratto le opzioni di disegno, chiusura o riempimento.