Delphi-utviklere forventer generelt at en streng tegnes til et dokument i nøyaktig samme visuelle rekkefølge og form som den vises i koden eller minnet. For engelsk og de fleste vesteuropeiske språk er den antagelsen sann: én char er lik én visuell glyff, tegnet fra venstre til høyre, isolert. Det varselet de fleste får om at denne antagelsen var farlig lokal, er når koden deres første gang forsøker å tegne arabisk, hebraisk, farsi eller thai inn i en PDF. Strengene kommer ut baklengs, bokstavene kobles ikke sammen slik de skal, og modifikatorene henger i løse luften. Du har kjørt på problemet med tekstforming (text shaping) for komplekse skript, og et rent teksttegnekall er ikke lenger tilstrekkelig for å løse det
Hvorfor arabisk mislykkes uten forming
Skjermer skjuler dette problemet fordi Windows ordner det for deg. VCL-kontroller delegerer teksttegning til Uniscribe (og nyere DirectWrite), Windows' tekstformingsmotor. Dens jobb er å ta en minne-buffer av tegn og kartlegge dem til visuelle glyffer. I et skript som arabisk skrives bokstavene fra høyre til venstre, så ordningen må snus. Mer kritisk, arabisk er kursivt. En enkelt bokstav endrer form (glyff) helt, basert på om den er i begynnelsen, midten, enden av et ord, eller står alene (initial, medial, terminal, og isolert form). Fonten inneholder alle fire, men Unicode-strengen inneholder bare ett logisk tegn. Det er formerens (shaper) jobb å inspisere konteksten og erstatte det ene tegnet med en av de fire glyffene, og i tillegg avgjøre hvordan flere glyffer kan kombineres til en enkelt ligatur
PDF er på den andre siden av den prosessen. Et PDF-dokument aksepterer ikke logiske tegn og forventer at seeren (viewer) former dem. PDF er et eksakt sidebeskrivelsesspråk, så innholdsstrømmen er en fastlagt liste med instruksjoner for visning: "tegn glyff #144 på X: 100, Y: 100, tegn deretter glyff #72 på X: 105". Når du sender en rå arabisk streng til standard TextOut-funksjoner i eldre biblioteker, skriver de den sekvensielt venstre til høyre ved å bruke standard isolerte glyffer. Liten arabisk-lesende bruker vil gjenkjenne resultatet som skrevet tekst
Hva RtLTextOut former for deg
HotPDF bærer ikke hele tekstformingskompleksiteten internt. I stedet utnytter den Delphis Uniscribe-modul for å konvertere de logiske tegnene til deres riktige sekvens av glyffer og forskyvninger, og oversetter deretter den posisjonerte glyff-sekvensen til native PDF-kommandoer som bibeholder visningen eksakt, slik at formingen blir hardkodet inn i dokumentet uansett om sluttbrukerens seer (viewer) har riktige font- eller formingsoppsett
For å tegne høyre-til-venstre eller kompleks tekst, bytter du fra det generelle TextOut-kallet til det spesifikke DrawComplexText (noen ganger oppkalt via TextOut-overbelastninger som håndterer flagg eller Uniscribe eksplisitt i dokumentasjonen for HotPDF). Klargjøring av fonten er avgjørende: en font uten arabiske tabeller kan ikke tvinges til å tegne formet arabisk, selv av Uniscribe. Du må bygge inn en TTF/OTF-font som du har validert inneholder de riktige skriptene og ligaturtabellene, for eksempel Arial, Tahoma eller Segoe UI
Når omordning og sammenføying er nok, og når det ikke er det
I dette eksemplet tegner vi en arabisk hilsen ("السلام عليكم", Fred være med deg). Vi bygger inn fonten, lar motoren håndtere bidireksjonal (bidi) rekkefølge og kursiv sammenkobling, og sender den til siden
uses
hppdf, System.SysUtils, Vcl.Graphics;
var
Pdf: THotPDF;
ArabicStr: string;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'ComplexText_Output.pdf';
Pdf.BeginDoc;
// 1. Definer strengen. Legg merke til at i minnet/kode
// er dette lagret i logisk rekkefølge, ikke den visuelle rekkefølgen.
ArabicStr := 'السلام عليكم';
// 2. Vi MÅ bruke en font som støtter arabiske glyffer,
// og vi MÅ bygge den inn (embedded). PDF-viseren kan ikke
// bytte fonter midtveis (fallback) på en trygg måte for posisjonerte glyffer.
// Sett 'True' for 'Embed'-parameteren i AddFont eller AutoEmbed.
Pdf.CurrentPage.SetFont('Arial', [], 24);
// 3. For latinsk/standard venstre-til-høyre gjør en grunnleggende TextOut jobben.
Pdf.CurrentPage.TextOut(100, 700, 0, 'Standard English TextOut');
// 4. For komplekse skript bruker vi API-et for DrawComplexText / uniscribe-drevet utdata.
// Noen revisjoner av HotPDF ruter TextOut() automatisk til Uniscribe for
// hebraiske/arabiske Unicode-blokker hvis en bryter er satt; se etter
// egenskapen AutoShape eller TextOutComplex. Dette eksemplet
// representerer hensikten med å tegne formet RTL-tekst
// Anta at komponenten har et DrawRTLText- eller Uniscribe-kall
Pdf.CurrentPage.DrawComplexText(100, 600, 0, ArabicStr, [htRTL]);
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
(Merk: Sjekk din spesifikke versjon av HotPDF for den nøyaktige metodesignaturen for Uniscribe-utdata, som kanskje er TextOutRTL, DrawComplexText eller et ekstra parameter til TextOut.)
Dekning på tvers av skriftsystemer
Arabisk og hebraisk trenger høyre-til-venstre-behandling, mens thai og devanagari også kan kreve plassering av merker og ligaturer. Test derfor hvert skriftsystem med den faktiske fonten og fontens glyfdekning, ikke bare med en streng som ser riktig ut i et Windows-kontroll
Glyfdekningen avgjøres før formingen starter
Forming kan ordne rekkefølge og posisjon, men kan ikke lage glyfer som fonten mangler. Velg og bygg inn en font som dekker tegnene, og kontroller at PDF-leseren får de samme glyfene som formingsmotoren valgte
Leserekkefølgen tilhører dokumentet, ikke glyfene
RTL er sjelden rent RTL. En kvittering trykt for Midtøsten har arabisk tekst for varenavnet, etterfulgt av en europeisk tallverdi for prisen, og kanskje en engelsk merkevare. Denne blandingen av venstre-til-høyre og høyre-til-venstre i samme streng kalles "bidireksjonal" tekst, eller bidi. Unicode-algoritmen håndterer dette ved å bryte strengen opp i "løp" (runs) av ensartet retning og ordne dem for visning
Hvis du prøver å håndtere RTL ved å skrive en enkel funksjon for å snu en string i Delphi, vil koden din feile i det øyeblikket den treffer bidi. Tallet "150" i en reversert arabisk streng blir "051". Avsnitt blir blandet opp og uleselige. Du må stole på den formende rørledningen for å bryte bidi-løpene riktig og oversette dem til PDF. Du må bare sørge for én ting: når du justerer eller bygger avgrensningsbokser for tekst, måles posisjonen til bidi-tekst typisk fra den høyre justeringsmarginen for det avsnittet i stedet for fra venstre. Hvis koden din forventer at X er venstre kant av arabisk utdata, vil teksten ofte flyte mot venstre ut av den tiltenkte boksen
Verifisere formet utdata
Når en bruker rapporterer at Thai-vokalene deres svever bort fra konsonantene, eller det arabiske ser ut som frakoblede bokstaver, følg denne veien tilbake for å fikse utdataene:
- Bruker du et rent tekstkall (pure text call)? Erstatt de eldre
TextOut-bruksområdene med de formingsklare motpartene for den regionens utdata - Er fonten innebygd? En formet glyff-indeks betyr ingenting hvis seeren bruker en erstatningsfont som kartlegger den indeksen til noe annet. Fonten må bygges inn
- Har fonten dekning?
ArialogTahomastøtter de fleste;Courier Newgjør det kanskje ikke i eldre OS-versjoner. Feilsøk med en systemfont du stoler på (Tahoma) før du feilsøker med en tilpasset font bedriften leverte - Gjetter du forskyvninger? Ikke forsøk å manuelt posisjonere bidi- eller arabiske bokstaver med
GetCharWidth, ligaturer vil slå den gjetningen ut av balanse. Stol på komponentens ord-innpaknings (word-wrap) og formingsmotor (shaping engine) for å produsere linjen
PDF har ikke et dynamisk formingsmaskineri, den ber bare om å få beskjed om hva den skal vise. Ved å bruke HotPDF og utnytte Delphis integrasjon med Windows' formingsmotor, kan du levere pålitelige internasjonale dokumenter uten å måtte skrive reglene for ligaturer i applikasjonen din