*
  Мысли   Галерея   Проекты   Тексты  
  Мысли   Галерея   Проекты   Тексты  
Giver: Веселые разукрашки  (2010-01-10 08:03:18)

Бочонок намоделили, a теперь нужно его раскрасить. Причем в это же время нужно оставить alpha-канал в покое, то есть закрасить остальное, поэтому метод через g2d.setColor(new Color(цвет, 127)); g2d.fillRect(); отпал сразу. Долго ковырял Composite, но никаких положительных результатов это не дало. Уже ближе к полуночи в голове начал вызревать хитрый план.

Исходная картника(1) у нас в градациях серого , и это замечательно. То есть все каналы равны, кроме альфы. Убрав ненужный канал мы получим бочку, залитую оставшимися. Например если убрать красный и синий канал, оставив лишь зеленый выйдет бочка нумер 2, если же наоборот закрыть только зеленый, то выйдет пурпурный (3), закрыв синий канал получим желтую бочку (4). Спрятав все каналы получим силует бочки (5), или ее маску, вещь тоже иногда полезную.

Смотрим как у явы с каналами, видим что очень печально. Люди либо используют страшный обход всех пикселей копии картинки накладывая битовую маску. Другой, более, но недостаточно красивый вариант, использовать ColorLookupOp, для этого нужны еще два 256-элементных массива типа short, и картинка, опять же, на выходе будет копия. Ее хотелось бы избежать.

В отчаянии просматривая дебаггером содержимое BufferedImage я наткнулся на достаточно интересную штуку — ColorModel. Именно она занималась преобразованием набора байт в конкретный цвет. Превосходно! Пишем обертку которая скрывает по желанию некоторые каналы.

public class ShadowColorModel extends ComponentColorModel {
    boolean red, green, blue;

    /**
     * Копируем параметры из родитеслькой цветовой модели и сохраняем парамтртры преобразования 
     */
    public ShadowColorModel(ColorModel parent, boolean red, boolean green, boolean blue) {
        super(parent.getColorSpace(), parent.hasAlpha(), parent.isAlphaPremultiplied(), 
              parent.getTransparency(), parent.getTransferType());
        this.red = red;
        this.green = green;
        this.blue = blue;
    }

    /**
     * Если красный цвет разрешен, возвращаем значение, иначе 0
     */
    public int getRed(Object inData) {
        return red ? super.getRed(inData) : 0;
    }

    /**
     * Таким же образом поступаем с остальными цветами
     */
    public int getGreen(Object inData) {
        return green ? super.getGreen(inData) : 0;
    }

    public int getBlue(Object inData) {
        return blue ? super.getBlue(inData) : 0;
    }
}

Что мы получаем в итоге? Желанный эффект достигнут, стоит создать объект класса BufferedImage с тем же растром, что и исходная картинка, на наложив ограничения на каналы. При этом копирования данных картинки не происходит, она хранится в памяти лишь один раз. Падения производительности нет. Все рады и довольны.


Имя:
Комментарий: