momente şi schiţe de informatică şi matematică
anti point—and—click

Caractere (vechi şi noi), cu PostScript (VI)

PostScript
2020 jun

Exerciţiu: confruntarea numelor de caracter

În [1] semnalam dicţionarul GS /AdobeGlyphList; acesta are 4200 de intrări, asociind numelor de caracter posibile în fişiere-font PS, „coduri universale” din Unicode:

vb@Home:~/20-iun$ gs -q    # sesiune interactivă Ghostscript
GS> (/usr/share/ghostscript/9.26/Resource/Init/gs_agl.ps)  run
GS> AdobeGlyphList length  ==
4200
GS>[/abreve /scommaaccent /ahiragana /whitediamondcontainingblacksmalldiamond] 
    {AdobeGlyphList exch get ==}  forall
GS<1> 259  % /abreve ă  (HTML: &#259; sau &abreve;)
537        % /scommaaccent ș  (HTML: &#537;)
12354      % /ahiragana   (HTML: &#12354;)
9672       % /whitediamondcontainingblacksmalldiamond   (HTML: &#9672;)
GS> quit

În [1] exprimasem bănuiala că 33 dintre cele 35 de fonturi PS de bază, conţin drept chei în dicţionarele CharStrings aceleaşi 1004 nume de caracter (dintre cele 4200 posibile, înregistrate în /AdobeGlyphList); cum am verifica aceasta, cât mai simplu?

Obs. Pentru a învăţa să foloseşti limbajul PostScript, trebuie să-ţi faci două obiceiuri: să consulţi din când în când §8.2 Operator Details din PLRM şi pe de altă parte, să experimentezi în sesiuni de lucru interactiv cu Ghostscript.
Ideea de bază în procesul de confruntare între ele a numelor de caracter din diversele fonturi, constă în folosirea operatorului known:

vb@Home:~/20-iun$ gs -q
GS> /ChrStr /Times-Roman findfont /CharStrings get def
GS> ChrStr /abreve known   % caută cheia '/abreve' în dicţionarul 'ChrStr'
GS<1>pstack
true   % există!
GS<1>pop
GS> ChrStr /ahiragana known
GS<1>pstack
false   % numele de caracter '/ahiragana' NU există (în /Times)

Fonturile dintr-o aceeaşi familie modelează aceleaşi caractere (diferind stilul glifelor: regulat, italic, oblic, bold, etc.); deci este suficient să considerăm câte unul din fiecare familie (dar ignorăm deocamdată, /Symbol şi /ZapfDingbats):

%!  confront.ps
/fonts [ /AvantGarde-Demi /Bookman-Light /Courier /Helvetica 
         /NewCenturySchlbk-Roman /Palatino-Roman /Times-Roman
         /ZapfChancery-MediumItalic ] def  % /Symbol /ZapfDingbats 

Să fixăm, prin /ChrStr, dicţionarul "CharStrings" al unuia dintre aceste fonturi, sau (cum preferăm aici) dintr-o derivată stilistică a acestuia (alegem Times-Italic):

/ChrStr /Times-Italic findfont /CharStrings get def

Putem constata într-o sesiune interactivă GS, că acest ChrStr are 1004 elemente (prin comanda: ChrStr length ==) şi că dicţionarele "CharStrings" ale celor opt fonturi indicate în tabloul fonts au deasemenea, lungimea 1004:
      fonts {findfont /CharStrings get length} forall  pstack

Obs. Amintim că "CharStrings" conţine perechi < cheie -string- >, unde cheie este un nume PS de caracter, iar -string- reprezintă criptat o anumită secvenţă de instrucţiuni PS prin care se produce traseul grafic al caracterului respectiv.
(putem afişa componentele fiecărei perechi prin: ChrStr {== ==} forall)

Următoarea procedură presupune că vom fi adus pe stivă dicţionarul "CharStrings" al unuia dintre fonturi; se parcurg (prin forall) elementele acestuia (descărcând prin pop partea -string-) şi se verifică prin known dacă numele curent întâlnit se regăseşte în dicţionarul ChrStr (dacă da, atunci descărcăm cheia respectivă, trecând la următoarea; dacă nu, atunci descărcăm şi afişăm cheia respectivă prin operatorul ==, trecând apoi la următorul element al dicţionarului din stivă):

/find_diff {  % pe stivă: dicţionarul CharStrings al unui font
    { pop dup ChrStr exch  % stiva: CharStrings, cheie, ChrStr, cheie
      known {pop}{==} ifelse }  % cheie se găseşte în ChrStr?
                                % pe stivă rămâne numai CharStrings
    forall  % repetă blocul {...} pentru toate elementele din CharStrings
} bind def

Pentru fiecare font din tabloul fonts, scoatem pe stivă dicţionarul "CharStrings" al său şi invocăm find_diff (programul „principal” al fişierului):

fonts {
    findfont /CharStrings get  
    find_diff
} forall

Lansând programul de 16 linii desfăşurat mai sus: gs -q confront.ps, constatăm că nu se afişează nicio cheie; aceasta înseamnă că toate cheile din dicţionarul "CharString" al fiecăruia dintre fonturile respective, au fost regăsite în dicţionarul „martor” ChrStr. Altfel spus, cele 33 de fonturi considerate mai sus conţin aceleaşi 1004 caractere (încât, „bănuiala” iniţială este acum confirmată).

Folosind apoi /find_diff pentru fonturile rămase:
      /Symbol findfont /CharStrings get find_diff
(şi analog pentru ZapfDingbats) pe ecran se vor afişa câteva zeci de nume de caracter prezente în aceste două fonturi şi care nu se regăsesc în ChrStr (dar sunt prezente în dicţionarul /AdobeGlyphList).

Desigur, se conturează acum o noua încercare de programare PS: să formulăm un catalog comun, pentru toate fonturile numite în tabloul /fonts – cam aşa:

În antetul fiecărei pagini scriem (prescurtat) numele fonturilor; apoi, pe fiecare rând, scriem glifele care corespund în fiecare font câte unui aceluiaşi nume de caracter.
Pe fiecare coloană (exceptând ultima) am avea glifele dintr-un acelaşi font (cel al cărui index în antetul paginii este egal cu rangul coloanei), corespunzătoare numelor de caracter indicate pe ultima coloană a paginii.

docerpro | Prev | Next