Artykuł techniczny

Pionowy tekst japoński i chiński w PDF z Delphi

PDF Library for Delphi rysuje tekst japoński i chiński w dół strony. SetVerticalWritingMode włącza pisanie pionowe, zwykłe wywołania DrawText biegną wtedy w dół, a GetVerticalWritingMode raportuje bieżący stan. Zanim to istniało, ustawienie tekstu pionowo oznaczało ręczne pozycjonowanie każdego znaku i nadzieję, że odstępy wyglądają dobrze

Pisanie pionowe to nie jest poziomy tekst obrócony o dziewięćdziesiąt stopni. Znaki pozostają prosto, posuw przebiega w dół zamiast w poprzek, a część znaków zmienia kształt całkowicie — to jest ta część, która odróżnia dokument czytający się naturalnie od takiego, który japoński czytelnik od razu rozpoznaje jako wykonany maszynowo

Diagram PDF Library for Delphi porównujący obrócony poziomy wiersz tekstu z prawdziwym pionowym trybem pisania, gdzie glify pozostają proste, a postęp biegnie w dół strony
Pismo pionowe ustawia znaki prosto z pionowymi metrykami danego kroju zamiast obracać poziomy wiersz, a skopiowana kolumna czyta się z powrotem znak w znak

Co zmienia się wewnątrz PDF

Tekst rysowany w ten sposób przechodzi przez czcionkę Type0 w trybie pisania pionowego niosącą własne pionowe metryki króju. To ma znaczenie w dwóch kierunkach. Czytnik posuwa każdy znak o odległość przewidzianą przez projektanta zamiast o jednorodny krok, więc kolumna ma rytm, dla którego krój był rysowany. A skopiowanie tekstu zwraca oryginalne znaki, ponieważ pionowy przebieg to wciąż prawdziwy tekst z właściwym mapowaniem, a nie sekwencja pozycjonowanych glifów

Krój, który nie niesie własnych metryk pionowych, posuwa się o jeden em na znak, co zrobiłby czytnik z wartością domyślną. Ta rezerwa warto ją znać, bo to różnica, którą zobaczysz, gdy dokument renderuje się poprawnie z właściwym krójem CJK, a wygląda na rozstawiony maszynowo przy kroju łacińskim, który akurat zawiera trochę kana

var
  Lib: TPDFlib;
  H: Double;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.AddTrueTypeFont('MS Mincho', 1);      // 1 = osadź krój
    Lib.SetTextSize(12);
    Lib.SetVerticalWritingMode(1);            // zwykłe DrawText teraz biegnie w dół
    H := Lib.GetVerticalTextHeight('MS Mincho', 12, '第三章 保守点検');
    Lib.DrawText(480, 72, '第三章 保守点検');
    Lib.SetVerticalWritingMode(0);            // powrót do poziomego
    Lib.DrawText(72, 72 + H, 'Chapter 3');
    Lib.SaveToFile('manual-ja.pdf');
  finally
    Lib.Free;
  end;
end;

Dlaczego nawiasy wyglądają źle w tekście pionowym?

Ponieważ nawias ma dwie formy i tylko jedna z nich należy się do kolumny. Nawiasy, znak długiej samogłoski i małe kana są rysowane inaczej, gdy tekst biegnie w dół strony — nawias obraca się, by siedzieć wzdłuż kolumny zamiast leżeć w poprzek, a znak długiej samogłoski staje się pociągnięciem pionowym. Narysuj formy poziome w kolumnie pionowej, a każdy z nich leży na boku

PDF Library for Delphi bierze formy z własnej cechy pionowej kroju, więc każdy krój dostarcza tego, co narysował jego projektant, a nie podstawienia odgadniętego ze znaku. To rozróżnienie ma znaczenie dla poprawności: odgadnięta tabela podstawień ma rację w zwykłych przypadkach i myli się w krójach, które traktują znak inaczej, a krój nie wymieniający żadnych form pionowych jest rysowany dokładnie tak jak wcześniej, zamiast być przepychanym przez tabelę, o jaką nigdy nie prosił

GetVerticalTextHeight mierzy formy, które faktycznie zostaną narysowane, więc kolumna, której znaki zmieniają kształt, jest wciąż mierzona poprawnie. Mierzenie form poziomych i rysowanie pionowych to klasyczne źródło kolumn, które przebijają swój prostokąt o kilka znaków

Diagram PDF Library for Delphi pokazujący, jak funkcja pionowa czcionki dostarcza form nawiasów i znaku przedłużonego dźwięku leżących wzdłuż pionowej kolumny, podczas gdy zwykłe znaki stoją niezmienione, wszystko mierzone przez GetVerticalTextHeight
Własna funkcja pionowa kroju decyduje, które glify zmieniają formę w kolumnie, a GetVerticalTextHeight mierzy formy, które faktycznie zostaną narysowane

Rysowanie jednego przebiegu bez zmiany trybu

DrawVerticalText rysuje pojedynczy przebieg pionowo, przyjmując pozycję, nazwę czcionki, rozmiar i tekst, a zostawia tryb pisania w spokoju. Używaj go dla pionowego wyjątku wewnątrz poziomego dokumentu — grzbiet etykiety, stempel, pojedyncza kolumna nazwisk — gdzie włączanie i wyłączanie globalnego trybu wokół każdego wywołania to więcej stanu, niż zadanie wymaga

Formy poziome i pionowe jednego kroju są trzymane osobno wewnętrznie, więc strona może nieść obie bez wzajemnego zakłócania. To właśnie to czyni stronę mieszaną praktyczną: strona książki japońskiej z pionowym tekstem głównym i poziomymi nagłówkami biegnącymi albo chiński certyfikat z pionowym tytułem nad poziomymi liniami szczegółów

// Jeden pionowy przebieg wewnątrz poza tym poziomej strony
Lib.DrawVerticalText(520, 96, 'MS Mincho', 14, '保守点検記録');
// Poziomy tekst wokół niego pozostaje niezmieniony
Lib.DrawText(72, 96, 'Maintenance inspection record');

Doprowadzenie czcionki do porządku przed wszystkim innym

Pisanie pionowe zależy w całości od króju. Krój CJK z właściwymi metrykami pionowymi i cechą pionową produkuje poprawny wynik bez dalszej pracy; krój bez nich produkuje wyprostowane znaki posuwające się o jeden em naraz i w ogóle bez zmian kształtu. Jeśli pionowy tekst wygląda subtelnie źle, zbadaj czcionkę przed badaniem kodu

Osadzanie idzie za zwykłymi regułami i zwykłymi kosztami. Pełny krój CJK jest duży, więc subsetting nie jest opcjonalny dla dokumentów, które mają gdziekolwiek trafić — notatki o optymalizacji rozmiaru pliku PDF i subsettingu czcionek omawiają, czego się spodziewać, a przewodnik po osadzaniu brakujących czcionek w istniejącym PDF obejmuje przypadek naprawy, gdy dokument pionowy przychodzi bez swoich czcionek

Gdzie tekst pionowy wciąż wymaga od Ciebie decyzji układu

Kolejność kolumn. Japoński tekst pionowy biegnie od prawej do lewej po kolumnach, więc strona dwukolumnowa zaczyna się od prawej krawędzi, a żadne ustawienie trybu pisania nie jest w stanie wywnioskować tego z tekstu. To samo dotyczy kolejności stron w dokumencie czytanym w całości od prawej do lewej oraz tego, gdzie siedzą furigana, przypisy i podpisy pod figurami

Diagram PDF Library for Delphi DrawVerticalText umieszczającego jeden prosty pionowy przebieg obok zwykłych poziomych linii DrawText na wspólnej stronie bez dotykania globalnego trybu pisania
DrawVerticalText niesie własną czcionkę, rozmiar i pozycję, więc pojedyncza pionowa kolumna współistnieje z poziomymi wywołaniami wokół niej

Czego biblioteka daje gwarancję, to że każdy przebieg jest zapisany poprawnie: poprawne formy, poprawne posuwy, tekst dający się wydobyć. Gdzie przebiegi lądują na stronie, to problem układu, a dla dokumentów składanych z danych przewodnik po wyszukiwaniu tekstu i wyliczaniu elementów strony jest użyteczny do późniejszego sprawdzenia, że to, co wylądowało na stronie, to to, co zamierzałeś

PDF Library for Delphi to natywna biblioteka PDF w Pascalu dla środowisk Delphi, C++Builder i Lazarus, a pisanie pionowe CJK jest częścią API rysowania zamiast dodatkiem — zobacz stronę produktu PDF Library for Delphi, by poznać listę funkcji tekstowych i czcionkowych