Техническая статья

HotPDF: Unicode text shaping for complex scripts в Delphi

HotPDF — нативная VCL PDF-библиотека для приложений Delphi и C++Builder, которым нужны прямое создание и редактирование PDF, формы, аннотации, шифрование, цифровые подписи, Unicode-шрифты, вывод с учетом стандартов и preflight-отчеты без внешнего PDF-runtime.

Эта статья предназначена для developers producing multilingual invoices, certificates, labels, or reports from Delphi. Она рассматривает Unicode text shaping for complex scripts как промышленную инженерию документов, а не как одиночный вызов компонента.

Практический риск состоит в том, что text can appear plausible in a sample PDF while ligatures, bidirectional order, fallback fonts, or copy-and-search behavior fail for real customer names. Поэтому процессу нужны письменный контракт, наблюдаемая диагностика и реалистичные регрессионные файлы.

Архитектурные решения

Make the text pipeline locale-aware. font fallback order for Arabic, Hebrew, Indic, CJK, and mixed Latin text / normalization rules for copied text, database values, and template placeholders

  • font fallback order for Arabic, Hebrew, Indic, CJK, and mixed Latin text
  • normalization rules for copied text, database values, and template placeholders
  • right-to-left paragraph handling and mixed-direction number policy
  • whether text must remain searchable, selectable, and accessible after output

Порядок реализации

Resolve fonts and shaping before pagination. The order below keeps the workflow reviewable for Delphi and C++Builder teams.

  1. normalize source text and record the locale used for formatting
  2. select fonts that contain the required glyphs before measuring layout
  3. shape and position text before page breaks are finalized
  4. embed or subset fonts according to licensing and PDF standard requirements
  5. verify visual output and extracted text with multilingual regression samples

Доказательства проверки

Proof that text is readable and extractable. Keep these fields with the output or support record.

  • font selected for every script range and fallback reason when it changed
  • glyph coverage warnings, embedding mode, and subset identifier
  • extracted Unicode text compared with the original application value
  • viewer screenshots for representative right-to-left and combining-mark cases

Visual output is not enough

Complex-script support involves character normalization, shaping, glyph positioning, embedding, ToUnicode maps, and reading order. A PDF that only looks right in one viewer can still fail search, selection, accessibility, or downstream extraction.

Regression files worth keeping

Keep more than successful samples. A useful Unicode text shaping for complex scripts regression set contains normal files, boundary files, and intentional failure files so the behavior is stable across releases.

  • database collation can alter composed characters before the PDF layer sees them
  • font substitution on a developer machine can hide missing embedded fonts
  • line breaks in bidirectional text can reorder punctuation and numbers
  • search may fail when ToUnicode data is missing even if the page renders correctly
  • normalize source text and record the locale used for formatting
  • select fonts that contain the required glyphs before measuring layout

Замечания для инженерного ревью по Unicode text shaping for complex scripts

Используйте эти замечания, чтобы убедиться, что функция вышла за рамки демо и может быть обоснована на релизе, в поддержке и при эскалации клиента

  • Решение: font fallback order for Arabic, Hebrew, Indic, CJK, and mixed Latin text. Точка приложения при реализации: select fonts that contain the required glyphs before measuring layout. Доказательство приемки: extracted Unicode text compared with the original application value. Триггер регрессии: search may fail when ToUnicode data is missing even if the page renders correctly
  • Решение: normalization rules for copied text, database values, and template placeholders. Точка приложения при реализации: shape and position text before page breaks are finalized. Доказательство приемки: viewer screenshots for representative right-to-left and combining-mark cases. Триггер регрессии: database collation can alter composed characters before the PDF layer sees them
  • Решение: right-to-left paragraph handling and mixed-direction number policy. Точка приложения при реализации: embed or subset fonts according to licensing and PDF standard requirements. Доказательство приемки: font selected for every script range and fallback reason when it changed. Триггер регрессии: font substitution on a developer machine can hide missing embedded fonts
  • Решение: whether text must remain searchable, selectable, and accessible after output. Точка приложения при реализации: verify visual output and extracted text with multilingual regression samples. Доказательство приемки: glyph coverage warnings, embedding mode, and subset identifier. Триггер регрессии: line breaks in bidirectional text can reorder punctuation and numbers

Пограничные случаи

  • database collation can alter composed characters before the PDF layer sees them
  • font substitution on a developer machine can hide missing embedded fonts
  • line breaks in bidirectional text can reorder punctuation and numbers
  • search may fail when ToUnicode data is missing even if the page renders correctly

Примечания по Delphi / C++Builder

HotPDF Component should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Важные термины включают Unicode, text shaping, font embedding, ToUnicode, bidirectional text, fallback font.

Пример кода Delphi

Следующий эскиз Delphi показывает практическую границу сервиса для этой темы. Оставляйте проверки политики, журналирование и валидацию вне узкого блока вызова продукта, чтобы сценарий было проще тестировать.

procedure DrawShapedRun(Pdf: THotPDF; const Text: UnicodeString; const Script: TScriptProfile);
begin
  Pdf.CurrentPage.SetFont(Script.FontName, [], Script.Size, 0, Script.Vertical);
  if Script.RequiresReorder then
    Pdf.CurrentPage.TextOut(Script.X, Script.Y, 0, ShapeUnicodeRun(Text, Script))
  else
    Pdf.CurrentPage.TextOut(Script.X, Script.Y, 0, Text);
  RecordGlyphCoverage(Script.FontName, Text);
end;

Производственный чек-лист

  • Запускайте сценарий на пустом файле, обычном клиентском файле и файле худшего случая
  • Открывайте сгенерированный PDF в целевом просмотрщике, валидаторе, принтере или downstream-приложении
  • Записывайте версию продукта, версию профиля, хэш входа, путь вывода, затраченное время и число предупреждений
  • Храните пароли, сертификаты, временные файлы и данные клиентов по явным правилам хранения
  • Добавляйте регрессионные документы, когда клиентский файл выявляет новый граничный случай

Документация по продукту

HotPDF Component

Дополнительные примеры кода

// Ship a known font instead of relying on installed system fonts
Pdf.RegisterUnicodeTTF('C:\Fonts\NotoSansArabic.ttf');
Pdf.CurrentPage.SetFont('NotoSansArabic', [], 12);

// Audit coverage for the codepoints your data actually uses
GID := Pdf.GetUnicodeGlyphForCodepoint($0628);  // U+0628 ARABIC LETTER BEH
LogGlyphAudit($0628, GID);
// Declare right-to-left reading order at the document level
Pdf.Direction := RightToLeft;  // adds vpDirection to ViewerPreferences