Firebird Documentation Index → Come fare il manuale di Firebird → Avanzato: perfezionare i PDF |
A causa delle limitazione nei sistemi di ricostruzione, il PDF generato può soffrire di alcuni irritanti difetti, quali:
Testate e titoli vedovi (appaiono alla fine della pagina, con il testo corrispondente che inizia nella pagina successiva).
Salti pagina nelle tabelle posti in posizioni strane.
Spazi di giustificazione enormemente larghi.
Contenuti della pagina compressi, troncati, o sparpagliati. Questa è una nuova caratteristica, introdotta da FOP 0,93
Questa sezione vi mostra come affrontare questi problemi, nel caso vi sia la necessità.
La prima cosa da capire è come viene ricostruito il PDF. A differenza della generazione dell'HTML, è un processo in due passi:
Il sorgente XML DocBook viene convertito in un file Formatting
Objects (FO). Il formato FO – chiamato formalmente
XSL-FO – è anch'esso un formato XML, ma a
differenza del DocBook è orienato alla presentazione. Questo passo è
effettuato da un cosiddetto XSL transformer
chiamato Saxon. Il risultato va in
manual/inter/
(per i documenti in italiano in
filename
.fomanual/inter/it/
).
filename
.fo
Un secondo strumento, Apache FOP
(Formatting Objects Processor), prende
e lo
converte in
filename
.fo
, che è
memorizzato in filename
.pdfmanual/dist/pdf
(per i documenti
in italiano in manual/dist/pdf/it
).
Dando il comando build pdf, vengono ricostruiti internamente due consecutivi obiettivi: fo e fo2pdf, che corrispondono ai due passi descritti sopra. Però si possono chiamare distintamente dalla linea di comando. Ad esempio,
build fo -Did=qsg15
...trasforma il sorgente della Quick Start Guide 1.5 in
manual/inter/qsq15.fo
. E
build fo2pdf -Did=qsg15
...produce il PDF dal file FO (che deve ovviamente essere presente affinchè questo passo possa avere successo).
Pertanto, build pdf è solo un'abbreviazione per build fo seguito da build fo2pdf.
Questa impostazione permette di modificare il file FO manualmente prima di generare il PDF finale. E sarà esattamente quello che si farà per aggiustare alcuni di quei noiosi problemi che affliggono i nostri PDF.
In generale, la procedura per migliorare il PDF in uscita modificando il file FO è:
Costruire il PDF una prima (ed unica) volta volta come al
solito con build pdf
[argomenti]
. Questo comando non
dovrà più essere utilizzato.
Cominciare a leggere il PDF e trovare il primo evidente problema.
Aprire il file FO con un editor di testo o un editor XML.
Riconoscere il punto nel file FO che corrisponde al problema nel PDF (vedremo come in dettaglio più avanti).
Modificare il file FO per eliminare il problema (anche questo sarà dettagliato più oltre), e salvare le modifiche.
Ricostruire il PDF, ma questa volta usando build
fo2pdf [argomenti]
. Non
facendolo, si sovrascriverebbero le modifiche fatte al file FO,
rigenerando lo stesso PDF dell'inizio e dovendo rifare tutte le
modifiche daccapo.
Controllare se il problema risulta effettivamente risolto e se si, cercare il successivo problema.
Ripetere i punti dal 4 al 7 finchè non si è sistemato tutto il PDF.
Sebbene questo metodo di modificare il FO suggerisca che il problema sia nel file FO, in realtà non è vero. Il file FO è giusto, purtroppo Apache FOP non supporta tutte le specifiche carine definite dal formato XSL-FO (per il momento). Con le modifiche manuali, si costringe la generazione del PDF in un determinato modo.
È importante aggiustare le cose in ordine, dalla prima pagina all'ultima. Modificare il FO in un punto può comportare aggiustamenti verticali al corrispondente punto nel PDF: più linee, meno linee, linee che si spostano alla pagina successiva, ecc... Questi aggiustamenti possono influire su tutto ciò che segue.
Per lo stesso motivo, si dovrebbe sempre passare al
successivo problema solo dopo aver risolto il
precedente. Ad esempio, non farsi una lista di tutte le testate di
finestra (windowed headers
) e poi iniziare a
modificarle tutte insieme nel file FO. Aggiustando un widowed
header sposta tutto il testo che segue in giù, e può creare altri
windowed headers e toglierne altri.
In generale si potrebbe tenere aperto il file FO durante tutto il processo. Solo ricordarsi di salvare il file per rigenerare il PDF. Bisogna ricordarsi di chiudere comunque il file PDF prima di ogni rigenerazione: una volta che è aperto in Adobe (perfino nel Reader), gli altri processi non lo possono scrivere.
L'intero processo potrebbe diventare veramente lungo, così è meglio non aggiustare subito ogni piccola imperfezione, specialmente se si è alle prime armi nel maneggiare i file FO. In generale, solo le testate vedove sono veramente brutte, e rendono l'aspetto del documento veramente dilettantesco. Per fortuna, sono diventate rarissime da quando abbiamo adottato la versione FOP 0.93.
La prossima sezione tratta dei vari problemi e di come risolverli.
Problema: Si tratta di testate o di titoli che restano isolati (il termine tecnico è vedovi) alla fine della pagina.
Causa: Apache FOP non supporta ancora da
nessuna parte l'attributo keep-with-next
(mantieni con
successivo
).
Da quando si è aggiornato il sistema all'uso di Apache FOP 0.93, questo noiosissimo problema è diventato estremamente raro. Tuttavia in alcuni rari casi può ancora accadere. Oppure, più in generale, potrebbe esserci un salto pagina che sembra fastidioso, ad esempio dopo una linea che annuncia un seguito e finisce con due punti. Questa sezione aiuta a risolvere questi casi.
Notare che l'esempio che qui viene esemplificato, cioè una
testata di sezione vedova, non dovrebbe più succedere, ma è utile
per mostrare i passi da prendere, specialmente per gli elementi che
hanno un attributo id
.
Soluzione: Forzare un salto pagina all'inizio dell'elemento (tipicamente una lista, un elemento di lista o una tabella) a cui il titolo o la testata appartengono.
Come: Se l'elemento ha un attributo
id
(si può vedere nel sorgente
DocBook), si può allora cercare per quell'id nel file FO. Ad esempio,
supponendo di aver appena generato la Firebird 2 Quick
Start Guide e si sia riscontrato che il titolo
Creating a database using isql sia posizionato
alla fine di una pagina. Nel sorgente DocBook XML si può vedere che
quello è il titolo di una sezione il cui id è qsg2-databases-creating
. Cercando il testo
qsg2-databases-creating
dall'inizio del file FO, la
prima cosa che si trova è probabilmente qualcosa di questo
genere:
<fo:bookmark starting-state="hide"
internal-destination="qsg2-databases-creating">
L'elemento fox:outline
corrisponde al link nel pannello di navigazione alla sinistra del PDF.
Così questa non è ancora la sezione vera e propria, e bisogna cercare
oltre. Successivamente si trova:
<fo:block text-align-last="justify" end-indent="24pt"
last-line-end-indent="-24pt"><fo:inline
keep-with-next.within-line="always"><fo:basic-link
internal-destination="qsg2-databases-creating">Creating a database...
In questo caso, l'id è il valore d'un attributo in un fo:basic-link
. Pertanto ora siamo
nell'indice iniziale o tabella dei contenuti (Table of
Contents
). Ancora non è il posto giusto.
Il terzo ed il quarto tentativo sono spesso un paio di linee dopo il secondo, per creare il numero di linea alla citazione nell'indice. Ma il quinto tentativo è di solito quello che si stà cercando (a meno che non ci siano altri link in avanti alla sezione in questione):
<fo:block id="qsg2-databases-creating">
Eccolo qua! La maggior parte degli elementi gerarchicamente di
medio e basso livello in DocBook (preface
, section
, appendix
, para
ecc.) determinano un fo:block
nel file FO. Adesso si deve
modificare il file FO in modo da costringere Apache FOP a iniziare
questa sezione a pagina nuova. Si modifica la linea in questo
modo:
<fo:block id="qsg2-databases-creating" break-before="page">
Salvare la modifica e ricostruire il PDF, ricordandosi di usare build fo2pdf, e non build pdf. Il titolo della sezione adesso apparirà alla successiva pagina nuova, e si può passare al problema successivo.
E se l'elemento di DocBook non ha un suo id? Allora si dovrà
cercare il (o parte del) titolo o della testata. Questo sarà un po'
più complicato, perchè il titolo potrebbe contenere un a capo nel
file FO, nel qual caso non verrebbe trovato. Oppure il titolo
potrebbe contenere dei suoi elementi figli (ad esempio quote
o emphasis
). Questo impedirebbe di trovare
il titolo completo. D'altra parte più si stringe il testo da
cercare, più alta sarà la probabilità di trovare cose non correlate.
In questo caso si dovrà adoperarre il proprio metro di gudizio; Se
ad esempio c'è del testo riconoscibile subito prima o subito dopo il
titolo che si può cercare facilmente, si può provare a trovare il
titolo nelle linee sopra o sotto di esso.
Ad ogni modo, una volta che l'avete trovato, risalite nel file FO finchè non si trova l'inizio della sezione, spesso identificabile con un numero di id autogenerato:
</fo:block> <fo:block id="d0e2340"> <fo:block> <fo:block> <fo:block keep-together="always" margin-left="0pc" font-family="sans-serif,Symbol,ZapfDingbats"> <fo:block keep-with-next.within-column="always"> <fo:block font-family="sans-serif" font-weight="bold" keep-with-next.within-column="always" space-before.minimum="0.8em" space-before.optimum... space-before.maximum="1.2em" color="#404090" hyph... text-align="start"> <fo:block font-size="11pt" font-style="italic" space-before.minimum="0.88em" space-before.opti... space-before.maximum="1.32em">The DISTINCT keyword comes to the rescue!</fo:block>
Come si può vedere, ci possono essere un bel po' di righe tra l'inizio della sezione ed il titolo del testo. Notare, inoltre, come il titolo qui è diviso su due linee.
Una volta identificato il fo:block
che corrisponde all'inizio della
sezione, basta mettergli un attributo break-before="page"
proprio come si è
fatto prima.
Perchè risalire e cercare l'inizio della sezione e non mettere
il break-before
al fo:block
che racchiude direttamente il
titolo? Be', perchè ciò stamperà sì il titolo nella pagina
successiva, giustamente, ma i link nel frame di navigazione e
nell'indice punteranno (oibò!) alla pagina precedente, perchè la
«invisibile» sezione inizia - cioè il blocco che ha
l'ID - prima del salto pagina forzato.
Come già detto, il problema delle testate vedove non dovrebbe più accadere con le sezioni, ma potrebbe presentarsi con qualche altro tipo d'oggetto, come le tabelle o le figure. In tutti questi casi si possono usare le tecniche illustrate qui sopra.
Inoltre, ci sono molti elementi DocBook (di fatto, la maggior
parte) per i quali i fogli di stile non generano ID. Esempi sono
para
, informaltable
, i vari tipi di liste, ecc.
In tali casi, una volta trovato il frammento di testo del file FO,
si tratta di applicare semplicemente l'attributo break-before
al più vicino fo:block
che ha un ID.
Problema: In una tabella, una riga è interrotta da un salto pagina per cui non è tutta da una parte o dall'altra. Lo stesso dicasi per gli elementi di una lista.
Causa: Nessuna in particolare - non c'è una regola che impedisca i salti pagina in questi casi particolari.
Soluzione: Per tenere la riga insieme, inserire un salto pagina all'inizio della riga.
Come: Cerca la riga sulla base del testo
all'inizio della riga o alla fine della riga precedente. L'elemento
che si sta cercando è fo:table-row
,
ma non si deve usare come stringa di ricerca, perchè molti elementi di
DocBook (non solo per le tabelle, cioè gli elementi <table>
) sono implementati usando fo:table
e pertanto contengono fo:table-row
s.
Una volta trovato l'inizio della riga tagliata a metà, si
aggiunge un attributo break-before
esattamente come per i
windowed headers:
<fo:table-row break-before="page">
In alternativa si può sempre impostare un attributo break-after
alla riga precedente.
Problema: Spazi molto larghi per giustificare linee precedenti lunghe stringhe senza spazi. Queste stringhe lunghe sono spesso stampate con font a spazio fisso:
Causa: Apache FOP spesso non sillaba queste stringhe e le prende come un tutt'uno. Pertanto, se la stringa non entra nella riga la sposta interamente nella riga seguente. Questo lascia alla linea precedente «troppo poco» testo, rendendo necessaria una giustificazione con larghi spazi. Notare come nell'esempio qui sopra, gli spazi nella linea sopra siano causati dall'incapacita di suddividere la stringa della linea successiva, e non dal contenuto della linea precedente stessa.
Soluzione: Ci potrebbero essere buone
ragioni per non suddividere la stringa. In quel caso ci si adatta ai
larghi spazi facendo buon viso a cattivo gioco. Altrimenti si
inserisce uno spazio (oppure il carattere '-
'
seguito da uno spazio) al punto dove si desidera separare la
stringa.
Come: Prima bisogna trovare la stringa nel
file FO cercando il (o parte del) suo contenuto. Se è una stringa a
spazio fisso nel PDF, molto probabilmente la si dovrebbe trovare in un
elemento fo:inline
. Poi, si osserva
nel PDF per valutare quanta parte della stringa ancora ininterrotta
entrerebbe nello spazio rimasto della linea precedente. Di nuovo nel
file FO, si inserisce uno spazio, possibilmente preceduto da un
«-», nella stringa al punto in cui sembra accettabile
mandarla a capo. Rigenerare il PDF (build fo2pdf !)
e verificare il risultato. Se si è interrotta la stringa troppo a
destra, rimane ancora tutta nella linea successiva. Troppo a sinistra
e lo spazio potrebbe rimane ancora troppo largo rispetto alle proprie
intenzioni. Si continua a sistemare e a ricostruire finchè non si
ottiene l'aspetto desiderato.
Durante questo procedimento, si potrebbe essere sorpresi dal fatto che, una volta interrotta la stringa in un punto, Apache FOP autonomamente decide di sillabare il resto della stringa. Questo lascia una parte della stringa nella linea precedente con lo spazio aggiunto (adesso nel posto sbagliato) perchè prosegue oltre quel punto. Non resta che cancellare lo spazio che si è aggiunto e interrompere la stringa nel punto deciso da Apache.
Una soluzione alternativa al problema degli spazi enormi sarebbe inserire spazi di dimensione zero proprio in tutti i punti in cui la stringa in esame potrebbe essere mandata a capo, lasciando decidere Apache FOP quale è il più adatto. Questo funziona sicuramente al primo tentativo, ma si può fare solo a queste condizioni:
avendo un editor che permette di inserire facilmente gli ZWSP;
dove è possibile interrompere la stringa senza il «-»;
Problema: Tabelle, figure o altri oggetti formali vengono spiaccicati oppure alcune loro parti sono stampate sopra altre.
Causa: Agli oggetti formali viene dato un
un attributo nel foglio di stile keep-together.within-page="always"
(mantieni insieme nella pagina sempre). Con FOP 0.93, questo attributo
è sempre forzato, anche se l'oggetto è troppo grande per stare in una
pagina. Il risultato: il contenuto distrutto è strizzato tutto dentro
la pagina.
Soluzione: Ci sono tre alternative. 1: Usare il corrispondente elemento DocBook informale. 2: Inserire una elaborazione di istruzioni nel sorgente DocBook. 3: Rimuovere l'attributo dal sorgente FO.
Come: Due soluzioni sono applicate al sorgente DocBook, la terza implica la modifica del file FO:
Se non si vuole lasciare gli elementi senza titolo, si può
usare informalequation
/
informalexample
/ informalfigure
/ informaltable
invece delle loro
controparti formali, rispettivamente, equation
, example
, figure
e table
. Questi elementi non prendono
l'attributo keep-together
nella trasformazione, in tal modo il salto pagina viene
all'interno dell'elemento.
Se riguarda una tabella, volendo mantenere il titolo, si può inserire una elaborazione di istruzioni (processing instruction) come questa:
<table frame="all" id="ufb-about-tbl-features">
<?dbfo keep-together='auto'?>
<title>Summary of features</title>
...
(table content...)
...
</table>
Aggiungere l'istruzione modificando il codice sorgente è abbastanza semplice. Con XMLMind, è un pochino più laborioso:
Mettere il cursore da qualche parte del titolo o selezionare tutto l'elemento del titolo.
Scegliere Modifica -> Elabora Istruzione -> Inserisci Istruzione di Elaborazione Prima dal menù. Apparirà sopra il titolo una linea, di solito verde ma ciò dipende dai colori scelti.
Digitare keep-together='auto'
su
quella linea.
Con il cursore ancora su quella linea, scegliere Modifica -> Inserisci Istruzione di Elaborazione -> Cambia l'Obiettivo dell'Istruzione di Elaborazione dal menu. Si apre una finestra di dialogo.
Nella finestra di dialogo, modificare la parola
target
in dbfo
e
cliccare su OK.
A proposito, si può fare l'opposto con una informaltable
se si desidera
assolutamente che non venga interrotta da un salto pagina. La
procedura è identica, eccetto che si deve specificare
always
invece di auto
.
Ovviamente bisogna essere più che sicuri che la informaltable ci
stia nella pagina!
Non sono stati previste soluzioni similari per altri oggetti formali perchè probabilmente non ce ne sarà mai bisogno. Cose di questo genere richiedono molto lavoro nei nostri fogli di stile personalizzati, pertanto li implementeremmo solo in caso di reale necessità.
L'ultima risorsa è mettere mano al file fo... pertanto,
aprire il file FO, trovare l'elemento (suggerimento: dargli un
id
nel sorgente DocBook per
trovarlo facile facile) e togliere l'attributo keep-together.within-page="always"
. Lo
svantaggio, già si sa, è che bisogna rifarlo tutte le volte che si
cambia il sorgente e viene costruito un nuovo PDF. Le altre
soluzioni sono invece durature.
La pagina web uffilciale di XSL-FO (Formatting Objects) è qui: http://www.w3.org/TR/xsl/
La pagina di Apache FOP è qui: http://xmlgraphics.apache.org/fop/
La pagina di adeguamento di Apache FOP è qui: http://xmlgraphics.apache.org/fop/compliance.html. Contiene una grande tabella di supporto agli oggetti in cui si può verificare quali oggetti ed attributi (proprietà) XSL-FO sono supportati. Consultando la tabella, si tenga presente che attualmente si sta adoperando Apache FOP 0.93 (con alcune modifiche).
Firebird Documentation Index → Come fare il manuale di Firebird → Avanzato: perfezionare i PDF |