Zet een Japanse roman op de pagina en het eerste dat opvalt is dat de tekst de kolom afloopt, niet de regel, en dat de kolommen van de rechterrand van het vel naar links vorderen. Een lezer die ermee is opgegroeid vindt horizontale tekst ietwat klinisch. Het technische probleem is dat PDF, net als vrijwel elk digitaal tekstsysteem, is gebouwd rond een horizontale basislijn die van links naar rechts groeit, en een inhoudsstream heeft geen begrip van "schrijf deze alinea omlaag in plaats van opzij." Dus wanneer een Delphi-toepassing een certificaat, een gedicht, bewegwijzering of een traditioneel juridisch document voor een Taiwanese, Japanse of Koreaanse lezer moet produceren, moet de opmaak met de hand worden samengesteld: één teken onder het volgende, één kolom links van de laatste.
HotPDF biedt u een schakelaar die de boekhouding per teken voor u bijhoudt. Het lettertype dat u instelt draagt een IsVertical-vlag, en zodra die aan staat, stapelt één TextOut-aanroep een hele tekenreeks in een verticale kolom in plaats van deze langs een basislijn te laten lopen. De kolomplaatsing, de volgorde van rechts naar links en één stilzwijgend belangrijke glyphvervanging zijn waar de rest van deze pagina doorheen werkt.

De schakelaar bevindt zich in SetFont
Verticale opmaak is geen eigenschap van de pagina of het document. Het is een eigenschap van het lettertype waarmee u tekent, en u schakelt het in met het vijfde argument van SetFont:
// SetFont(FontName, FontStyle, Size, FontCharset, IsVertical)
// The 5th argument flips the current font into vertical mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, False); // horizontal
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 12, DEFAULT_CHARSET, True); // vertical
Omdat de vlag aan het lettertype zit, wisselt u eenvoudig tussen horizontaal en verticaal schrijven door SetFont opnieuw aan te roepen met een ander laatste argument. Een pagina kan een horizontale koptekst bovenaan en verticale tekst eronder hebben, en HotPDF houdt de twee modi apart per lettertype-object in plaats van per pagina. Dat is wat gemengde opmaak mogelijk maakt zonder enige speciale modusafhandeling van uw kant: elke TextOut na een verticale SetFont stapelt, elke TextOut na een horizontale loopt langs de basislijn, en de laatste SetFont wint.
Het vierde argument is de Windows-tekenset, dezelfde als een horizontale aanroep neemt. Het doorgeven van DEFAULT_CHARSET laat het systeem glyphs per tekenreeks omzetten, wat hier van belang is omdat een verticaal document vaak schriften mengt. Al het andere over het lettertype is nog steeds van toepassing: het moet op de bouwmachine geïnstalleerd zijn, en u wilt bijna altijd FontEmbedding := True zodat het bestand dezelfde CJK-glyphs weergeeft op een lezer die nooit Arial Unicode MS heeft gehad.
Eén TextOut-aanroep is één kolom
Met een verticaal lettertype actief verspreidt een TextOut-aanroep zijn tekenreeks niet meer zijdelings vanaf het gegeven punt. Het plaatst het eerste teken bovenaan en loopt de rest recht omlaag, waarbij het per glyph de regelhoogte van het lettertype vooruitgaat. De X die u meegeeft bepaalt de kolom; de Y die u meegeeft bepaalt waar de bovenkant van de kolom begint. Om een echte passage op te maken, geeft u dus één TextOut per kolom en stapt u X naar links tussen aanroepen, omdat CJK-kolommen van rechts naar links worden gelezen.
var
Pdf: THotPDF;
const
ColTop = 760; // y of the first glyph in every column (points)
ColGap = 28; // horizontal distance between columns
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'VerticalText.pdf';
Pdf.FontEmbedding := True; // embed the CJK face for portable rendering
Pdf.BeginDoc;
Pdf.CurrentPage.Size := psA4;
// A horizontal heading first, in the ordinary writing mode.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 16, DEFAULT_CHARSET, False);
Pdf.CurrentPage.TextOut(60, 800, 0, 'Tang poem, vertical layout');
// Switch the font into vertical mode; every TextOut below now stacks.
Pdf.CurrentPage.SetFont('Arial Unicode MS', [], 18, DEFAULT_CHARSET, True);
// Columns advance right to left, so X decreases with each call.
Pdf.CurrentPage.TextOut(520, ColTop, 0, '床前明月光');
Pdf.CurrentPage.TextOut(520 - ColGap, ColTop, 0, '疑是地上霜');
Pdf.CurrentPage.TextOut(520 - ColGap * 2, ColTop, 0, '舉頭望明月');
Pdf.CurrentPage.TextOut(520 - ColGap * 3, ColTop, 0, '低頭思故鄉');
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Het gedicht leest zoals het hoort: de meest rechtse kolom eerst, van boven naar beneden, dan springt het oog naar links naar de volgende kolom. Niets in de tekenreeks zelf codeert die volgorde. U codeert die in de X-coördinaten door ze aanroep voor aanroep te verlagen. Keer de richting om en het vers komt omgekeerd uit, wat de meest voorkomende fout is bij het overzetten van een horizontale opmaak naar verticaal.
Coördinaten: omlaag over de pagina, van rechts naar links
Twee assen zijn in het spel en ze trekken in tegengestelde richtingen, dus het is de moeite waard precies te zijn. HotPDF meet vanuit de linkeronderhoek van de pagina, met Y dat omhoog toeneemt, in punten. Een verticale kolom begint dus bij een hoge Y (nabij de bovenkant van het vel) en de tekens dalen vandaar af terwijl HotPDF een regelhoogte aftrekt voor elk teken. U stelt die beginwaarde Y eenmalig per kolom in en de component verwerkt de afdaling.
De horizontale as is degene die u handmatig aanstuurt. Elke kolom staat bij zijn eigen X, en opeenvolgende kolommen stappen naar kleinere X-waarden omdat de leesrichting van rechts naar links is. Een verstandig ritme is om de X van de meest rechtse kolom te kiezen en voor elke volgende aanroep een vaste kolomafstand af te trekken, zoals het voorbeeld doet met ColGap. De afstand is aan u; te dicht en aangrenzende kolommen raken elkaar, te ruim en het blok ziet er ijl uit. Voor tekst van 12 tot 18 punten leest een afstand iets groter dan de lettergrootte comfortabel.
Glyphs die van vorm moeten veranderen
Een paar tekens zijn niet simpelweg geroteerde kopieën van hun horizontale tegenhanger; ze moeten worden vervangen wanneer de tekst verticaal wordt. De teken die HotPDF voor u afhandelt is het Japanse verlengde klankteken ー (U+30FC), de lange klinkerstreep die voorkomt in katakanawoorden zoals コーヒー. Horizontaal getekend is het een korte streep op de basislijn. Als u dat glyph in een kolom zou stapelen, zou het plat over de kolom liggen, wat fout is: in verticaal Japans wordt het teken een verticale streep die de twee tekens verbindt waartussen het staat. HotPDF detecteert U+30FC in het verticale pad en geeft het weer als een verticale balk (U+007C), zodat het lange-klinkteken de juiste richting wijst zonder enig werk van uw kant.
Die ene vervanging dekt het geval dat de meeste naïeve implementaties breekt, maar het is de moeite waard te weten waar het algemene probleem dieper gaat. Volledige verticale typografie roteert ook Latijnse letters en westerse leestekens negentig graden, verschuift kleine kana en herpositioneert haakjes en komma's naar hun verticale vormen, en een volledige implementatie daarvan zit in de OpenType-verticale kenmerken van een lettertype in plaats van in vaste regels. HotPDF kan die kenmerken aanspreken wanneer het lettertype ze bevat: verticale alternatieven (de GSUB-kenmerken vert en vrt2) en verticale kerning (vkrn en vpal GPOS-lookups) zijn opt-in en worden alleen toegepast langs het verticale pad wanneer het actieve lettertype ze daadwerkelijk definieert. Voor gemengde CJK-tekst in een breed dekkend lettertype zoals Arial Unicode MS zijn de ingebouwde U+30FC-afhandeling plus een gelijke regelafstandstap voldoende voor correcte, leesbare kolommen; de OpenType-kenmerken zijn belangrijk wanneer u overstapt op een lettertype dat is ontworpen voor fijne verticale opmaak en de native kanapositionering en tussentekenstijl ervan wenst.
Schriften en oriëntaties mengen op één pagina
Echte documenten zijn zelden puur. Een verticale Japanse pagina kan een horizontaal Engels bijschrift dragen, een paginanummer onderaan of een blok Koreaans dat verticaal naast het Japans staat. Omdat de verticale vlag een schakelaar op letterty-niveau is, componeert u deze door SetFont-aanroepen af te wisselen in plaats van een paginabrede toestand te beheren. Stel een horizontaal lettertype in, schrijf de koptekst en het folionummer, stel een verticaal lettertype in, leg de kolommen neer, stel opnieuw een horizontaal lettertype in voor een voettekst. Elke regio pakt de modus van de meest recente SetFont op, zodat de enige vereiste discipline is het aanroepen ervan wanneer u van richting verandert.
Eén detail om voor te plannen wanneer schriften worden gemengd: Chinese, Japanse en Koreaanse ideogrammen zijn bijna vierkant en stapelen op een gelijke stap, maar Latijnse tekstreeksen die zijn ingebed in een verticale kolom hebben die uniforme vooruitgang niet. Als u een paar Latijnse woorden nodig heeft in anderszins verticale tekst, beslis dan bewust of ze geroteerd moeten worden om de kolom af te lopen of rechtop als een korte horizontale inset moeten staan, en positioneer dat fragment met zijn eigen TextOut in plaats van het te laten rijden op de verticale stap bedoeld voor ideogrammen. Het behandelen van de gemengde reeks als een eigen plaatsingsprobleem houdt het kolomritme intact.
Van voorbeeld naar productie
De onderdelen zijn klein en componeren voorspelbaar. Schakel de verticale vlag in via SetFont, geef één TextOut per kolom vanuit een vaste bovenste Y en verlaag X per aanroep zodat de kolommen van rechts naar links worden gelezen. Sla het lettertype in zodat de CJK-glyphs de reis naar de machine van een lezer overleven, en laat de component het U+30FC lange-klinkteken en, waar het lettertype ze ondersteunt, de OpenType-verticale kenmerken afhandelen. Vanaf daar is het productierijp maken van de opmaak grotendeels rekenkunde: kolom-X-posities afleiden uit een gemeten blokbreedte, lange passages opdelen in kolommen die in de paginahoogte passen en ruimte reserveren voor horizontale kopteksten en folionummers.
Voor het bredere tekst- en lettertype-oppervlak waarop dit voortbouwt, inclusief de horizontale TextOut-conventies en Unicode-lettertype-registratie, zie het meertalige Hello World-voorbeeld en het TextOut-voorbeeld. De SetFont-verticale schakelaar en de hier getoonde TextOut-aanroepen maken deel uit van de HotPDF Component voor Delphi en C++Builder.