Формат TTF - чтение и запись

Общие темы о программировании
Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Формат TTF - чтение и запись

Сообщение blackstrip » Сб дек 15, 2012 10:42 pm

Пришла в голову мысль сделать в PaintCAD 4Windows экспорт PCF шрифтов в TTF. Чтобы можно было использовать нарисованные шрифты не только в PCW, но и в других программах.

PCF - формат растровый, внутри него картинки букв, цифр и других символов. (кстати, недавно узнал что есть еще один формат шрифтов PCF - Portable Compiled Format, он тоже растровый, как ни странно).

А TTF - векторный. Внутри него опорные точки для прямых линий, кривых линий Безье и множество других вещей, даже можно внутрь запихнуть растр (вроде как).

Формат TTF придумал Apple. Потом он разошелся на разные подформаты, один для Mac-ов, другой для Винды, еще для OS/2 что то было. Вроде бы это все один и тот же формат, но для каждого направления там свои особенности что ли.

У майкрософта и у эппла есть спецификации по этому формату. Возьмем майкрософтские (PaintCAD 4Windows же, а не 4Mac): http://www.microsoft.com/typography/Spe ... rview.mspx

Возьмем главу про формат файла: http://www.microsoft.com/typography/tt/ ... ttch02.doc

Т.к. в инете почти нет информации про чтение TTF, и тем более про запись TTF, а тем более на русском - то буду потихоньку переводить этот файл спецификации. Переведенное в упрощенном виде буду выкладывать в эту тему. Основная задача - записать растр в векторный формат TTF. Кому то может быть будет интересно почитать (тем кто тоже захочет читать и писать TTFы). Заодно и сам разберусь.

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вс дек 16, 2012 12:11 pm

Значит то, что будет записываться у нас - это файл OpenType. Он может иметь расширение как TTF, так и OTF. Зависеть расширение файла должно от того, если ли в нашем шрифте TrueType outlines или нет. Но чтобы долго не думать - будем сохранять с расширением TTF, а что это за зверь "TrueType outlines", наверное, поймем позже.

Во всей этой документации используются следующие типы данных:
BYTE 1-байтовое беззнаковое целое
CHAR 1-байтовое знаковое целое
USHORT 2-байтовое беззнаковое целое
SHORT 2-байтовое знаковое целое
UINT24 3-байтовое беззнаковое целое
ULONG 4-байтовое беззнаковое целое
LONG 4-байтовое знаковое целое
Fixed 4-байтовое знаковое с фиксированной (неплавающей) точкой (а ля 16 бит до точки и 16 бит после)
FUNIT Минимальное измеряемое расстояние в пространстве "em"
FWORD 2-байтовое знаковое целое (SHORT), которое описывает количество в единицах FUNIT.
UFWORD 2-байтовое беззнаковое целое (USHORT), которое описывает количество в единицах FUNIT.
F2DOT14 2-байтовое знаковое с фиксированнной точкой, где 2 бита - число до точки, а 14 оставшихся - после точки (а ля 2.14).
LONGDATETIME Дата, описывающая количество секунд с полуночи 12:00 от 1 января 1904 года. Знаковое 64-битное целое.
Tag Массив из четырех uint8s (длина в общем - 32 бита) используется для идентификации скрипта, языковой системы, фичи или базовой линии
GlyphID Индекс глифа, такой же как uint16 (длина 16 бит)
Offset Смещение таблицы, такое же как uint16 (длина 16 бит), неустановленное смещение (NULL) должно быть равно 0x0000

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вт дек 18, 2012 8:05 am

Чтобы не просто читать документацию, а сравнивать ее с реальными шрифтами - возьмем несколько готовых TTF шрифтов и будем смотреть их внутреннюю структуру.

Я выбрал три шрифта из папки Windows/Fonts
Изображение

Первый - пиксельный грубый шрифт, примерно такой же я хочу получать в паинткаде из растрового PCF шрифта. Чем больше выбираем размер - тем сильнее увеличиваются квадраты-пиксели:
Изображение

Второй - шрифт для нотной грамоты, там всякие ноты, паузы и другие значки:
Изображение

Третий - спецшрифт от Adobe, внутри почти нет символов, несколько хреновинок и точек:
Изображение

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вс сен 01, 2013 2:45 pm

Почитав разные источники, понял что выбрал не те шрифты для разбора)

С этого http://www.dafont.com/bitmap.php сайта можно взять пиксельные мелкие шрифты. Хороший мелкий шрифт Wendy http://img.dafont.com/dl/?f=wendy

Изображение

Смотрим его в хекс-редакторе, попутно читая документацию по TTF от Apple и от Microsoft

4 байта: 00 01 00 00 - это тип "масштабатора" (ну той штуки, которая видимо их отрисовывает с разными размерами). Как пишут тут https://developer.apple.com/fonts/TTRef ... erTypeNote - это или 0x00010000 (или даже 0x74727565) как нормальный TTF, либо другие значения для других масштабирований. Причем подчеркнуто, что Fonts for Windows must use 0x00010000. А я как раз в PCW хочу сохранить шрифт для Windows, значит берем 00 01 00 00 как первые 4 байта любого сохраняемого TTF шрифта.

2 байта: 00 0С - "количество таблиц". 12 штук. Ну и хорошо.

2 байта: 00 80 - "диапазон поиска" - 16 умножить на максимальную степень двойки, меньшую или равную "количеству таблиц". В байтах у нас число 128. Поделим обратно на 16 - будет 8. Ну все правильно.
2^0 - это 1. И это меньше 12 таблиц.
2^1 - это 2. И это меньше 12 таблиц.
2^2 - это 4. И это меньше 12 таблиц.
2^3 - это 8. И это меньше 12 таблиц.
2^4 - это 16. И это больше 12 таблиц! Он уже не подходит, надо брать предыдущий. Значит 8 это максимальный результат возведения двойки в степень. Его и записали, причем умноженным на 16.

2 байта: 00 03 - "входной селектор". Логарифм по основанию 2 от (максимальной степени двойки, меньшей или равной "количеству таблиц"). Это в какую степень надо возвести 2, чтобы получить не большее число, чем количество таблиц. В предыдущих двух байтах нам подошло число 2^3, поэтому сюда надо эту самую степень, т.е. 3. Так оно и есть.

2 байта: 00 40 - "сдвиг диапазона". Это ("количество таблиц" * 16 - "диапазон поиска") = 12 * 16 - 128 = 12 * 16 - 8 * 16 = 4 * 16 = 64, т.е. 40 в шестнадцатиричной системе. Так оно и есть.

Вот такой основной заголовок TTF шрифта. Совсем несложный вроде бы. Ниже под ним идут структуры для каждой из 12 таблиц.

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вс сен 01, 2013 3:12 pm

Заголовок таблицы

4 байта - идентификатор, обычный текст. Например, cmap, glyf, head и т.д.
4 байта - контрольная сумма. О ней ниже.
4 байта - смещение в байтах от начала sfnt-файла (видимо в яблочных устройствах TTF-файлы именуются как SFNT).
4 байта - длина таблицы в байтах.

Apple приводит код для подсчета контрольной суммы:

uint32 CalcTableChecksum(uint32 *table, uint32 numberOfBytesInTable)
{
uint32 sum = 0;
uint32 nLongs = (numberOfBytesInTable + 3) / 4;

while (nLongs-- > 0)
sum += *table++;

return sum;
}


Приходит в процедуру указатель на массив table и 32-битная длина таблицы в байтах (видимо, та самая из заголовка таблицы). Высчитывается длина таблицы в 4-байтных словах (1 байт = (1+3)/4 = 1 слово, 2 байта - 1 слово, 3 байта - 1 слово, 4 байта - 1 слово, 5 байт = (5+3)/4 = 2 слова, 6 байт - 2 слова и т.д., поэтому там +3). И потом в цикле по всем 4-байтным элементам таблицы идет сложение их беззнаковых значений в одну кучу (одно беззнаковое число). Беззнаковые 32-битные в дельфе это тип Longword или Cardinal (одно и тоже, но Longword это "фундаментальный", а Cardinal нет, в общем то разницы между ними нет).

Таким образом, в дельфе это будет нечто типа
checksum:=0;
leng:=(lenbytes+3) div 4;
for i:=0 to leng-1 do checksum := checksum + table; ,
достаточно простой подсчет. Я ожидал худшего.

Apple приводит обязательные таблицы в TTFе, а также необязательные.

Обязательные (9 штук, значит в шрифте Wendy из 12 таблиц еще есть 3 штуки необязательных):
'cmap' -связи между символами и их номерами
'glyf' - изображения символов
'head' - заголовок шрифта
'hhea' - горизонтальный заголовок
'hmtx' - горизонтальные метрики
'loca' - индекс положения
'maxp' - профиль максимума
'name' - обозначение
'post' - PostScript

Необязательные:
'cvt ' - контрольное значение
'fpgm' - программа шрифта
'hdmx' - горизонтальные метрики устройства
'kern' - кернинг
'OS/2' - OS/2
'prep' - программа контрольного значения

В хекс-редакторе сразу виды все названия таблиц в шрифте друг под другом (т.к. длина заголовка таблицы 16 байт и в хекс-редакторах обычно бывает по 16 байт на строку), это OS/2, cmap, fpgm, glyf, head, hhea, htmx, loca, maxp, name, post, prep.

Изображение

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Пн сен 02, 2013 4:55 pm

Придется посмотреть все таблицы по очереди, чтоб понять как устроен TTF.

Итак, расшифровываем заголовки таблиц и содержимое каждой таблицы.

Название
4F 53 2F 32
OS/2
Контрольная сумма
6E 3C 74 00
Смещение
00 00 01 48
С 328-го байта
Длина
00 00 00 4E
78 байт

Лезем на 328 байт и смотрим по документации, что такое таблица OS/2: https://developer.apple.com/fonts/TTRef ... p6OS2.html
Написано, что таблица требуется для шрифтов Windows. И еще написано, что она в оригинале была 68 байт, но для майкрософтовских шрифтов были введены удлиненные версии 78 и даже 86 байт. Далее приведен пример 68-байтной таблицы. Нам это не подходит, у нас 78 байтная. Лезем в документацию майкрософта http://www.microsoft.com/typography/otspec/os2.htm . Оказывается бывает такая таблица версий 0, 1, 2, 3, 4. Страница с описанием нулевой версии для windows дается ниже по ссылке: http://www.microsoft.com/typography/otspec/os2ver0.htm

Отличия от Apple: после полей fsFirstCharIndex и fsLastCharIndex есть еще лишние 10 байт, превращающие таблицу из 68 байт в 78 байт.

Поехали по файлу:
2 байта 00 00 - версия таблицы, должна быть 0. Так и есть.
2 байта 01 68 - 360, среднее значение ширины символа в "пикселях" (pels). Видимо имеются ввиду какие то маленькие пиксели, типографские какие нибудь) Расчет этого числа предлагается проводить умножая реальную ширину в пикселях каждого из символов на его вес (дается таблица весов, где у буквы a вес 64, у пробела 166 и т.д.), а затем эту сумму надо еще поделить на 1000. В общем если лень это считать - то можно использовать любое число, видимо это число для тех, кто сидит в типографии и выбирает шрифт по "средней температуре по больнице" +) Например, использовать 360.
2 байта 01 90 - 400, класс веса (жирноты), бывает, судя по майкрософту, от 100 (ультратонкий) до 900 (ультражирный). 400 это нормальный (Regular).
2 байта 00 05 - 5, класс ширины, от 1 (ультрасжатый) до 9 (ультрарасширенный). У нас 5, это Нормальный.
2 байта 00 00 - 0, характеристики шрифта. Если равен нулю, то шрифт "устанавливаемый и встраиваемый", свободный. А иначе можно установить разные биты, и таким образом сказать, что он лицензионный, защищенный, только для печати и т.п. У нас это 0 - свободный шрифт.

Дальше идут 4 поля по 2 байта, они описывают, что надо сделать со шрифтом, если использовать его для нижнего индекса:
2 байта 00 64 - 100, горизонтальный размер при нижнем индексе
2 байта 00 64 - 100, вертикальный размер при нижнем индексе
2 байта 00 00 - 0, смещение по горизонтали при нижнем индексе
2 байта 00 8С - 140, смещение по вертикали при нижнем индексе

Дальше идут 4 поля по 2 байта, они описывают, что надо сделать со шрифтом, если использовать его для верхнего индекса (причем такие же, как и для нижнего индекса):
2 байта 00 64 - 100, горизонтальный размер при верхнем индексе
2 байта 00 64 - 100, вертикальный размер при верхнем индексе
2 байта 00 00 - 0, смещение по горизонтали при верхнем индексе
2 байта 00 8С - 140, смещение по вертикали при верхнем индексе

Дальше 2 поля по 2 байта, они описывают рекомендуемую толщину штриха и его вертикальное положение при отрисовке текста, зачеркнутого посередине горизонтальной линией:
2 байта 00 32 - 50, толщина штриха
2 байта 00 FA - 250, смещение

2 байта 00 00 - 0, класс семейства шрифтов. У Apple расписана таблица с классами, старший байт это класс, младший байт это подкласс. 0 - это "никакой" класс, т.е. пофиг какой. Отлично.

Далее 10-байтовая структура с говорящим названием "panose":
10 байт 00 00 00 00 00 00 00 00 00 00 - вообще в этой структуре задаются свойства шрифта, но если поставить все нули, это значит выставить "любой" (Any) во все свойства.

Далее 4 поля по 4 байта каждое, делятся на 96 и 32 бит. Рекомендуют ставить нули, т.к. еще не утвердили конкретно какие биты выставлять и что это будет значить =) Тут зачем-то стоит тройка в одном из полей.
4 байта 00 00 00 03 - 3
4 байта 00 00 00 00 - 0
4 байта 00 00 00 00 - 0
4 байта 00 00 00 00 - 0

4 байта 6D 69 65 70 - "miep", поле с названием вендора ("продавца, ответственного за маркетинг и распространение").

2 байта 00 40 - поле с битами, обозначающими какие же буквы в шрифте (наклонные, зачеркнутые, жирные, обведенные и т.п.). В двоичной системе это 01000000, т.е. 6 бит установлен, это обычный шрифт (REGULAR).

2 байта 00 20 - 0, минимальный код символа (в Unicode) в шрифте, то бишь первый символ "пробел" с 32 кодом.
2 байта 00 FC - 0, максимальный код символа (в Unicode) в шрифте, т.е. последний символ

Вот уже прошли 68 байт. Осталось 10 байт, которые Microsoft добавили в формат таблицы:
2 байта 02 BC - 700, типографский надстрочник, используется для расчета расположения пробелов между строк текста. Ну и пусть будет 700.
2 байта FF 38 - минус 200, типографский подстрочник, используется для расчета расположения пробелов между строк текста. Ну и пусть будет -200.
не забывайте смотреть в таблице, что поля SHORT - это знаковые, и тогда FF38 будет не 65336, а -(FFFF-(FF38-1)) = -(65535-(65336-1)) = -200

2 байта 00 1E - 30, расстояние между строками.
2 байта 03 BC - 956, виндовское расстояние над строкой, рассчитывается как Y максимальное для всех символов. Используется виндой для расчета расстояния между строками по умолчанию. Винда обрезает все куски символов, которые вылезут выше этого значения.
2 байта 01 64 - 356, виндовское расстояние под строкой, рассчитывается как минус Y минимальное для всех символов. Используется виндой для расчета расстояния между строками по умолчанию. Винда обрезает все куски символов, которые вылезут ниже этого значения.

Вот такая вот таблица OS/2, причем она обязательная для Windows шрифтов.

Осталось разобраться, что же это за "пиксели", которые называются то pels, то font design units. Некоторые опорные единицы, и видимо очень мелкие (равные одному пикселю при огромном размере шрифта, 1000, например). Или можно взять за основу то что есть в этом шрифте, а уже походу испытаний сохраненных шрифтов выискивать баги в расчете этих величин (когда винда начнет срезать куски букв при отрисовке и т.д.).

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вт сен 03, 2013 3:09 am

Следующей в каталоге шрифта в файле wendy.ttf идет таблица cmap.

Название
63 6D 61 70
cmap
Контрольная сумма
0F FC 10 79
Смещение
00 00 03 14
С 788-го байта
Длина
00 00 01 98
408 байт

CMAP - это character code mapping, т.е. таблица назначения кодов символов. Описание этой таблицы лежит по адресу https://developer.apple.com/fonts/TTRef ... 6cmap.html

Коды символов, для которых в шрифте нет векторного рисунка (глифа), должны быть назначены на глиф номер ноль.

2 байта 00 00 - версия таблицы, должна быть равна 0. Так и есть.
2 байта 00 02 - 2, количество подтаблиц.

Далее идет заголовок первой подтаблицы.
2 байта 00 01 - 1, идентификатор платформы.
2 байта 00 00 - 0, идентификатор кодировки, спефицичной для этой платформы.
Расшифровка этих кодов есть в описании таблицы name - https://developer.apple.com/fonts/TTRef ... me.html#ID
Для этой подтаблицы платформа 1 означает Macintosh, а кодировка 0 означает Roman.
4 байта 00 00 00 14 - 20, смещение, по которому лежит таблица

Далее идет заголовок второй подтаблицы.
2 байта 00 03 - 3, идентификатор платформы.
2 байта 00 01 - 1, идентификатор кодировки, спефицичной для этой платформы.
Для этой подтаблицы платформа 3 означает Microsoft, а кодировка 1 означает Unicode BMP (UCS-2). Майкрософт очень сильно рекомендует эту кодировку.
Вот здесь есть таблица для майкрософта: http://www.microsoft.com/typography/otspec/cmap.htm
А вот здесь объяснено про Unicode BMP: http://en.wikipedia.org/wiki/Plane_(Uni ... gual_Plane
4 байта 00 00 01 1С - 284, смещение, по которому лежит таблица

От начала таблицы cmap прошло как раз 20 байт (4+8+8) и далее начинается первая подтаблица для Macintosh. Однако, мы делаем шрифт для Windows, поэтому перейдем сразу ко второй подтаблице. Значит надо проехать от начала первой подтаблицы на (284-20)=264 байта.

Смотрим заголовок.
2 байта 00 04 - 4, подтаблица формата "4". Смотрим ее формат у майкрософта http://www.microsoft.com/typography/otspec/cmap.htm под заголовком Format 4: Segment mapping to delta values, раскодируем следующие поля:
2 байта 00 7С - 124, длина подтаблицы 124 байт.
2 байта 00 00 - 0, язык.
2 байта 00 1A - 26, количество сегментов, умноженное на два.
Далее идут еще много полей. Формат "4" обеспечивает 2-байтовую кодировку. Для PaintCAD 4Windows это излишне, т.к. текстовые шрифты PCF предназначены для хранения 256 символов по досовской аски-таблице.

Поэтому посмотрим на формат "0". Это самый простой однобайтовый формат. Для него заголовок подтаблицы должен выглядеть следующим образом:
2 байта 00 00 - формат подтаблицы, ноль-ноль.
2 байта 00 00 - длина подтаблицы, т.к. будет 256 символов, то длина, посчитанная в Apple, должна составить 262 байта (6 - заголовок и 256 - массив индексов глифов, логично).
2 байта 00 00 - язык. Если ноль - то языконезависимая таблица. Наверное, подойдет.
256 байт - 256-байтовый массив номеров глифов, соответствующих тому или иному коду. Как писали выше, все символы, которые не имеют изображения - должны указывать на нулевой глиф.

Вот такую cmap с подтаблицей формата "0" будем записывать при перекодировке PCF в TTF. Попробуем, съест ли это винда вообще. Вместо кодировки Unicode BMP (UCS-2) в заголовке таблицы попробуем использовать Symbol (0) кодировку. Да и у майкрософта написано, что When building a symbol font for Windows, the platform ID should be 3 and the encoding ID should be 0. Так что все норм.

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вт сен 03, 2013 3:41 am

Следующей в каталоге шрифта в файле wendy.ttf идет таблица fpgm.

Название
67 70 67 7D
fpgm
Контрольная сумма
30 D1 A5 01
Смещение
00 00 04 AC
С 788-го байта
Длина
00 00 01 D2
466 байт

FPGM - font program, обеспечивает некоторое "программирование" отрисовки шрифтов на каком то ассемблере со стеком. Описывается вот здесь https://developer.apple.com/fonts/TTRef ... nt_program . Пропускаем эту таблицу, она необязательна и, думаю, не понадобится при конвертации PCF в TTF.

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вт сен 03, 2013 3:53 am

Следующей в каталоге шрифта в файле wendy.ttf идет, наверное, самая интересная (и самая длинная) таблица glyf, в которой записаны векторные изображения символов.

Название
67 6C 79 66
glyf
Контрольная сумма
FB 73 6D F9
Смещение
00 00 07 48
С 1864-го байта
Длина
00 00 1B A8
7080 байт

Принцип записи векторных букв в TTF хорошо описывается в википедии http://ru.wikipedia.org/wiki/TrueType .
Также описание таблицы glyf есть у Apple: https://developer.apple.com/fonts/TTRef ... 6glyf.html
И у майкрософт: http://www.microsoft.com/typography/otspec/glyf.htm

Контуры, вписанные друг в друга, закрашиваются при отрисовке в зависимости от того, в каком направлении идут внутренний и внешний контуры - по или против часовой стрелки.

Цель же конвертации PCF в TTF - превратить каждый пиксель растрового PCF в векторный квадрат в TTF-е. Поэтому и был выбран для разбора шрифт Wendy - он сделан именно из квадратов-пикселей. Если открыть его в редакторе шрифтов, то можно увидеть - каждый пиксель это реальный квадрат из 4 опорных точек. Точки нумеруются по порядку, например, для 1 контура это 1.1, 1.2, 1.3, 1.4. Вот глиф номер 26 "двоеточие":

Изображение

Во избежание пересечения контура - рядом стоящие углы соседних векторных пикселей не совпадают, а чуть-чуть расходятся. Этого достаточно, чтобы каждый векторный пиксель отрисовывался отдельно как закрашенный квадрат и не образовывал дополнительных пересечений пикселей с другой закраской.

Изображение

Продолжение следует...

Аватара пользователя
blackstrip
Админ
Сообщения: 1176
Зарегистрирован: Ср янв 02, 2008 1:42 pm
Откуда: Подольск
Контактная информация:

Re: Формат TTF - чтение и запись

Сообщение blackstrip » Вт сен 03, 2013 5:05 am

Переходим на смещение 0x748. Там лежит первый глиф. Судя по редактору шрифтов ttfedit - это восклицательный знак:

Изображение

Смотрим данные таблицы и документацию по glyf-таблице:

2 байта 00 02 - 2, это два контура в глифе. Действительно, у восклицательного знака 2 контура - это черта и точка. Если это число отрицательное - то это составной глиф, состоит из стольких отдельно описанных простых (как Ё = Е+две точки).
2 байта 00 00 - 0, минимальный X
2 байта 00 00 - 0, минимальный Y
2 байта 00 64 - 100, максимальный X
2 байта 01 F3 - 499, максимальный Y

Причем, судя по редактору шрифтов, ось X - отсчитывается вправо, а ось Y - вверх. Как в математике (а не как в программировании "от левого верхнего угла").

Т.к. количество контуров > 1, то это просто глиф. Для него под заголовком следует заголовок простого глифа:

а) массив последних точек каждого из 2 контуров, номер точки двухбайтовый:
2 байта 00 03 - третья точка (а контур состоит из 0,1,2 и 3).
2 байта 00 07 - седьмая точка (а контур состоит из 4,5,6 и 7).

По этому массиву можно сразу количество точек в символе - это номер последней точки последнего контура плюс 1. Он понадобится ниже при считывании флагов.

б) 2 байта 00 00 - 0, длина инструкций по отрисовке в байтах

в) инструкции в байтах, но т.к. длина = 0 - то инструкций нет

г)1 байт флагов для каждой точки. Если 8 точек в символе (от 0 до 7) - то это 8 байт. Внутри каждого байта 8 бит - т.е. 8 флажков.

Расположение бит:

7 - резерв (0)
6 - резерв (0)
5 - Y не изменился (или короткий Y-вектор положителен): также как и про Х ниже.
4 - X не изменился (или короткий X-вектор положителен):
если флаг про короткий X-вектор стоит, то этот флаг означает положительное относительное смещение по X (1) либо отрицательное (0)
если флаг про короткий X-вектор не стоит, то этот флаг означает неизменившуюся координату X (1) либо сообщает о том, что текущая X-координата это вектор относительного смещения со знаком (0)
3 - повторение флагов: если стоит (1) - то значит следующий байт флагов - это количество повторов данной конфигурации флагов. Поэтому последовательность флагов может быть и меньше 8 штук в данном случае. Например, один байт-флаг с выставленным 3 битом, а потом еще второй байт со значением 7 - т.е. 7 раз повторить описанную в первом флаге-байте конфигурацию.
2 - короткий Y-вектор: координата точки кодируется 1 байтом если (1) или 2 байтами если (0).
1 - короткий X-вектор: координата точки кодируется 1 байтом если (1) или 2 байтами если (0).
0 - точка находится на рисуемой кривой (1) или вне ее (0)

Сочетания 1 и 4 бита для X или 2 и 5 для Y означают:
00 - 2-байтовое знаковое смещение
01 - координата не изменилась
10 - 1-байтовое отрицательное смещение
11 - 1-байтовое положительное смещение

Из массива видно, что последний (т.е. 0 бит) установлен везде - все точки на кривой (еще бы, это же квадраты, и в углах точки у них).
Также видно, что 3 бит нигде не установлен, повторения флагов нет.

Для контура 1:
1 байт 35 - 00110101, длинный X-вектор, короткий Y-вектор, не изменяется Х, положительное смещение по Y
Выпишем биты (1 и 4) для X, (2 и 5) для Y.
X:01 - не изменяется
Y:11 - 1-байтовое положительное смещение
1 байт 33 - 00110011, короткий X-вектор, длинный Y-вектор, положительное смещение по X, не изменяется Y
X:11 - 1-байтовое положительное смещение
Y:01 - не изменяется
1 байт 11 - 00010001, длинный X-вектор, длинный Y-вектор, не изменяется Х, текущая координата Y точки это вектор смещения со знаком
X:01 - не изменяется
Y:00 - 2-байтовое знаковое смещение
1 байт 23 - 00100011, короткий X-вектор, длинный Y-вектор, отрицательное смещение по Х, не изменяется Y
X:10 - 1-байтовое отрицательное смещение
Y:01 - не изменяется

Для контура 2:
1 байт 11 - 00010001, длинный X-вектор, длинный Y-вектор, не изменяется Х, текущая координата Y точки это вектор смещения со знаком
1 байт 33 - 00110011, короткий X-вектор, длинный Y-вектор, положительное смещение по X, не изменяется Y
1 байт 35 - 00110101, длинный X-вектор, короткий Y-вектор, не изменяется Х, положительное смещение по Y
1 байт 23 - 00100011, короткий X-вектор, длинный Y-вектор, отрицательное смещение по Х, не изменяется Y

Далее массивы самих координат (когда X или Y не меняются - то элемент координаты в массиве просто отсуствует):
X: 4 байта 64 64 64 64 - четыре числа 100
Y: 8 байт AA 01 49 FE 0D 64

Получаем для контура 1:
Сначала X = 0; Y = 0;

Точка 1:
X = 0
Y = Y + 170 (1 байт: AA) = 170

Точка 2:
X = X + 100 = 100
Y = 170

Точка 3:
X = 100
Y = Y + 329 (2 байта: 01 49) = 170 + 329 = 499

Точка 4:
X = X - 100 = 0
Y = 499


Получаем для контура 2:
Сначала X = 0; Y = 499;

Точка 5:
X = 0
Y = Y - 499 (2 байта FE 0D) = 0

Точка 6:
X = X + 100 = 100
Y = 0

Точка 7:
X = 100
Y = Y + 100 (1 байт: 64) = 100

Точка 8:
X = X - 100 = 0
Y = 100

Получились координаты точек точно как на рисунке выше. Первый контур - длинная черта. Второй контур - квадратная точка.

Продолжение следует...

Ответить

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость