Проблемы производительности с Java 2D при рисовании буферизованных изображений

Я разрабатываю объект Canvas, который использовался для рисования BufferedImage размером 228x262 пикселей.

Это изображение было нарисовано с использованием метода Graphics2D.drawImage(...). Я выполняю манипуляции с цветом на основе пикселей в заданных диапазонах смещения. Пример кода ниже:

for( int i = frameOffset; i < colorClock; i++ ) {  
    rgb[i] = new Color(this.colorBK).getRGB();  
    }

Где rbg установлен на то буферизованное изображение, в которое я вношу изменения.
Проблема в том, что код отрисовывается медленно.

Я создаю изображение с помощью GraphicsConfiguration.createCompatibleImage и использую двойную буферизацию с помощью Buffer Strategy.

Какие-нибудь огни, пожалуйста?

Спасибо за рекламу.


person Leonardo    schedule 17.02.2010    source источник
comment
Под рисованием вы имеете в виду после преобразования RGB? Или указанное выше преобразование происходит при каждом такте рендеринга?   -  person jevon    schedule 17.02.2010
comment
Привет, цикл рисования происходит после завершения обновления. Сначала я меняю цвета на заданных пикселях, а затем использую Graphics2D.drawImage с новыми цветами пикселей.   -  person Leonardo    schedule 17.02.2010
comment
Пробовали профилировать? Какую IDE вы используете? В NetBeans есть встроенный профилировщик, и я полагаю, что для Eclipse есть подключаемый модуль.   -  person Michael Myers    schedule 17.02.2010


Ответы (2)


Если вы запускаете цикл каждый раз, когда рисуете изображение, цикл может быть узким местом. Существует совершенно ненужное выделение объектов, из-за чего сборщик мусора будет запускаться довольно часто.

Я предполагаю, что colorBK имеет значение int. Если это так, вы просто создаете и инициализируете объект Color и просите его вернуть значение rgb, присвоенное массиву rgb. Что на самом деле происходит, так это то, что вы присваиваете значение colorBK в массиве rgb. Таким образом, эквивалентной и более эффективной реализацией будет rgb[i] = colorBK.

Чтобы оптимизировать это еще больше, вы можете присвоить значение colorBK последней локальной переменной. Это позволит избежать получения значения поля снова и снова. Таким образом, цикл может выглядеть так:

final int color = colorBK;
for( int i = frameOffset; i < colorClock; i++ ) {
    rgb[i] = color;
}

Чтобы получить еще больший прирост производительности, вы должны думать, что если есть совершенно другие способы сделать это. Поскольку приведенный выше пример просто меняет некоторые пиксели на определенный цвет, я мог бы предположить, что это можно сделать с изображением и парой fillRects.

Таким образом, вы должны заполнить прямоугольник за изображением желаемым цветом (в данном случае colorBK). Если изображение имеет прозрачные пиксели в этих областях, описанный выше цикл изменяется, они остаются неизменными на холсте, и получается тот же эффект. Это может быть более эффективным, поскольку графические методы лучше оптимизированы и не требуют интенсивного использования массива.

person Lauri    schedule 17.02.2010
comment
И, как указывали другие в этой теме, если цвет постоянный, это нужно делать только один раз, когда изображение загружается, а не при каждой рисовании. - person Lauri; 17.02.2010
comment
Привет Лаури. На самом деле, графические методы должны быть лучше, но я уже пробовал это с fillRects раньше, и это было намного медленнее. Но поскольку код сейчас так же сильно отличается от того времени, я сделал fillRects вместо рисования BufferedImage, но производительность осталась неизменной. Тем не менее, я не пробовал трюк с fillRect, и я проверю его. Спасибо. Наверное, мне придется переосмыслить всю систему рисования. - person Leonardo; 17.02.2010

Не создавайте новый цвет только для того, чтобы извлечь целое число RGB для каждого пикселя изображения. Единственный конструктор с одним параметром, который я могу найти для Color, - это тот, который принимает int RGB - не можете ли вы просто использовать colorBK напрямую?

Кроме того, если вы выполняете это преобразование для каждой краски, это будет медленным; вам нужно сделать преобразование только один раз.

person Lawrence Dol    schedule 17.02.2010
comment
Привет Манки, спасибо за ответ. На самом деле, я должен изменить цвет определенных пикселей после выполнения фрагмента кода. Конструктор цвета, который я использую для преобразования, на самом деле тот, который принимает int RGB, но я внес некоторые изменения и теперь могу использовать напрямую. Пока getRGB() под капотом делает некоторые сдвиги в битах цветовых компонентов, она возвращает значение, отличное от того, которое я передаю конструктору. Но после незначительных изменений кода я теперь могу сделать это прямо. Спасибо. Но все равно никакого прироста производительности. - person Leonardo; 17.02.2010
comment
@Leonardo: Единственное изменение, внесенное этим конструктором, — сделать альфа-значение полностью непрозрачным: value = 0xff000000 | rgb;. Это то, что вы могли бы легко сделать, не создавая временный объект. - person Lawrence Dol; 18.02.2010
comment
Легкий человек, ты прав. Как я уже сказал: Но после небольших изменений кода я теперь могу сделать это прямо. Я имел в виду, что мне удалось сделать это без какого-либо временного объекта. Извините за отсутствие у меня способностей к самовыражению. После этого я хочу сказать, что даже без временных параметров у меня все еще возникают проблемы с производительностью. Это небольшое BufferedImage размером 262x228, но мне требуется достаточно времени, чтобы увидеть, как линии были раздавлены во время рисования. Спасибо за ответы. - person Leonardo; 18.02.2010