Technical Article

Oblikovanje arapskog i RTL teksta u Delphi PDF-ovima s HotPDF-om

Proslijedite arapsku frazu يوضح ملف PDF metodi TextOut i otvorite rezultat. Slova idu u pogrešnom smjeru i svako stoji u svom izoliranom obliku s vidljivim razmakom prije sljedećeg, kao da je netko utipkao engleski unatrag i pritisnuo razmaknicu između svakog znaka. Nikakva iznimka nije prijavljena. Nikakvo upozorenje nije ispisano. Izlaz je jednostavno pogrešan, i to zato što se dvije zasebne transformacije o kojima arapski jezik ovisi nikada nisu dogodile. Poznavanje tih dviju transformacija i poziva koji ih izvodi čini većinu onoga na što se svodi ispis složenih pisama u PDF.

HotPDF je izvorna VCL PDF komponenta za Delphi i C++Builder, a rad s pismom zdesna nalijevo obavlja umjesto vas kroz zaseban poziv. Ona također staje na nekoliko specifičnih mjesta koja želite znati prije nego što se obvežete na podršku za određenu lokalizaciju, pa iskrene granice njezinih mogućnosti dobivaju vlastiti odjeljak pri kraju članka.

Zašto se ispravan niz znakova i dalje ispisuje pogrešno

Unicode čuva tekst u logičkom redoslijedu, onom kojim ga tipkate i čitate naglas. Renderer mora postaviti glifove vizualnim redoslijedom. Za pisma slijeva nadesno ti se redoslijedi podudaraju i nitko o tome ne razmišlja. Za arapski i hebrejski to nije slučaj, a kada jedna linija miješa smjerove, recimo arapska rečenica koja sadrži latinični pojam "PDF" ili cijenu napisanu brojkama, Unicode dvosmjerni algoritam (UAX #9) odlučuje točno kako se fragmenti slijeva nadesno ugnježđuju unutar linije zdesna nalijevo. To je prva transformacija – promjena redoslijeda, a njezino preskakanje je ono što preokreće liniju.

Druga transformacija je oblikovanje prema kontekstu (contextual shaping). Arapsko slovo se crta drugačije ovisno o tome gdje se nalazi u riječi: na početku, u sredini, na kraju ili samostalno. Kodna točka (codepoint) ostaje ista cijelo vrijeme; mijenja se samo glif. Tijek obrade koji svaku kodnu točku prosljeđuje izravno njezinom zadanom glifu proizvodi upravo onaj nepovezani, izolirani izlaz iz uvodnog odlomka. Hebrejski preskače ovaj korak jer se njegova slova ne spajaju, ali i dalje zahtijeva promjenu redoslijeda. Arapskom je potrebno oboje, i zato je arapski, a ne hebrejski, niz znakova s kojim testirate.

Na stolnom računalu ništa od ovoga nije vaš problem. Kada VCL obrazac iscrtava arapski u kontrolu TEdit, tekstualni stog operacijskog sustava tiho mijenja redoslijed i oblikuje ga, što je upravo razlog zašto niz znakova koji izgleda savršeno na zaslonu ispada pokvaren u jednostavnom PDF-u. Tok sadržaja ne pohranjuje tekst koji se može uređivati. On pohranjuje pozicionirane glifove, tako da onaj tko emitira tok nasljeđuje posao oblikovanja koji je operacijski sustav prije obavljao. RtLTextOut je poziv koji preuzima taj posao.

RtLTextOut vrši promjenu redoslijeda i spajanje

HotPDF drži latinični put i put za složena pisma kao dvije različite metode. TextOut ispisuje ono što mu date redoslijedom kojim mu to date. RtLTextOut najprije mijenja redoslijed i pokreće kontekstualnu analizu, a zatim ispisuje. Koja pravila pisma primjenjuje dolazi iz argumenta charset u SetFont: 178 označava arapski, 177 označava hebrejski.

Jedna pogreška troši više sati otklanjanja pogrešaka nego bilo koja druga ovdje. RtLTextOut sam okreće niz znakova, pa ako mu proslijedite tekst koji ste već ručno okrenuli (obično privremeno rješenje preostalo iz ranijeg pokušaja s običnim TextOut-om), on će ga ponovno okrenuti i vratit ćete se na početak. Okrutan dio je taj što dvostruko okrenuti tekst može izgledati ispravno za jedan testni niz koji je u potpunosti na arapskom, a zatim se raspasti čim linija sadrži latiničnu riječ ili broj, jer ti ugrađeni dijelovi više ne prate UAX #9. Uvijek proslijedite logički redoslijed i pustite da poziv sam to riješi.

Isto to ponašanje s miješanim smjerom češće zbunjuje recenzente nego kod. Unutar linije zdesna nalijevo, znamenke i ugrađene latinične riječi i dalje se čitaju slijeva nadesno. Netko tko nije radio s dvosmjernim rasporedom pogledat će renderirani račun, vidjeti broj računa koji se čita na "pogrešan" način u odnosu na arapski oko njega i prijaviti to kao pogrešku. To je rezultat koji je točan prema specifikaciji. Kratka bilješka u vašim kriterijima prihvaćanja, napisana prije prve provjere izvornog govornika, štedi taj povratni krug rasprave.

Pokrivenost glifovima se odlučuje prije nego što oblikovanje uopće započne

Oblikovanje bira glifove iz fonta. Ako ih font ne sadrži, nema se što odabrati. To je neuspjeh pri implementaciji koji uzalud troši cijelo popodne: izvještaj je besprijekoran na razvojnom programskom računalu gdje je Arial Unicode MS instaliran, a ispada kao niz praznih okvira na klijentovom poslužitelju, gdje je Windows zamijenio font nekim koji uopće nema arapski. Lijek je prestati vjerovati fontovima koje određeno računalo ima i registrirati onaj koji šaljete s aplikacijom.

Dvije granice dolaze s ovim. Font registriran putem RegisterUnicodeTTF se ugrađuje, a HotPDF-ovo rukovanje ugrađenim Unicodeom zahtijeva dokument u verziji PDF 1.5 ili novijoj. To stvara probleme samo ako nešto dalje u lancu inzistira na PDF 1.4, no kada se to dogodi, simptom je tih. Druga je granica pravne prirode: TrueType datoteke nose bitove dopuštenja za ugradnju, pa font koji se lijepo crta na zaslonu i dalje može biti licenciran na način koji zabranjuje njegovo slanje unutar prilagođenih dokumenata.

Taj drugi poziv, GetUnicodeGlyphForCodepoint, vaš je sustav ranog upozorenja. Prođite kroz raspon kodnih točaka koje vaši podaci stvarno koriste prilikom pokretanja usluge i zabilježite koji se ID-ovi glifova vraćaju. Nedostatak pokrivenosti tada se prikazuje kao linija u zapisniku pokretanja tijekom uvođenja sustava, a ne kao znakovi koji nedostaju na računu koji je već stigao do kupca.

Tekst koji je Unicode, ali nije zdesna nalijevo – poput CJK nizova, vijetnamskog s njegovim naslaganim dijakritičkim znakovima, miješanog europskog teksta – ide kroz uobičajenu putanju. TextOut prima WideString i crta ga kroz registrirani font bez ikakve dvosmjerne analize. Isplati se držati te dvije putanje fizički odvojene u kodu izvještaja, jednu rutinu za RTL izvođenja i jednu za sve ostalo, tako da je logika lokalizacije vidljiva na samom mjestu poziva umjesto da bude skrivena iza zastavice koju će netko na kraju zaboraviti postaviti.

Redoslijed čitanja pripada dokumentu, a ne glifovima

Ispravan prikaz svakog glifa i dalje ostavlja jednu stvar nedovršenom. ISO 32000-1 §12.2 definira postavku preglednika zvanu /Direction koja navodi cjelokupni redoslijed čitanja dokumenta. To ne utječe na glifove. Ono što radi jest da govori pregledniku kako organizirati dvostruke stranice (two-up spreads), s koje strane bi trebao početi raspored nasuprotnih stranica i prema kojem smjeru bi se korisničko sučelje za čitanje trebalo naginjati. Ništa se od toga ne vidi na jednoj stranici, što je upravo razlog zašto se to zaboravlja.

Postavljanje Direction je cijeli posao: postavljanje tog svojstva dodaje vpDirection u ViewerPreferences dokumenta, pa jedna linija koda prenosi tu postavku u datoteku. Neuspjeh je njezino izostavljanje, što se čini bezopasnim jer probna jednostrana stranica u koju gledate izgleda identično u oba slučaja. Zatim netko ispiše obostranu knjižicu, stranice ispadnu zrcaljene, a uzrok je nedostatak te jedne linije napisane tjednima ranije.

Gdje završava HotPDF-ovo oblikovanje

Iskren pregled ograničenja vrijedi tjedan dana evaluacije. RtLTextOut samostalno pokriva dvosmjernu promjenu redoslijeda i arapsko spajanje prema kontekstu. Ono što ne čini automatski je opća primjena OpenType značajki. Izborni ligaturni i slični tipografski oblici idu kroz GetSingleSubstituteGlyph(GID, 'liga'), koji razrješava jednu po jednu zamjenu, najprije s ID-om glifa, a zatim sa zastavicom značajke, te vraća nepromijenjeni ulazni glif kada se značajka ne primjenjuje. To je dovoljno za upravljanje poznatim, konačnim popisom ligatura koji sami održavate. To nije potpuni GSUB pokretač. Za pisma koja trebaju više od same promjene redoslijeda i spajanja – pri čemu su indijska pisma sa svojim vokalnim znakovima koji mijenjaju redoslijed klasičan primjer – pokrenite stvarni pilot projekt na pravim korisničkim nizovima prije nego što obećate podršku za tu lokalizaciju. To što arapski radi nije dokaz da će raditi i Devanagari.

Provjerite proces od kraja do kraja, jer stranica može izgledati ispravno, a i dalje biti beskorisna za sve dalje u lancu obrade. Tri provjere pronalaze većinu problema. Kopirajte tekst natrag iz Acrobata i usporedite kodne točke s vašim izvornim nizom. Pokrenite pretragu unutar dokumenta u pregledniku za riječ koju možete vidjeti na stranici. I otvorite izlaz na računalu koje nema vaše razvojne fontove, što će najvjerojatnije otkriti neželjenu zamjenu fonta. Ništa od toga ne zamjenjuje izvornog čitatelja koji gleda jedan stvarni dokument, što otkriva stvari koje nikakav sintetički korpus neće. Stavite taj pregled u kalendar prije nego što format krene u isporuku.

Odaberite testne nizove namjerno umjesto recikliranja onoga što je prevoditelj poslao prošle godine. Uzorak minimuma po lokalizaciji: rečenica na čistom pismu, rečenica s ugrađenim latiničnim nazivima brendova, linija koja nosi znamenke i valutu, te imena s dijakritičkim znakovima ili kombiniranim oznakama. Stvarna imena klijenata ruše pretpostavke koje ogledni tekst ostavlja netaknutima, pa neka se skup za testiranje regresije poveća za jedan niz svaki put kada slučaj korisničke podrške otkrije uzorak koji do tada niste vidjeli.

Registracija fontova, izdvajanje podskupa (subsetting) i svakodnevni API za crtanje teksta opisani su u članku o izlazu izvještaja, fontovima i slikama s HotPDF-om. Kada isti dokumenti moraju zadovoljiti i profile pristupačnosti, pravila za označavanje jezika i strukturu u članku o provjeri valjanosti PDF/A i PDF/UA nadograđuju se na rad oblikovanja teksta koji je ovdje opisan.

API-jevi za pismo zdesna nalijevo i Unicode fontove opisani iznad isporučuju se s HotPDF komponentom za Delphi i C++Builder; stranica proizvoda sadrži poveznicu na cjelovitu dokumentaciju o ispisu teksta.