Из журнала Funeral #1, Барнаул, 03.1999



(c) Eraser/Delirium Tremens'1999
 
------------------------------------------
 
Формат *.chr - векторных шрифтов.
 

    Как-то     пришлось     мне    сделать
качественную  надпись на Спекки... И круто
обломался...  Вспомнил  я такую прогу, как
Picasso под iS-Dos, где было 2-3 набора со
шрифтами,   но   все   меня  обламывало  у
кого-нибудь  его  взять.  Нашарив на диске
*.chr  -  шрифт и надыбав доку у Chronos'a
(в книжке по Пасквелю Фаронова), я за день
написал  печаталку  - радости моей не было
предела!   Это  ведь  круто:  увеличиваешь
шрифт,  а он почти не теряет качество, при
этом   сам  шрифт  занимает  от  4  до  18
килобайт.
    Существуют,  конечно, и другие форматы
векторных  шрифтов  (*.ttf, к примеру), но
выбар пал именно на *.chr, и вот почему:
 
1) У   меня  было  полное  описание  этого
формата,   с   которым   я  с  вами  готов
поделиться;
2) Он очень маленький по об'ему и работает
на  увеличение,  в  отличии от *.ttf (если
уменьшать *.ttf, то он выглядит хуже);
3) Простота реализации *.chr;
4) У  меня  на дисках как раз нашелся этот
формат.
   Для  создания  своих  фонтов,  придется
пока (я надеюсь) юзать редактор на пЦ.
 
           Описание формата *.chr
 
    Такие  шрифты  широко  используются  в
различных   программных   продуктах  фирмы
Borland,  в  том  числе  -  в компиляторах
Турбо   Паскаль,  Турбо  С,  Borland  C++.
Существуют  профессиональный пакет Borland
BGI  Toolkit,  в  состав  которого включен
редактор FE.EXE (хотя я его и не видел:()
    Любой  CHR  -  файл  состоит  из  пяти
частей:   заголовка,   блока   параметров,
таблицы  смещений,  таблицы  ширин,  блока
векторных команд. Структура файла показана
в таблице:
 
                      СТРУКТУРА CHR - ФАЙЛА
+--------------+-------+---------+-----------------------------+
| НАЗВАНИЕ     | РАЗМЕР| СМЕЩЕНИЕ|         СОДЕРЖИМОЕ          |
|   ПОЛЯ       |  ПОЛЯ |         |                             |
+--------------+-------+---------+-----------------------------+
|FontFileID    |   4   |    0    |         "РК",#08,#08        |
+--------------+-------+---------+-----------------------------+
|Copyright     | 0..253|    2    |        Любое (кроме #1A)    |
+--------------+-------+---------+-----------------------------+
|CopyrightEnd  |   1   |    ?    |              #1А            |
+--------------+-------+---------+-----------------------------+
|HeaderOffset  |   2   | CopEnd+1|          HeaderSize         |
+--------------+-------+---------+-----------------------------+
|FontName      |   4   | CopEnd+3|        Название шрифта      |
+--------------+-------+---------+-----------------------------+
|FontSize      |   2   | CopEnd+7|    Длина загружаемой части  |
+--------------+-------+---------+-----------------------------+
|FontVersion   |   3   | CopEnd+9|              1              |
+--------------+-------+---------+-----------------------------+
|ParPrefix(Pfx)|   1   | ?(128)  |             "+"             |
+--------------+-------+---------+-----------------------------+
|CharsCount(Ch)|   2   | Pfx+1   | Количество символов в шрифте|
+--------------+-------+---------+-----------------------------+
|Reserv1       |   1   | Pfx+3   |        Не используется      |
+--------------+-------+---------+-----------------------------+
|FirstChar     |   1   | Pfx+4   |      Код первого символа    |
+--------------+-------+---------+-----------------------------+
|DataOffset    |   2   | Pfx+5   |      FontStart-ParPrefix    |
+--------------+-------+---------+-----------------------------+
|FillFlag      |   1   | Pfx+7   |        Флаг заполнения      |
+--------------+-------+---------+-----------------------------+
|UpperMargin   |   1   | Pfx+8   |    Верхняя граница символа  |
+--------------+-------+---------+-----------------------------+
|Reserv2       |   1   | Pfx+9   |         Не используется     |
+--------------+-------+---------+-----------------------------+
|LowerMargin   |   1   | Pfx+10  |     Нижняя граница символа  |
+--------------+-------+---------+-----------------------------+
|Reserv3       |   5   | Pfx+11  |        Не используется      |
+--------------+-------+---------+-----------------------------+
|Offsets       | 2*[Ch]| Pfx+16  |       Таблица смещений      |
+--------------+-------+---------+-----------------------------+
|Widths        | [Ch]  | Pfx+16+ |         Таблица ширин       |
|              |       |  2*[Ch] |                             |
+--------------+-------+---------+-----------------------------+
|FirstData     |   ?   | Pfx+16+ |        Образы символов      |
|              |       |  3*[Ch] |                             |
+--------------+-------+---------+-----------------------------+
|FontEnd       |                                               |
+--------------+-----------------------------------------------+
 
    Поле  FontFileID  открывает CHR-файл и
всегда   содержит   символы  "PK",#08,#08,
которые     служат     для     определения
корректности  файла.  Символы  "PK"  - это
инициалы  Филиппа  Кана  (Philip  Khan)  -
основателя   фирмы  Borland.  Символы  #08
("Забой")  стирают эти инициалы при выводе
содержимого   дайла   на   экран  командой
TPascal  Type.  Длина Copyright в принципе
может  быть  произвольной,  т.к. он всегда
заканчивается      полем     CopyrightEnd,
содержащим символ 26(#1A) - конец файла.
 
    Сразу  за  полем  CopyrightEnd следует
двухбайтное  поле  HeaderSize,  содержащее
длину заголовка в байтах плюс 1.
    Поле         FontName         содержит
четырехбуквенное название шрифта.
    Двухбайтное   поле  FileSize  содержит
длину   CHR   -  файла  за  вычетом  длины
заголовка.
    Трехбайтное  поле FontVersion содержит
по всей видиомсти номер версии шрифта.
    Остальная  часть  заголовка  не  имеет
значения и может быть произвольной.
    Поле  ParPrefix  отстоит на HeaderSize
байт  от  начала файла. Оно открывает блок
параметров шрифта и всегда содержит "+". В
поле    CharsCount    указывается    общее
количество  символов,  начертания  которых
определены  в CHR - файле, а в FirstChar -
код    первого    определенного   символа.
Совокупность  полей CharsCount и FirstChar
задают диапазон кодов символов.
    Поле  DataOffset содержит расстояние в
байтах   от   поля   ParPrefix   до   поля
FirstData.  Его  значение  определяется по
формуле
 
       DataOffset=16+3*CharsCount
 
в  которой  слагаемое  16  учитывает длину
блока  параметров,  а 3*CharsCount - длину
двух  таблиц,  следующих  сразу  за блоком
параметров.
    Поле  FillFlag содержит так называемый
флаг  заливки  символов. Поскольку контуры
многих  символов  не  замкнуты,  этот флаг
почти всегда сброшен.
    Поле        UpperMargin       содержит
максимальное,  а LowerMargin - минимальное
значение  локальных  координат  для оси Y.
Локальные      вертикальные     координаты
векторных  команд  могут  иметь значения в
диапазоне  от  -64  до +63. Таким образом,
эти     поля    определяют    максимальный
вертикальный  размер  любого символа: поле
UpperMargin задает высоты от базавой линии
до  верхнего  края самого высокого символа
шрифта, а поле LowerMargin обычно содержит
отрицательное значение типа, показывающее,
насколько   ниже   базовой   линии   может
располагаться нижний край любого символа.
    Остальные  поля  блока  параметров  не
используются и содержат нули.
    Сразу  за блоком параметров начинается
таблица   смещений  Offsets.  Эта  таблица
содержит  CharsCount двухбайтных слов - по
одному  слову  на  каждый  символ.  В  ней
указывается,  на  каком расстоянии от поля
FirstData   содержится   начало  векторных
команд   каждого   символа.  Самый  первый
элемент таблицы всегда содержит ноль.
    Поле  Widths  длиной  CharsCount  байт
содержит    таблицу   ширин,   в   которой
указывается   ширина   (длина  по  оси  X)
каждого   символа.  Обычно  каждый  символ
выравнивается влево относительно локальных
координат,  поэтому  его  ширина в таблице
должна     задавать     также    небольшое
междусимвольное расстояние справа от него,
чтобы символы не сливались друг с другом.
    Поле   FirstData   определяет   начало
векторных    команд,    используемых   для
вычерчивание   первого   символа.   Каждая
векторная     команда     занимает    одно
двухбайтное  слово  и  содержит  локальные
координаты и собственно команду:
 
                        ВЕКТОРНЫЕ КОМАНДЫ
+-+-+----------------------------------------------------------+
|A|B|                        Kоманда                           |
+-+-+----------------------------------------------------------+
|0|0| Конец образа символа                                     |
+-+-+----------------------------------------------------------+
|1|0| Не используется (хотя можно заюзать для заливки?)        |
+-+-+----------------------------------------------------------+
|0|1| Поднять "перо" и перевести его в т.X,Y                   |
+-+-+----------------------------------------------------------+
|1|1| Опустить "перо" и вести его до точки X,Y                 |
+-+-+----------------------------------------------------------+
 
Увеличенный в 5 раз векторный шрифт (lcom)
с помощью программы ChrPrint:
   Как     правило,     последовательность
векторов   начинается   командой   01,  по
которой  воображаемое  "перо"  в  поднятом
состоянии   переводится  к  началу  самого
первого       вычерчиваемого      вектора.
Заканчивается  последовательность командой
00,   в   которой   координаты   X   и   Y
игнорируются, поэтому обычно это - команда
#0000.  Непосредственно  перед  ней  часто
указывается   команда  Widths[N]+#80,  что
означает      установку      "пера"     на
горизонтальной  оси  на  расстоянии ширины
символа от начала координат.
 
                       СТРУКТУРА КОМАНДЫ
               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
               |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
               |B Координата Y |A Координата X |
               +-------------------------------+
 
   Координата    X    определяет   обычную
декартовую координаты оси абсцисс и всегда
имеет   значение   в  диапазоне  от  0  до
Widths[N]  (Widths[N]  -  ширина символа в
таблице   ширин).   Координата   Y   может
задавать    как   положительные,   так   и
отрицательные  значения,  поскольку нижняя
кромка  символа  (поле  LowerMardin) может
располагаться    ниже    координаты    Y=0
("хвостики"  у букв p,q,g и т.п.). Поэтому
при  определении координаты Y используется
следующее    соглашение:    если    Y<=63,
координата   используется   так,  как  она
задана  в  команде, в противном случае она
определяется разницей Y-128.
 
 Ну,  с форматом разобрались - все элемен-
тарно!   Приемущества данного шрифта нали-
цо:  минимальная  потеря  качества  шрифта
при  его  увеличении; малый размер; легко-
сть  создания  оригинальных  надписей (его
можно  "пустить"  по определенной таректо-
рии); короче, вектор он и в Африке вектор.