Шрифты в PDF экспорте в FR VCL 5

26.08.2011

Что такое "эмбеддинг" шрифта

PDF документы часто содержат текст написанный разными шрифтами. Чтобы Acrobat Reader или другой просмотрщик pdf могли изобразить этот текст, ему нужен доступ к файлам шрифтов используемых в документе. Если на ОС в которой вы открываете pdf не будет нужных шрифтов, то текст может стать нечитаемым. Для решения этой проблемы в стандарте PDF есть возможность копировать файлы используемых шрифтов внутрь документа, таким образом гарантируя, что где бы вы ни открыли документ, шрифты всегда будут доступны и текст будет читаемым. Такое копирование шрифтов называется "эмбеддингом" (от англ. embedding). Здесь, конечно, возникает проблема: файлы шрифтов часто имеют большой размер и pdf файл может стать неприемлемо большим из за эмбеддинга. PDF экспорт в FR VCL 4 умеет делать эмбеддинг, но делает это самым простым способом - просто копирует все файлы шрифтов в документ. Иногда такое приводит к раздуванию pdf файла до десятков мегабайт.

Эмбеддинг шрифтов в FR VCL 5

В пятой версии было решено улучшить эмбеддинг, за счёт извлечения из нужных шрифтов только используемых символов. Обычно из каждого шрифта используется не более 50 символов - это связано с тем, что pdf документ создаётся на каком либо одном языке и потому использует символы только одного алфавита. Шрифты же, особенно универсальные как Arial Unicode MS и восточные, в которых изображены иероглифы, содержат от 3 до 50 тысяч символов.

Для примера возьмём простой отчёт в котором несколько абзацев текста написаны шрифтом Arial. Отчёт использует только 41 символ, тогда как в Arial их 3415. Поэтому, если извлечь эти 41 символ и вставить их в pdf файл, то можно сэкономить почти 700 кб - размер шрифта Arial. Ещё один показательный пример: экспортируйте этот отчёт в pdf с включённым эмбеддингом и посмотрите на размер получившегося файла - больше 30 мб; если этот же отчёт сохранить в pdf экспортом из 5-ой версии, то получится вот такой файл на 116 кб, который даже открывается в Acrobat Reader значительно быстрее.

В этой ветке нашего форума можно взять тестовую программу которая экспортирует в pdf с новой версией эмбеддинга.

Как устроен шрифт

Обычно шрифт представлен файлом формата TTF, реже - файлом формата TTC который просто содержит несколько TTF файлов. Шрифт состоит из двух важных частей:

  • Массив глифов. Каждый из глифов является изображением некоторого символа или части символа. Глиф в TTF представлен в виде кривых Безье и, возможно, картинки показывающей как должен выглядеть глиф для очень маленького размера шрифта.
  • Таблица "cmap" которая задаёт отображение 2-байтного юникода в индекс глифа. Такая таблица нужна потому что шрифт редко содержит глифы для всех возможных значений юникода и нужно как то указать, для каких именно юникодов в шрифте есть глифы.



Некоторые символы нарисованы при помощи одного глифа: обычно символы английского алфавита нарисованы именно так. Другие символы могут быть представлены несколькими глифами: например русская буква Ё во многих шрифтах состоит из глифа буквы Е и глифа изображающего две точки (точнее два квадрата - точки в шрифтах почему то рисуют в виде квадратов). Наконец, некоторые шрифты содержат глифы изображающие сразу несколько символов (т.н. лигатуры), глифы изображающие символ в зависимости от его положения в слове и некоторые другие особые глифы. Вообщем, алгоритм который узнает какими глифами изобразить слово не такой тривиальный как может показаться.

Реализация эмбеддинга в PDF экспорте

Суть эмбеддинга в том, что из массива глифов, из таблицы "cmap" и других таблиц в шрифте извлекается информация соответствующая используемым глифам, после чего создаются аналогичные таблицы куда записывается извлечённая информация. В итоге получается файл шрифта, но с меньшим количеством глифов. Пример такого укороченного файла здесь.

Далее, полученный шрифт записывается в pdf файл в виде нескольких pdf объектов. Рассмотрим это на примере отчёта с одной строчкой "Open Type Font" внутри, из которого получается вот такой pdf файл.


Код


%PDF-1.5
%ЂЂЂЂ

% Этот pdf объект представляет TfrxMemoView с текстом "Open Type Font".
% Он выбирает шрифт оператором Tf и рисует текст оператором Tj.

2 0 obj
<< /Length 257 /Length1 257 >>
stream
...
/F0 10 Tf
...
<004F00700065006E0020005400790070006500200046006F006E0074> Tj
...
endstream
endobj

% Общее описание шрифта
% Поле /Encoding задаёт преобразование кодов символов в CID-ы.
% Здесь это преобразование тождественно, т.е. CID символа равен его коду.

3 0 obj
<<
/Type /Font
/Subtype /Type0
/BaseFont /IJIVDA+Arial
/Encoding /Identity-H
/DescendantFonts [11 0 R]
/ToUnicode 6 0 R
>>
endobj

% Это параметры шрифта.
% Здесь указываются параметры извлекаемые из файла шрифта.

9 0 obj
<<
/Type /FontDescriptor
/FontName /IJIVDA+Arial
/FontFamily /IJIVDA+Arial
/FontBBox [-1361 -665 4096 2060]
/ItalicAngle 0
/Ascent 1854
/Descent -434
/CapHeight 0
/StemV 0
/Flags 32
/CIDSet 5 0 R
/FontFile2 8 0 R
>>
endobj

11 0 obj
<<
/Type /Font
/Subtype /CIDFontType2
/CIDToGIDMap 10 0 R
/BaseFont /IJIVDA+Arial
/CIDSystemInfo 7 0 R
/FontDescriptor 9 0 R
/W [ 32 [277.8] 70 [610.8] 79 [777.8] 84 [610.8] 101 [556.2] 110 [556.2] 111 [556.2] 112 [556.2] 116 [277.8] 121 [500.0] ]
>>
endobj

% А это сам TTF файл с шрифтом.
% Между stream и endstream находится .ttf файл с нужными глифами.

8 0 obj
<< /Length 15148 /Length1 10856 /Filter [ /ASCIIHexDecode /FlateDecode ] >>
stream
7801c57a7b...00175ac7e0
endstream
endobj

% Таблица преобразования CID-ов в индексы глифов.

10 0 obj
<< /Length 86 /Length1 244 /Filter [ /ASCIIHexDecode /FlateDecode ] >>
stream
78016360a0103052a81f593b133207cc66868bb0c059b818ac18126c0cec0c1c50514eb82c1700078f0038
endstream
endobj

...
%%EOF



Здесь все параметры шрифта очень просты. Интерес представляет то, как оператор Tj выводит текст.

  • В качестве аргумента он принимает последовательность 2-байтных кодов. В примере это коды 4f 70 65 6e и т.д.
  • Каждый код оператор преобразуется в CID, при помощи параметра шрифта /Encoding /Identity-H. В данном случае преобразование тривиальное - все коды не изменяются. Теперь у оператора Tj есть последовательность CID-ов (она та же самая: 4f 70 65 6e ...) и далее он работает с этими CID-ами.
  • Каждый CID преобразуется в GID с помощью параметра /CIDToGIDMap. GID это индекс глифа. После этого у Tj есть индексы глифов и он может начать рисовать текст.



Здесь нужно заметить, что стандарт PDF не используется таблицу "cmap" которая отвечает как раз за поиск глифов по кодам символов. Вместо этого в pdf файл нужно записывать аналог "cmap".

VCL FastReport PDF
10 июля 2026

Как настроить Content Security Policy для отчетов FastReport .NET WEB

Узнайте, как настроить Content Security Policy для отчётов FastReport .NET WEB: обзор директив и значений CSP, изменения в архитектуре FastReport, типичные сценарии обхода и способы защиты.
22 июня 2026

Как настроить отчет с Business Objects из кода и дизайнера в FastReport .NET

В этой статье рассматривается реальный пример создания и использования шаблона отчета .frx для подключения к иерархическим бизнес-объектам в FastReport .NET.
21 апреля 2026

Использование водяных знаков в FastReport VCL

В статье подробно рассмотрели функционал добавления водяных знаков в FastReport VCL — как через визуальный интерфейс, так и программно, с помощью кода на Delphi и в скриптах отчётов.

Не является публичной офертой
© 1998-2026 ООО «Быстрые отчеты»