Шрифты в условиях экстремальной экономии

    Очень долго мелкие растровые шрифты были бичем KolibriOS. Но относительно недавно к проекту присоединился еще один разработчик — Pathoswithin. Быстро сориентировавшись в проекте, он взялся за решение данной проблемы. Результаты его работы вы можете наблюдать в последних ночных сборках. Ну а данная статья является повествованием о работе над шрифтами, написанная самим Pathoswithin.


    Каждый символ шрифта называется «глиф». По сути, это обычное изображение. Много ли проблем с рисованием картинок? Как минимум, две. Прежде всего, шрифт должен масштабироваться, и если уменьшить его ещё можно, то из увеличения ничего хорошего не получится



    Таким образом, глифы должны изначально иметь высокое разрешение, а для достижения максимального качества, нужны несколько наборов разного размера. И ладно ещё, если в шрифте 256 символов. А если юникод? Такой шрифт займёт немало памяти даже по современным меркам.

    Растровое изображение хранит цвета каждой точки. Но зачем, если можно хранить описание того, как глиф нарисовать. К счастью, шрифты отлично вписываются в принципы векторной графики. В данном случае, достаточно указать координаты нескольких точек, между которыми нужно провести прямые; максимум — параметры для рисования кривой. Поскольку почти все точки рисуются «на лету», такие глифы не привязаны к конкретному разрешению, и занимают гораздо меньше памяти.



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

    Для решения этой проблемы используются особенности жк мониторов. Каждый пиксель экрана в горизонтальном направлении состоит из трёх субпикселей: красный, зелёный и синий. Сочетание разной яркости этих цветов образует все остальные. Кодируются они таким же способом, что позволяет легко управлять субпикселями по отдельности. Более того, если разница между их яркостью не слишком высока, цвета соседних пикселей могут сливаться. Этот принцип лежит в основе технологии сглаживания «ClearType»: глифы рисуются в трёхкратном горизонтальном разрешении, пиксели приравниваются к субпикселям и их яркость определяется с учётом 4 соседей. По сути, производится размытие цветов с диаметром в 5 субпикселей, классическое соотношение — 1/2/3/2/1.



    В MenuetOS использовался крохотный растровый шрифт с разрешением глифа 6х9. Каждый пиксель описывается одним битом, строка — байтом, 9 байт на каждый из 256 глифов, итого шрифт занимает 2 кб. Только выглядит он хорошо при разрешении экрана не более 800х600. В KolibriOS неоднократно пытались использовать векторные шрифты, но обе проблемы встали ребром.

    За исключением ядра, писать под KOS можно не только на ассемблере. Но для того, чтобы оставаться маленькой, быстрой и не превратиться в Linux, основной дистрибутив является образом дискеты на 1,4 Мб. Для одних это психологический барьер, для других — банальное ограждение. Векторные шрифты позволяют экономить размер по сравнению с огромными растровыми, но всё же занимают гораздо больше 2 кб. Будет обидно использовать шрифт размером больше ядра с драйверами и графикой.

    Также, в любой открытой ОС есть проблемы с драйверами для видеокарт. Nvidia и ATI — та ещё мафия, железки то продают, а вот как с ними общаться при отсутствии Windows не объясняют. К счастью, существует VESA BIOS Extensions, которое позволяет хотя бы устанавливать нормальное разрешение экрана, но писать в видеопамять полупрозрачные пиксели — нет. Значит нужно вручную считать оттуда пиксель, смешать цвета в нужном соотношении, и записать обратно. Частота общения с видеопамятью высокая, но от начала передачи до получения результата происходят большие задержки. Запись работает быстро, а вот при чтении нужно немало подождать, пока запрошенный пиксель будет доставлен. Например, создание скриншота в таком режиме требует больше секунды. Поскольку сглаживание основывается на смешивании пикселей фона с цветом глифа, то рисование векторных шрифтов на экране становится крайне медленным процессом. Без сглаживания они либо требуют дополнительные данные для хинтинга, либо выглядят хуже, чем растровые.



    В лучших традициях низкоуровневого программирования я задался вопросом «Как получить максимум при минимальных затратах?», и решил попробовать выжать больше из того, что есть. При простом увеличении, символы состоят из квадратов и прямых углов (хотя некоторым ценителям кубизма нравится такой стиль), но если дорисовать точки в правильных местах, то появятся углы в 45 или даже 30 градусов. Меня вдохновил алгоритм сглаживания изображений, опционально представленный в этой «пиксельной» игре. Впрочем, со шрифтами однопиксельной толщины существующие реализации справляются не очень.
    Например, результат работы hqx:



    В итоге, я создал свой алгоритм, предназначенный конкретно для мелких растровых шрифтов, и назвал его Anti Eye Bleeding, ибо ни больше, ни меньше.



    Проследить эволюцию алгоритма вы можете на нашем форуме.

    С использованием общих принципов, он производит кратное увеличение или сглаживание (на выбор обычное или субпиксельное с предрасcчитанным соотношением). В случае со сглаживанием, смешиванию подлежат лишь несколько отдельных пикселей, что позволяет достичь приемлимой производительности. Написан он на ассемблере и интегрирован в ядро KolibriOS, как базовое средство. Также, я добавил в ядро шрифт 8х16 на 1400 символов юникода, размером 22 кб (без сжатия), из-за чего оно разожралось аж до 188 кб (92 кб после сжатия).

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

    Основной проблемой остаётся масштабирование с дробным множителем. Я попытался написать библиотеку, в которой используется ClearType для уменьшения до нужного размера после кратного увеличения, но результат остаётся спорным. Впрочем, вы можете помочь его оценить:

    KolibriOS Project Team
    68.83
    Быстрая операционная система для бизнеса и хобби
    Share post

    Comments 3

      +1
      Молодец, что внедрил на системном уровне. У нас до этого дальше демок на уровне приложения не продвигалось, хотя многие занимались шрифтами.
        +1
        Ребят, это круто. Невероятно круто. Первая картинка отсюда: http://board.kolibrios.org/viewtopic.php?f=36&t=3084 вообще восхищает. Полное отсутствие мыла. Хоть глиф и необычный (например у буквы И), читать необычно комфортно.
          0
          В нашей группы вконтакте были заданы вопросы vk.com/kolibri_os?w=wall-48924138_3536 к статье, на которые автор дал ответ на форуме board.kolibrios.org/viewtopic.php?f=36&t=3084&p=62863#p62863

          «Векторные шрифты позволяют экономить размер… но всё же занимают гораздо больше 2 кб.»
          А если использовать сжатие?


          То из 2 кб получится меньше килобайта. Растровые шрифты ещё и сжимаются лучше чем векторные. Например, в юникодистом много пустых строк, так из 22 кб получается 5,5 кб.

          «Nvidia и ATI —… железки-то продают, а вот как с ними общаться при отсутствии Windows не объясняют.»
          А что не так с открытыми дровами AMD? Ещё и Intel наступает им на пятки.


          Для Intel у нас драйвера есть. Собственно и открытые AMD портированы, но там огромное количество кода и попробуй что-то понять; чтобы написать драйвер без особой боли, нужна документация. А вот Nvidia — редиска.

          «Без сглаживания они либо требуют дополнительные данные для хинтинга, либо выглядят хуже, чем растровые.»
          А что там с экранами высокой плотности? Понимаю, что они пока не у всех, но мода уже давно задана и на мобилах и на десктопах.


          Типа «Retina Display»? Да, видимо для этих целей они и создавались. Во всяком случае, другого смысла в них я не вижу.

          Only users with full accounts can post comments. Log in, please.