Растровый шрифт Java: разбиение 1-битного изображения разными цветами

Я бы хотел реализовать простой рисунок растрового шрифта в Java-приложении на основе AWT. Приложение рисует объект Graphics , где я хотел бы реализовать простой алгоритм:

1) Загрузите файл (возможно, используя ImageIO.read (new File (fileName)) ), который представляет собой 1-битный PNG, который выглядит примерно так:

8*8 bitmap font

Т.е. это 16 * 16 (или 16 * много, если я хочу поддерживать Unicode) матрица из 8 * 8 символов. Черный соответствует цвету фона, белый - переднему плану.

2) Нарисуйте строки посимвольно, дублируя соответствующие части этого растрового изображения для целевой Graphics . Пока у меня получалось только что-то вроде этого:

    int posX = ch % 16;
    int posY = ch / 16;

    int fontX = posX * CHAR_WIDTH;
    int fontY = posY * CHAR_HEIGHT;

    g.drawImage(
            font,
            dx, dy, dx + CHAR_WIDTH, dy + CHAR_HEIGHT,
            fontX, fontY, fontX + CHAR_WIDTH, fontY + CHAR_HEIGHT,
            null
    );

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

Итак, вопрос в следующем: есть ли в Java простой (и быстрый!) Способ преобразовать часть одного 1-битного растрового изображения в другое, раскрашивая его в процессе копирования (т.е. заменяя все 0 пикселей одним заданным цветом и все 1 пиксель с другим)?

Я изучил пару решений, все они кажутся мне неоптимальными:

  • Использование пользовательской раскраски BufferedImageOp , как описано в this решение - должно работать, но кажется, что было бы очень неэффективно перекрашивать растровое изображение перед каждой блит-операцией.
  • Использование нескольких 32-битных RGBA PNG, с альфа-каналом, установленным на 0 для черных пикселей и на максимум для переднего плана. Каждый желаемый цвет переднего плана должен иметь собственное предварительно обработанное растровое изображение. Таким образом, я могу сделать фон прозрачным и нарисовать его как прямоугольник отдельно перед копированием, а затем выбрать одно растровое изображение с моим шрифтом, предварительно раскрасив его желаемым цветом, и нарисовать его часть над этим прямоугольником. Мне кажется огромным излишеством - и что делает этот вариант еще хуже - он ограничивает количество цветов переднего плана относительно небольшим количеством (т.е. я могу реально загружать и хранить сотни или тысячи растровых изображений, а не миллионы)
  • Объединение и загрузка пользовательского шрифта, как описано в , это решение может работать, но, насколько я вижу в документации Font # createFont , шрифт AWT , похоже, работает только с векторными шрифтами, а не с растровыми.

Может быть, уже есть библиотеки, реализующие такую ​​функциональность? Или мне пора переключиться на какую-то более продвинутую графическую библиотеку, что-то вроде lwjgl ?

Результаты тестирования

Я протестировал пару алгоритмов в простом тесте: у меня есть 2 строки по 71 символ в каждой, и рисую их непрерывно одну за другой, прямо в одном и том же месте:

    for (int i = 0; i < N; i++) {
        cv.putString(5, 5, STR, Color.RED, Color.BLUE);
        cv.putString(5, 5, STR2, Color.RED, Color.BLUE);
    }

Затем я измеряю затраченное время и вычисляю скорость: строка в секунду и количество символов в секунду. До сих пор различные реализации, которые я тестировал, дали следующие результаты: растровый шрифт

  • , растровое изображение 16 * 16 символов: 10991 строк / сек, 780391 символов / сек
  • растровый шрифт, предварительно разделенные изображения: 11048 строк / сек. , 784443 символов / сек
  • g.drawString (): 8952 строк / сек, 635631 символов / сек
  • цветной растровый шрифт, раскрашенный с помощью LookupOp и ByteLookupTable: 404 строки / сек, 28741 символов / сек

6
задан Community 23 May 2017 в 12:01
поделиться