Teknisk artikel

Vertikal japansk og kinesisk tekst i PDF med Delphi

PDFlibPas tegner japansk og kinesisk tekst nedad på siden. SetVerticalWritingMode slår vertikal skrivning til, almindelige DrawText-kald løber derefter nedad, og GetVerticalWritingMode rapporterer den nuværende tilstand. Før dette eksisterede, betød vertikal tekst at placere hvert tegn manuelt og håbe, at afstanden så rigtig ud

Vertikal skrivning er ikke horisontal tekst roteret halvfems grader. Tegnene forbliver oprette, advance-løbet løber ned i stedet for på tværs, og en række tegn ændrer form helt — hvilket er den del, der adskiller et dokument, der læser naturligt, fra et, som en japansk læser straks genkender som maskinfabrikeret

Hvad ændrer sig inde i PDF'en?

Tekst tegnet på denne måde går gennem en Type0-skrifttype i vertikal skrivetilstand, der bærer skrifttypens egne vertikale metrik. Det betyder noget i to retninger. En læser advance-r hvert tegn med den afstand, dens designer havde til hensigt, frem for med et ensartet skridt, så kolonnen har det rytme, skrifttypen blev tegnet til. Og at kopiere teksten ud returnerer de oprindelige tegn, fordi den vertikale kørsel stadig er ægte tekst med en korrekt mapping frem for en sekvens af positionerede glyffer

En skrifttype, der ikke bærer sine egne vertikale metrik, advance-r et em pr. tegn, hvilket er, hvad en læser ville gøre med standarden. Den fallback er værd at kende, fordi det er den forskel, du vil se, når et dokument renderer korrekt med en rigtig CJK-skrifttype og ser mekanisk afstand med en latinsk skrifttype, der tilfældigvis indeholder lidt kana

var
  Lib: TPDFlib;
  H: Double;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.AddTrueTypeFont('MS Mincho', 1);      // 1 = embed the face
    Lib.SetTextSize(12);
    Lib.SetVerticalWritingMode(1);            // ordinary DrawText now runs down
    H := Lib.GetVerticalTextHeight('MS Mincho', 12, '第三章 保守点検');
    Lib.DrawText(480, 72, '第三章 保守点検');
    Lib.SetVerticalWritingMode(0);            // back to horizontal
    Lib.DrawText(72, 72 + H, 'Chapter 3');
    Lib.SaveToFile('manual-ja.pdf');
  finally
    Lib.Free;
  end;
end;

Hvorfor ser parenteser forkerte ud i vertikal tekst?

For en parentes har to former, og kun én af dem hører hjemme i en kolonne. Parenteser, det lange vokaltegn og de små kana tegnes anderledes, når tekst løber ned ad siden — en indrammende parentes roterer for at sidde langs kolonnen frem for at ligge på tværs af den, og det lange vokaltegn bliver til et vertikalt stregetegn. Tegn de horisontale former i en vertikal kolonne, og hvert eneste af dem ligger på siden

PDFlibPas tager formerne fra skrifttypens egen vertikale feature, så hver skrifttype leverer, hvad dens designer tegnede, frem for en substitution gættet ud fra tegnet. Den distinktion betyder noget for korrekthed: et gættet substitutionstabeller er rigtigt for de almindelige tilfælde og forkert for de skrifttyper, der behandler et tegn anderledes, og en skrifttype, der ikke navngiver nogen vertikale former, tegnes præcis som før, frem for at blive presset gennem en tabel, den aldrig bad om

GetVerticalTextHeight måler de former, der faktisk vil blive tegnet, så en kolonne, hvis tegn ændrer form, stadig måles korrekt. At måle de horisontale former og tegne de vertikale er den klassiske kilde til kolonner, der overskrider deres boks med et par tegn

At tegne én kørsel uden at ændre tilstanden

DrawVerticalText tegner en enkelt kørsel vertikalt, tager positionen, skrifttypenavnet, størrelsen og teksten, og lader skrivetilstanden uændret. Brug den til den vertikale undtagelse inden i et horisontalt dokument — et rygmærke, et stempel, en enkelt kolonne med navne — hvor at slå en global tilstand til og fra omkring hvert kald er mere tilstand, end opgaven fortjener

De horisontale og vertikale former af én skrifttype holdes adskilt internt, så en side kan bære begge uden, at nogen forstyrrer den anden. Det er det, der gør en blandet side praktisk: en japansk bogside med vertikal brødtekst og horisontale løbende sidehoveder, eller et kinesisk certifikat med en vertikal titel over horisontale detaljelinger

// One vertical run inside an otherwise horizontal page
Lib.DrawVerticalText(520, 96, 'MS Mincho', 14, '保守点検記録');
// The horizontal text around it is unaffected
Lib.DrawText(72, 96, 'Maintenance inspection record');

At få skrifttypen rigtig før alt andet

Vertikal skrivning afhænger helt af skrifttypen. En CJK-skrifttype med korrekte vertikale metrik og en vertikal feature producerer korrekt output uden videre arbejde; en skrifttype uden dem producerer oprette tegn, der advance-r et em ad gangen, og slet ingen formændringer. Hvis vertikal tekst ser subtilt forkert ud, så undersøg skrifttypen, før du undersøger koden

Indlejring følger de sædvanlige regler og de sædvanlige omkostninger. En fuld CJK-skrifttype er stor, så subsetting er ikke valgfrit for dokumenter, der skal nogensinde steder — noterne om PDF-filstørrelse-optimering og subsetting af skrifttyper dækker, hvad man kan forvente, og gennemgangen af indlejring af manglende skrifttyper i en eksisterende PDF dækker reparationstilfældet, hvor et vertikalt dokument ankommer uden sine skrifttyper

Hvor vertikal tekst stadig kræver en layout-beslutning af dig

Kolonne-rækkefølge. Japansk vertikal tekst løber højre mod venstre pr. kolonne, så en tocietet side starter ved højre kant, og ingen skrivetilstand kan udlede det fra teksten. Det samme gælder siderrækkefølge i et dokument, der læser højre mod venjur som helhed, og hvor furigana, fodnoter og figur-tekst plaatseres

Hvad biblioteket garanterer er, at hver kørsel sættes korrekt: korrekte former, korrekte advance, udtrækkbar tekst. Hvor kørslerne placeres på siden er et layout-problem, og for dokumenter samlet fra data er gennemgangen af tekst-søgning og opstilling af side-elementer nyttig til bagefter at verificere, at det, der landede på siden, var det, du havde til hensigt

PDFlibPas er et Pascal-baseret PDF-bibliotek til Delphi, C++Builder og Lazarus, og vertikal CJK-skrivning er del af tegne-API'en frem for et add-on — se PDFlibPas-produktsiden for listen over tekst- og skrifttype-funktioner