При работе с генерацией PDF-документов в Pascal (Delphi/Lazarus) с использованием библиотеки lcl-pdf разработчики часто сталкиваются с проблемой некорректного отображения специальных символов, таких как буквы с диакритическими знаками (например, 'è', 'ä', 'ö', 'ü'). В этой статье мы рассмотрим причины этой проблемы и предложим несколько решений.
Проблема с кодировкой UTF-8
Как видно из обсуждения на форуме, основной проблемой является обработка строковых литералов в кодировке UTF-8. Рассмотрим исходный код, который вызывает проблему:
В этом коде символ 'è' отображается некорректно в итоговом PDF-документе.
Решения проблемы
1. Использование директивы {$codepage UTF8}
Простейшее решение - добавить директиву компилятора, указывающую на использование UTF-8:
{$codepage UTF8}
Это сообщает компилятору, что строковые литералы в коде должны интерпретироваться как UTF-8. Модифицированный код:
program Project1;
{$mode objfpc}{$H+}
{$codepage UTF8} // Добавленная директива
uses
// ... остальной код без изменений
begin
// ... инициализация документа
Page.SetFont(FontBoldID, 11);
Page.WriteText(20, 30, 'è'); // Теперь символ отобразится правильно
// ... сохранение документа
end.
2. Использование UTF8Decode
Альтернативное решение - явное преобразование строки с помощью UTF8Decode:
Page.WriteText(20, 30, UTF8Decode('è'));
Это решение работает, но менее удобно, так как требует явного преобразования каждого специального символа.
3. Использование переменной вместо строкового литерала
Как заметил участник обсуждения wp, проблема может быть решена путем присвоения строки переменной перед передачей в WriteText:
var
s: String;
begin
// ... инициализация документа
s := 'è';
Page.WriteText(20, 30, s); // Работает корректно
// ... сохранение документа
end.
4. Подключение модуля LazUTF8
Для более комплексного решения можно подключить модуль LazUTF8:
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes,
fppdf, fpttf, lazutf8; // Добавлен LazUTF8
var
// ... объявление переменных
begin
// ... инициализация документа
Page.SetFont(FontBoldID, 11);
Page.WriteText(20, 30, 'äöü'); // Работает корректно
// ... сохранение документа
end.
Обратите внимание, что это решение добавляет зависимость от пакета LazUtils в консольных приложениях.
5. Проверка шрифта
Как отметил участник cdbc, проблема может быть связана с используемым шрифтом. Некоторые шрифты не поддерживают специальные символы. Убедитесь, что выбранный шрифт (в данном случае Arial) содержит необходимые символы.
Сравнение решений
Решение
Преимущества
Недостатки
{$codepage UTF8}
Простота, не требует дополнительных модулей
Может потребоваться для всего проекта
UTF8Decode
Точечное решение для конкретных символов
Неудобно для больших текстов
Использование переменной
Работает без дополнительных директив
Требует дополнительного кода
LazUTF8
Комплексное решение для всех строк
Добавляет зависимость от LazUtils
Смена шрифта
Решает проблему отсутствия символов
Ограничивает выбор шрифтов
Рекомендации
Для простых случаев рекомендуется использовать директиву {$codepage UTF8} - это наиболее чистое решение.
Если вы разрабатываете библиотеку или код, который должен работать в разных окружениях, рассмотрите вариант с подключением LazUTF8.
Всегда проверяйте, что выбранный шрифт поддерживает необходимые вам символы.
Для консольных приложений, где важно минимизировать зависимости, можно использовать первые три варианта.
Пример полного рабочего кода
program Project1;
{$mode objfpc}{$H+}
{$codepage UTF8}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
Classes,
fppdf, fpttf;
var
FontID, FontBoldID: Integer;
Document: TPDFDocument;
Section: TPDFSection;
Page: TPDFPage;
s: String;
begin
Document := TPDFDocument.Create(nil);
try
Document.FontDirectory := 'C:\Windows\Fonts';
Document.Options := Document.Options + [poPageOriginAtTop, poNoEmbeddedFonts];
Document.StartDocument;
FontID := Document.AddFont('arial.ttf', 'Arial');
FontBoldID := Document.AddFont('arialbd.ttf', 'Arial Bold');
Section := Document.Sections.AddSection;
Page := Document.Pages.AddPage;
Section.AddPage(Page);
// Обычный текст
Page.SetFont(FontID, 11);
Page.WriteText(20, 20, 'Это обычный текст');
// Текст с особыми символами
Page.SetFont(FontBoldID, 11);
Page.WriteText(20, 30, 'Специальные символы: è, ä, ö, ü, ß');
// Альтернативный вариант с переменной
s := 'Другой текст с символами: à, é, ì, ò, ù';
Page.WriteText(20, 40, s);
Document.SaveToFile('output.pdf');
finally
Document.Free;
end;
end.
Заключение
Проблема с отображением UTF-8 символов при генерации PDF в Pascal имеет несколько решений. Выбор конкретного подхода зависит от ваших требований к проекту. Наиболее универсальным решением является использование директивы {$codepage UTF8}, которое работает в большинстве случаев без дополнительных зависимостей.
При работе с международными приложениями всегда учитывайте вопросы кодировки и поддержки символов на всех этапах разработки - от выбора шрифтов до обработки строк в коде.
Статья описывает проблему некорректного отображения UTF-8 символов при генерации PDF в Pascal с использованием библиотеки lcl-pdf и предлагает несколько решений, включая использование директивы {$codepage UTF8}, функции UTF8Decode, подключение модуля Laz
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.