Posez 「コード」 le long d'une page en le dessinant caractère par caractère, chaque appel un em plus bas que le précédent, et trois des cinq glyphes sortent faux. Les deux crochets d'angle occupent la colonne comme ils occupent une ligne horizontale, ouvrant sur le côté, et la marque de voyelle longue ー est un tiret plat qui coupe la colonne là où un lecteur japonais attend un petit trait vertical. Seuls コ et ド, les deux katakana ordinaires, ont l'air qu'un typographe leur donnerait
Pivoter toute la ligne de quatre-vingt-dix degrés répare plus ou moins par accident les crochets et la marque de voyelle longue, et casse tout le reste : chaque kanji et chaque kana se couche maintenant sur le flanc. L'écriture verticale fait trois choses à la fois. Les caractères restent droits, l'avancement descend la page au lieu de la traverser, et une poignée de caractères passent à des dessins différents. Bien faire les trois exige une police qui porte des formes verticales et des métriques verticales, et une police PDF configurée pour les utiliser
Activer l'écriture verticale dans PDF Library for Delphi
PDF Library for Delphi traite l'écriture verticale comme un mode de dessin. SetVerticalWritingMode(1) l'active, chaque appel DrawText ensuite descend la page depuis le point que vous lui donnez, et SetVerticalWritingMode(0) ramène le texte horizontal. Le poseur renvoie le mode en vigueur avant l'appel et GetVerticalWritingMode lit celui en cours, donc une routine d'appui peut basculer le mode et remettre plus tard exactement ce qu'elle a trouvé
Les deux coordonnées signifient quelque chose de légèrement différent du texte horizontal. La valeur x nomme la ligne médiane de la colonne : chaque glyphe se suspend avec son milieu horizontal sur cette ligne, si bien qu'une ponctuation étroite et un kanji pleine largeur restent alignés sur le même axe. La valeur y est le haut de la première cellule de caractère, et la colonne pousse vers le bas à partir de là. Avec SetOrigin(1), qui met y = 0 au bord supérieur de la page, le calcul se lit comme vous disposeriez la page sur papier
var
Lib: TPDFlib;
H: Double;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.AddTrueTypeFont('MS Mincho', 1); // 1 = incorporer la police
Lib.SetTextSize(12);
Lib.SetVerticalWritingMode(1); // le DrawText ordinaire descend maintenant
H := Lib.GetVerticalTextHeight('MS Mincho', 12, '第三章 保守点検');
Lib.DrawText(480, 72, '第三章 保守点検'); // la colonne démarre à y = 72
Lib.SetVerticalWritingMode(0); // retour à l'horizontal
// Origin 1 met y = 0 en haut, donc 72 + H est le pied de la colonne ;
// la légende horizontale se place une ligne en dessous
Lib.DrawText(456, 72 + H + 18, 'Chapter 3');
Lib.SaveToFile('manual-ja.pdf');
finally
Lib.Free;
end;
end;
GetVerticalTextHeight prend le nom de la police, la taille et le texte, et renvoie la longueur de la colonne en points. Dans l'exemple, 72 + H est le pied de la colonne et la légende anglaise va 18 points plus bas, démarrant 24 points à gauche de la ligne médiane de la colonne pour que la courte ligne latine se place à peu près sous la colonne. La fonction renvoie 0 quand elle ne peut pas ouvrir une police sous ce nom, et une mise en page bâtie sur une hauteur nulle met la légende sur la colonne, donc testez-le avant d'utiliser la valeur
Pourquoi les crochets se couchent sur le flanc dans une colonne verticale ?
Parce que la police détient deux dessins de chaque caractère de ce genre et que le horizontal est le défaut. Les polices OpenType listent les alternatives dans une fonctionnalité GSUB nommée vert, ou vrt2 dans les polices qui livrent des glyphes déjà pivotés pour la composition verticale. La mise en forme d'une ligne de texte renvoie les glyphes horizontaux, et quelque chose doit appliquer la fonctionnalité verticale ensuite, un glyphe pour un glyphe. Crochets d'angle, parenthèses et marque de voyelle longue tournent pour courir le long de la colonne ; les petits kana et la ponctuation comme 、 et 。 se déplacent vers un autre coin de leur carré
PDF Library for Delphi lit cette fonctionnalité dans la police avec laquelle il dessine et échange chaque glyphe contre la forme verticale que la police nomme. Quand une police porte les deux fonctionnalités, vrt2 l'emporte et vert est ignorée. La spécification veut que vrt2 remplace vert, et lire les deux peut donner à un caractère deux glyphes verticaux différents selon la règle qui répond d'abord. Une police qui n'a ni l'un ni l'autre garde ses glyphes ordinaires. Nous préférons cette issue à une table de substitution intégrée : une table devinée tombe juste sur les caractères courants et écrase en silence les polices dont les concepteurs ont traité un caractère autrement
Videz les tables GSUB des copies livrées avec Windows et les comptages sont très éloignés : la fonctionnalité verticale de MS Gothic mappe 979 glyphes, Yu Gothic 2 491, SimSun 72, et Arial aucun du tout (les chiffres exacts bougent avec les versions de polices). Une police latine qui contient par hasard quelques kana dessinera une colonne droite avec chaque crochet et chaque marque de voyelle longue sous sa forme horizontale, car rien dans la police ne se substitue
La substitution change aussi la mesure. Une forme verticale peut avoir sa propre avance, différente du glyphe horizontal qu'elle remplace, donc GetVerticalTextHeight applique la même substitution avant de cumuler les avances. Mesurez les formes horizontales et dessinez les verticales, et la colonne dépasse la boîte que vous lui aviez réservée de quelques points par crochet
Rien de tout cela ne touche le texte lui-même. Copiez la colonne depuis un lecteur et vous récupérez 「コード」, parce que chaque glyphe vertical correspond au caractère que vous avez passé. La recherche et l'extraction de texte voient votre chaîne source, jamais les formes de présentation pivotées
Comment les métriques verticales aboutissent dans le PDF
Chaque caractère d'une suite verticale avance de la distance que les métriques verticales propres de la police lui donnent. Ouvrez la sortie dans un inspecteur PDF et vous y trouverez une police Type0 à encodage Identity-V dont la CIDFont porte une entrée W2 pour chaque glyphe utilisé : l'avance verticale de la table vmtx de la police, la moitié de la largeur du glyphe comme décalage vers la ligne médiane de la colonne, et l'origine verticale. ISO 32000-1 §9.7.4.3 définit ces trois nombres. Pour une police sans métriques verticales, pas de tableau W2, et le défaut DW2 fait avancer chaque caractère d'un em exactement
L'origine verticale est là où les polices tierces se contredisent. La table vhea a des champs ascendante et descendante qui paraissent la source évidente, mais la convention de signe de la descendante n'est pas partagée entre polices. Lisez le champ des copies Windows avec n'importe quel visualiseur de tables de polices et il sort +140 dans MS Gothic et +120 dans Yu Gothic, contre −144 dans SimSun et −500 dans MingLiU, et les valeurs peuvent changer avec les versions de polices. Toute position dérivée de ce champ dérive d'un montant différent pour chaque police. PDF Library for Delphi prend l'origine depuis l'ascendante verticale, que les polices CJK citées rapportent de manière cohérente, et retombe sur 880 unités (le défaut que la spécification PDF elle-même donne à DW2) quand une police ne rapporte rien de plausible
Positionner les glyphes verticaux à la main a son propre piège. Le texte horizontal fixe souvent l'espacement avec des nombres dans un tableau TJ. Sous un mode d'écriture verticale, ISO 32000-1 §9.4.4 applique ces nombres le long de la colonne, donc une correction calculée pour un espacement horizontal pousse chaque caractère plus bas sur la page. Voilà pourquoi une suite verticale dans le flux de contenu est une simple chaîne de codes de glyphes sans aucun ajustement, et tout l'espace vient de W2
Quand vous contrôlez la sortie, regardez l'encre plutôt que les dictionnaires. Trouver /Identity-V dans la police prouve que l'encodage a été déclaré ; cela ne dit rien sur le sens dans lequel le texte court réellement. Rendre la page et mesurer la boîte englobante des pixels dessinés, si : une suite de sept caractères devrait sortir à environ un caractère de large et sept caractères de haut
Une suite verticale sur une page horizontale
DrawVerticalText dessine une seule suite verticalement et laisse le mode d'écriture tranquille. Il prend la position, le nom de police, la taille et le texte, donc la sélection de police courante reste intacte aussi. Étiquettes de dos de livre, cachets, une seule colonne de noms à côté d'un tableau : ce sont les exceptions verticales à l'intérieur d'un document horizontal, et basculer un mode global autour de chacune est plus d'état que le travail n'en mérite
// Une suite verticale dans une page par ailleurs horizontale
if Lib.DrawVerticalText(520, 96, 'MS Mincho', 14, '保守点検記録') = 0 then
begin
// La police n'a pas pu s'ouvrir ou n'a pas pu composer ce texte.
// LogLayoutProblem est votre propre routine, hors bibliothèque
LogLayoutProblem('vertical label on page ' + IntToStr(Lib.SelectedPage));
end;
// Le texte horizontal autour n'est pas affecté
Lib.DrawText(72, 96, 'Maintenance inspection record');
Une page qui mélange les deux sens porte la police deux fois dans ses ressources, une fois en encodage horizontal et une fois en Identity-V, construites depuis le même programme de police. Chaque sens garde ses métriques, donc une page de livre japonais avec corps vertical et titres courants horizontaux, ou un certificat chinois avec un titre vertical au-dessus de lignes de détail horizontales, sort avec les deux sens correctement espacés
La valeur de retour est la raison pour laquelle nous atteignons DrawVerticalText même dans des documents majoritairement verticaux. En dessin par mode, une suite qui ne peut pas être composée verticalement est dessinée de la manière horizontale ordinaire au lieu d'être perdue, et DrawText signale le succès dans les deux cas. Pour le corps de texte, c'est le meilleur défaut, car une ligne horizontale égarée saute aux yeux à l'épreuve et un paragraphe manquant non. Pour une étiquette dont le sens est tout l'enjeu, utilisez DrawVerticalText et traitez un 0 comme un échec de mise en page
Disposer les colonnes de droite à gauche
L'ordre des colonnes vous appartient. Le texte vertical japonais et chinois traditionnel se lit colonne par colonne de droite à gauche, donc une page démarre à sa marge droite et chaque nouvelle colonne se place à gauche de la précédente. Aucun réglage de mode d'écriture ne peut le déduire du texte, et il en va de même pour l'ordre des pages dans un livre relié à droite et pour la place des furigana, notes de bas de page et légendes
La routine ci-dessous découpe une chaîne en colonnes qui tiennent dans une hauteur fixe, en mesurant avec GetVerticalTextHeight au fil de l'eau et en se déplaçant vers la gauche d'un em et demi par colonne :
procedure DrawColumns(Lib: TPDFlib; const Face: WideString; Size: Double;
const Text: WideString; Right, Top, BoxH: Double);
var
Col, Trial: WideString;
I: Integer;
X: Double;
begin
// Garde-fou suggéré, pas un contrôle de la bibliothèque : une hauteur nulle signifie
// que la police n'a pas pu s'ouvrir, et la boucle plus bas ne casserait jamais de colonne
if Lib.GetVerticalTextHeight(Face, Size, Text) <= 0 then
Exit;
X := Right; // première colonne à la marge droite
Col := '';
for I := 1 to Length(Text) do // suppose aucune paire de substitution
begin
Trial := Col + Text[I];
if (Col <> '') and (Lib.GetVerticalTextHeight(Face, Size, Trial) > BoxH) then
begin
Lib.DrawVerticalText(X, Top, Face, Size, Col);
X := X - Size * 1.5; // colonne suivante à gauche
Col := Text[I];
end
else
Col := Trial;
end;
if Col <> '' then
Lib.DrawVerticalText(X, Top, Face, Size, Col);
end;
Remesurer la chaîne d'essai à chaque caractère est plus lent que sommer les avances, mais cela mesure exactement ce qui sera dessiné, substitutions comprises. Ce que la boucle ne fait pas, ce sont les règles kinsoku. Un crochet fermant ou 。 en haut de colonne, ou un crochet ouvrant échoué au pied d'une colonne, est une erreur de composition pour un lecteur japonais, et le réparer signifie tirer ou pousser un caractère à travers la coupure avant de dessiner. Les paires de substitution exigent le même soin : indexer Text[I] coupe en deux un caractère hors du plan multilingue de base, donc avancez par point de code si votre texte peut en contenir
Pour les documents assemblés depuis des données, la visite guidée de la recherche de texte et l'énumération d'éléments de page montre comment relire ce qui a atterri sur chaque page, ce qui est un moyen rapide de confirmer que chaque colonne porte les caractères prévus
Quelle police pour un document vertical ?
Une police CJK avec ses propres métriques verticales et une fonctionnalité vert ou vrt2. Sans elles, vous obtenez des caractères droits avançant d'un em à la fois et aucun changement de forme. Quand un texte vertical semble subtilement faux, examinez la police avant d'examiner le code. Un visualiseur de tables qui liste les fonctionnalités GSUB d'une police et ses tables vhea et vmtx vous dira en une minute si la police peut faire le travail
DrawVerticalText et GetVerticalTextHeight ouvrent une police installée par son nom via Windows. Dans les builds Lazarus pour d'autres plateformes, l'écriture verticale passe par SetVerticalWritingMode et DrawText, qui travaillent depuis le programme de la police que vous avez chargée et sélectionnée, donc les mêmes formes et métriques verticales s'appliquent tant que cette police est la police CJK prévue
L'incorporation suit les règles habituelles et les coûts habituels. Une police CJK complète court sur plusieurs mégaoctets, donc le sous-ensemblage est le défaut raisonnable pour tout document qui quitte votre machine. Les notes sur l'optimisation de la taille de fichier PDF et le sous-ensemblage de polices couvrent ce qu'attendre, et la visite guidée de l'incorporation de polices manquantes dans un PDF existant couvre le cas de réparation où un document vertical arrive sans ses polices
L'écriture CJK verticale occupe la même API de dessin que le reste des fonctions de texte de PDF Library for Delphi, une bibliothèque PDF Pascal native pour Delphi, C++Builder et Lazarus. La page produit de PDF Library for Delphi liste l'ensemble des fonctionnalités de polices et de texte à côté