Технічна стаття

Вертикальний японський та китайський текст у PDF з Delphi

PDF Library for Delphi малює японський та китайський текст донизу сторінкою. SetVerticalWritingMode вмикає вертикальне письмо, звичайні виклики DrawText тоді йдуть униз, а GetVerticalWritingMode повертає поточний стан. До того, як це з'явилося, вертикальне розташування тексту означало розміщення кожного знака вручну з надією, що інтервал виглядатиме правильно

Вертикальне письмо — це не горизонтальний текст, повернутий на дев'яносто градусів. Знаки залишаються прямими, рух іде вниз, а не вбік, і низка знаків повністю змінює форму — це та частина, що відрізняє документ, який читається природно, від того, що японський читач одразу впізнає як машинний

Діаграма PDF Library for Delphi: повернений горизонтальний рядок тексту проти справжнього вертикального режиму письма, де гліфи залишаються прямими, а просування біжить униз сторінки
Вертикальне письмо ставить символи прямо з вертикальними метриками конкретної гарнітури замість обертання горизонтального рядка, а скопійована колонка зчитується назад посимвольно так само

Що змінюється всередині PDF

Текст, намальований таким чином, проходить через шрифт Type0 у режимі вертикального письма, несучи власні вертикальні метрики гарнітури. Це важливо у двох напрямках. Читач просуває кожен знак на відстань, яку задумав дизайнер, а не на однаковий крок, тож колонка має ритм, під який гарнітура малювалася. І копіювання тексту повертає оригінальні знаки, бо вертикальний ряд — це все ще справжній текст із належним відображенням, а не послідовність розташованих гліфів

Гарнітура, що не несе власних вертикальних метрик, просувається на одну em на знак, що й зробив би читач за замовчуванням. Цей запасний варіант варто знати, бо саме ним пояснюється різниця, яку ви побачите, коли документ рендериться правильно з належною CJK-гарнітурою і виглядає механічно розставленим із латинською гарнітурою, що випадково містить трохи кани

var
  Lib: TPDFlib;
  H: Double;
begin
  Lib := TPDFlib.Create;
  try
    Lib.SetOrigin(1);
    Lib.AddTrueTypeFont('MS Mincho', 1);      // 1 = вбудувати накреслення
    Lib.SetTextSize(12);
    Lib.SetVerticalWritingMode(1);            // звичайний DrawText тепер малює вниз
    H := Lib.GetVerticalTextHeight('MS Mincho', 12, '第三章 保守点検');
    Lib.DrawText(480, 72, '第三章 保守点検');
    Lib.SetVerticalWritingMode(0);            // назад до горизонтального
    Lib.DrawText(72, 72 + H, 'Chapter 3');
    Lib.SaveToFile('manual-ja.pdf');
  finally
    Lib.Free;
  end;
end;

Чому дужки виглядають неправильно у вертикальному тексті?

Тому що в дужки дві форми, і лише одна з них належить колонці. Дужки, знак довгої голосної та мала кана малюються по-різному, коли текст іде вниз сторінкою — круглі дужки повертаються, щоб стояти вздовж колонки, а не лежати поперек неї, а знак довгої голосового стає вертикальною рискою. Намалюйте горизонтальні форми у вертикальній колонці, і кожна з них лежатиме на боку

PDF Library for Delphi бере форми з власної вертикальної властивості шрифта, тож кожна гарнітура постачає те, що намалював її дизайнер, а не заміну, вгадану зі знака. Ця різниця важлива для коректності: таблиця замін, що вгадується, правильна для поширених випадків і неправильна для гарнітур, які обходять знак інакше, а гарнітура, що не називає жодних вертикальних форм, малюється точно так само, як і раніше, замість того, щоб проштовхуватися через таблицю, про яку вона не просила

GetVerticalTextHeight вимірює форми, що фактично будуть намальовані, тож колонка, чиї знаки змінюють форму, усе ще вимірюється правильно. Вимірювання горизонтальних форм і малювання вертикальних — класичне джерело колонок, що перевищують свою коробку на кілька знаків

Діаграма PDF Library for Delphi: вертикальна фіча шрифту подає форми дужок і знака подовження звуку, що лежать уздовж вертикальної колонки, тоді як звичайні символи стоять без змін; усе вимірюється GetVerticalTextHeight
Власна вертикальна фіча гарнітури вирішує, які гліфи змінюють форму в колонці, а GetVerticalTextHeight міряє ті форми, що справді будуть намальовані

Малювання одного ряду без зміни режиму

DrawVerticalText малює один ряд вертикально, беручи позицію, назву шрифта, розмір і текст, і залишає режим письма недоторканим. Використовуйте його для вертикального винятку всередині горизонтального документа — корінець, штамп, одна колонка імен — де перемикання глобального режиму навколо кожного виклику є зайвим станом для завдання

Горизонтальні та вертикальні форми однієї гарнітури зберігаються окремо всередині бібліотеки, тож сторінка може нести обидві без взаємних завад. Саме це робить мішану сторінку практичною: сторінка японської книги з вертикальним основним текстом і горизонтальними колонтиулами, або китайський сертифікат із вертикальним заголовком над горизонтальними рядками деталей

// Один вертикальний ряд усередині інакше горизонтальної сторінки
Lib.DrawVerticalText(520, 96, 'MS Mincho', 14, '保守点検記録');
// Горизонтальний текст навколо нього не постраждав
Lib.DrawText(72, 96, 'Maintenance inspection record');

Підготовка шрифта раніше за все інше

Вертикальне письмо повністю залежить від гарнітури. CJK-шрифт із належними вертикальними метриками та вертикальною властивістю дає правильний результат без додаткової роботи; шрифт без них дає прямі знаки, що просуваються по одній em за раз, без жодної зміни форми. Якщо вертикальний текст виглядає тонко неправильним, спершу огляньте шрифт, а вже потім код

Вбудовування підпорядковується звичайним правилам і звичайним витратам. Повна CJK-гарнітура велика, тож підмножина не є необов'язковою для документів, які кудись ідуть — нотатки про оптимізацію розміру PDF та підмножини шрифтів описують, чого чекати, а нарис вбудовування відсутніх шрифтів в існуючий PDF описує випадок відновлення, коли вертикальний документ приходить без своїх шрифтів

Де вертикальний текст усе ще потребує рішення про компонування від вас

Порядок колонок. Японський вертикальний текст іде колонками справа наліво, тож двоколонкова сторінка починається з правого краю, і жодне налаштування режиму письма не здатне вивести це з тексту. Те саме стосується порядку сторінок у документі, що читається справа наліво як ціле, і того, де сидять фуригана, виноски та підписи до фігур

Діаграма PDF Library for Delphi: DrawVerticalText розміщує один прямий вертикальний прогін поруч зі звичайними горизонтальними рядками DrawText на спільній сторінці, не торкаючись глобального режиму письма
DrawVerticalText несе власний шрифт, розмір і позицію, тож одиночна вертикальна колонка співіснує з горизонтальними викликами довкола

Бібліотека гарантує, що кожен ряд виведено правильно: правильні форми, правильні просування, текст, що витягується. Куди ряди лягають на сторінці — це проблема компонування, і для документів, зібраних із даних, нарис пошуку тексту та переліку елементів сторінки корисний для подальшої перевірки, що на сторінку лягло те, що ви задумали

PDF Library for Delphi — це рідна Pascal-бібліотека PDF для Delphi, C++Builder та Lazarus, а вертикальне CJK-письмо є частиною API малювання, а не надбудовою — дивіться сторінку продукту PDF Library for Delphi щодо списку текстових та шрифтових можливостей