Субпиксельный рендеринг (вики)— способ увеличить видимое разрешение LCD или OLED дисплея путем рендеринга пикселей с учетом свойств экрана. Используется тот факт, что каждый пиксель экрана фактически состоит из отдельных красных, зеленых и синих субпикселей.


В посте я хочу рассказать о методе Haarmony LCD, который применяется в последних версиях freetype, и как его адаптировать для произвольных векторных изображений и конфигураций субпикселей.



Как выглядят исходные изображения


Фотографией, сложно передать преимущества. Для сравнения можете посмотреть на следующую картинку. Если одна из конфигураций пикселей такая же, как у вашего монитора, разница должна быть существенной.



Ко мне обратились создатели U•HODL с предложением адаптировать субпиксельный рендеринг для их устройства. Устройство — миниатюрный криптокошелек с 0.96" OLED экраном (120?180). У них в блоге (англ.) описано, как они внимательно относится к удобству, и как выжимают максимум из небольшого экрана. Поэтому им был необходим SPR для иконок и текста.


История вопроса (ClearType)


В интернете можно встретить описание механизма ClearType, который используют в Windows. Лучшее описание, на мой взгляд, на сайте grc.com. Дальше короткая выжимка для тех, кому неинтересно вдаваться в подробности. ClearType состоит из двух этапов:


1. Текст рендерится с шириной в три раза больше оригинальной


Каждый пиксель рендера отвечает за один цветной субпиксель:



Если просто вывести такой текст на экран, будет видна цветовая аберрация на краях букв:



2. Фильтр меняет цвет (но не яркость) соседних пикселей


И восстанавливает локальный цветовой баланс:



У этого метода несколько недостатков:


  1. Не очевидно, как его применять с цветными изображениями
  2. Фильтр усложняется, если субпиксели не на одной прямой (чуть ниже будет конфигурация экрана)
  3. Сам фильтр защищен патентом Майкрософт. Возможно кто-то помнит, что по-умолчанию в ранних версиях freetype субпиксельный рендеринг был отключен из-за патентов.

Haarmony LCD


И тут на помощь приходит алгоритм Haarmony LCD. Кроме письма его автора, в интернете практически нет информации про алгоритм. Но, сам алгоритм прост и интуитивен. Надо 3 раза отрендерить текст со смещением равному смещению субпикселя, и сложить цветовые каналы.


Допустим, если у вас есть матрица такой конфигурации:



Вам надо отрендерить и сложить:


  1. Синий канал со смещением -0.25 пикселя по горизонтали
  2. Зеленый канал со смещением +0.25 пикселя по горизонтали
  3. Красный канал со смещение +0.5 пикселя по вертикали

Схема рендера будет приблизительно такой.



SVG


Легче всего оказалось рендерить SVG изображения. Просто смещая viewBox (3 раза), заменив :


viewBox="0 0 120 180"

на


viewBox="0.25 0 120.25 180"

Пример рендера иконок:



Изображения:



Конфигурация матрицы


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



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


П.С. mcufont


Если вам необходимо использовать субпиксельный рендеринг в mcufont (библиотека для рендеринга шрифтов на микроконтроллерах), надо пропатчить encoder/freetype_import.cc и установить там Haarmony LCD режим FT_Render_Glyph(face->glyph, FT_RENDER_MODE_LCD). А на выводе текста не забывать, что ширина букв будет в 3 раза больше необходимой.

Комментарии (12)


  1. x893
    07.11.2019 16:40

    Что то не могу найти FT_Render_Glyph в github.com/mcufont/mcufont


    1. PatapSmile Автор
      07.11.2019 16:53

      Да, согласен. freetype_import.cc

      FT_Int32 loadmode = FT_LOAD_TARGET_NORMAL | FT_LOAD_RENDER;
      ....
      checkFT(FT_Load_Glyph(face, gindex, loadmode));
      

      Они одним вызовом и загружают и рендерят. А если рендерить отдельно, то
      FT_Int32 loadmode = FT_LOAD_TARGET_LCD;
      ....
      checkFT(FT_Load_Glyph(face, gindex, loadmode));
      FT_Render_Glyph(face->glyph, FT_RENDER_MODE_LCD);
      


      1. x893
        07.11.2019 16:56
        +1

        Спасибо! Попробую


  1. Aingis
    07.11.2019 16:46

    Смещение как алгоритм не очень. Видна фальшивость рендеринга. В настоящем ClearType
    так вообще есть специальные методы. Например, толщина линий должна быть кратна полуторам пикселям, чтобы не было излишней размытости. Хинтинг помогает горизонтальным линиям попадать в пиксели и т. п. Есть целый сайт, посвящённый вопросу: «The Raster Tragedy» с хорошим описанием и иллюстрациями.


    1. PatapSmile Автор
      07.11.2019 17:04

      С другой стороны, на сколько я помню, ClearType не умеет, если субпиксели не по горизонтали (допустим если просто перевернуть экран вертикально).


    1. JTG
      07.11.2019 17:44
      +1

      ClearType, к сожалению, весь обложен патентами, поэтому приходится делать «не настоящий ClearType».


      1. Aingis
        07.11.2019 17:47
        +2

        Срок их действия как раз истекает. По ссылке:
        2019-11-07 Application status is Expired — Lifetime


        1. JTG
          07.11.2019 18:06
          +2

          1. JTG
            07.11.2019 19:25

            А, там Google, похоже, для всех патентов указывает состояние на сегодняшний день, что несколько вводит в заблуждение. Тем не менее, срок действия патентов действительно уже истёк.


  1. AntonSazonov
    07.11.2019 21:12

    Где-то пару лет назад в исходниках или документации FreeType читал, что если изменить коэффициенты FIR-фильтра, то данная технология уже не попадёт под патент.
    Плюс ко всему, примерно в то же время где-то (возможно там же) читал, что сроки действия патента уже истекли.


    1. Krypt
      08.11.2019 05:20

      Видимо обход патента минорной модификацией распространен (или крайней мере вера в возможность):
      Попадалась реализация патента дизеринга, запатентованного Adobe — статья, где был описан алгоритм утверждала, что для обхода патента достаточно изменить размер матрицы дизеринга.


  1. Smbdy_kiev
    08.11.2019 14:46
    +1

    Оу. Тот случай, когда сначала прочитал здесь, а потом увидел на фейсбуке ссылку на статью. Да не такие уж и сложные слова ;)