Шрифты в 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".

2 сентября 2024

Обзор облачного решения для создания и управления отчетами

МоиОтчеты Облако — это мощное облачное решение для создания и управления отчетами, обеспечивающее широкий спектр возможностей, от создания документов в различных форматах до интеграции с корпоративными системами.
12 августа 2024

Как собрать и установить плагин Postgres в FastReport .NET

В этой статье описывается подключение к базе посредством плагина FastReport .NET для дизайнера отчетов из Visual Studio через NuGet-сервер.
8 августа 2024

Как установить FastReport .NET и его компоненты в Windows

Пошаговая инструкция по онлайн и ручной установке через регистрационный код FastReport .NET и его компонентов в Windows.