[1] partea a VI-a
Considerăm iarăşi – v. [1] – cele 33 de fonturi PS "Type 1" pentru care dicţionarul /CharStrings
aferent are 1004 intrări (formate pe aceleaşi nume de caracter); alegem 8 dintre aceste fonturi (preferând totuşi, câte unul din fiecare familie):
%!PS confCat.ps (bbsort.ps) run % /sort_cvs (ordonează alfabetic un tablou; v. „partea a V-a”) /Fonts [/AvantGarde-Demi /Bookman-Light /Courier /Helvetica /NewCenturySchlbk-Roman /Palatino-Roman /Times-Roman /ZapfChancery-MediumItalic] def
Vrem să formulăm un tabel cu 8 coloane şi 1004 linii, conţinând glifele fonturilor din tabloul /Fonts
– adică, redând aici produsul final:
Intrările pe coloană corespund fonturilor, iar cele pe linie – numelor de caracter (pe care le-am scris în dreapta tabelului fiindcă lungimea acestora variază).
Vom proceda cam la fel ca în glyphCat.ps din „partea a V-a” – program care tabela glifele unui font indicat (în ordinea alfabetică a numelor de caracter); în fond, acum vom „rescrie” cumva, acest program.
În exerciţiile anterioare formulam „din aproape în aproape” (sau „de jos în sus”), scriind o procedură sau alta numai după ce puneam la punct toate sub-procedurile pe care le implică aceasta; în particular, procedura „principală” era formulată la sfârşitul fişierului PS respectiv. De data aceasta, începem cu acele două proceduri care exprimă esenţa lucrului (amânând pe cele „ajutătoare”): constituim un tablou cu numele de caracter comune (ordonate alfabetic) şi îl parcurgem aplicând gliphshow
fiecărui nume, pentru toate fonturile consemnate în tabloul /Fonts
.
Prin următoarea procedură constituim tabloul PS Keys
, conţinând cele 1004 nume de caracter, în ordine alfabetică (fără distincţie de caz pentru litera iniţială):
/storeKeys { /Times-Italic findfont /CharStrings get % pe stivă: perechi <nume "-string-"> {pop} forall % descarcă "-string-", din toate perechile count array astore % pe stivă: un tablou PS cu cheile din /CharString /Keys exch def % „salvează” tabloul cheilor în 'Keys' (variabilă „globală”) Keys sort_cvs % ordonează alfabetic după numele glifelor } bind def
Tabelul dorit se va obţine scriind pentru fiecare nume de caracter din tabloul Keys
, glifele corespunzătoare acestuia în fonturile specificate în tabloul Fonts
(rămânând de văzut cum trecem de la un rând la cel următor şi de la o pagină la următoarea):
/glyphList { % procedura „principală” storeKeys % creează tabloul 'Keys' (numele glifelor, alfabetic) newPage % iniţializează prima pagină (scriindu-i antetul) Keys { writeGlyphs } forall % scrie cele 8×1004 glife, pagină după pagină showpage % ejectează ultima pagină } bind def
Obs. Următorul mic experiment ne arată cumva, diferenţa dintre interpretare (sau „citirea programului” de către interpretorul PS) şi execuţie. Salvăm în acest moment, fişierul "confCat.ps" şi-l încărcăm într-o sesiune interactivă de lucru cu Ghostscript:
vb@Home:~/20-iun$ gs -q GS> (confCat.ps) run GS> storeKeys GS> Keys length == 1004 GS> glyphList Error: /undefined in newPage
Nu se produce nicio eroare la citirea programului (chit că se implică subproceduri care nu sunt încă, definite); s-a putut executa /storeKeys
(care este complet definită), dar nu şi /glyphList
(a cărei definiţie lipseşte în acest moment, din fişierul încărcat).
În ierarhia logică a importanţei, urmează să formulăm subprocedura writeGlyphs
; aceasta produce glifele din fonturile specificate în tabloul /Fonts
, corespunzătoare numelui de caracter care îi este transmis pe stivă:
/writeGlyphs { % pe stivă: un nume de caracter din tabloul 'Keys' /key exch def % salvează numele din stivă în variabila globală 'key' 18 newLine id0 Fonts { % scrie pe un rând glifele din cele 8 fonturi, pentru 'key' findfont 24 scalefont setfont key glyphshow nextpos id1 % avansează 'currentpoint' la următoarea coloană a rândului } forall fontEntry setfont % scrie pe ultima coloană, numele de caracter din 'key' -10 0 rmoveto key 20 string cvs show currentpoint exch pop neg 700 lt % trece la un nou rând (dacă încape), sau la o nouă pagină {18 newLine} {showpage newPage} ifelse } bind def
De observat că după completarea unui rând de glife, se trece pe rândul următor dacă nu s-a ajuns încă la baza paginii curente; altfel, se ejectează pagina curentă (prin showpage
) şi se iniţializează o nouă pagină. Aceasta înseamnă că dacă pe ultima pagină, după ce s-a scris ultimul rând, încă ar fi loc pentru un nou rând – atunci această ultimă pagină trebuie ejectată direct (vezi ultima instrucţiune din /glyphList
).
Mai rămâne să scriem procedurile „ajutătoare”, prin care poziţionăm glifele una lângă alta pe un acelaşi rând, sau trecem pe rândul următor sau pe următoarea pagină:
/newLine { % <dy> newLine /dy exch def currentpoint exch % pe stivă: y x pop dy sub 0 exch moveto % y dy | y1=y-dy 0 | 0 y1 | moveto } bind def /fontEntry {/Times-Italic findfont 12 scalefont} bind def % font chei şi antet /Header { % scrie (prescurtat) numele fonturilor, la începutul fiecărei pagini fontEntry setfont (AvG-De Bkm-Li Courier Helvet NCenSc-Ro Palat-Ro Times-Ro ZapfCha) show 12 newLine } bind def /newPage {54 800 translate 0 0 moveto Header} bind def % format "A4" /id0 {/idx 0 def} def % vizează prima glifă de pe rândul curent /id1 {/idx idx 1 add def} def % vizează glifa următoare celei curent scrise /nextpos { % poziţia pe rând a următoarei glife (50 puncte pentru fiecare) currentpoint pop 50 idx 1 add mul exch sub 0 rmoveto } bind def glyphList % pune în execuţie procedura principală a fişierului
Se poate constata că am păstrat definiţiile (schimbând cel mult denumirea) din glyphCat.ps pentru newLine
, nextpos
şi chiar (dar acum, cu alt rol) id0
şi id1
; desigur, faptul că am denumit la fel procedurile principale ("glyphList
") este o gafă (dar uşor de îndreptat, dacă ar fi cazul de a folosi împreună cele două fişiere).
Pentru că în finalul fişierului confCat.ps am invocat deja procedura principală glyphList
, putem obţine fişierul final PDF prin comanda (vezi exerciţiile precedente):
ps2pdf -dNOSAFER -dPDFSETTINGS=/prepress -dEmbedAllFonts=true confCat.ps
Rezultă astfel fişierul confCat.pdf (redat aici la început), conţinând 51 de pagini (cu câte 20 rânduri de glife, exceptând ultima pagină, cu numai 4 rânduri).
vezi Cărţile mele (de programare)