Java: заполнение BufferedImage прозрачными пикселями - PullRequest
19 голосов
/ 15 апреля 2011

У меня есть закадровый BufferedImage, построенный с типом BufferedImage.TYPE_INT_ARGB.Он может содержать что угодно, и я ищу способ (довольно эффективно) полностью перезаписать изображение прозрачными пикселями, что приведет к появлению «невидимого» изображения.

Использование чего-то подобного:

    (bufimg.getGraphics()).setColor(new Color(10, 10, 100, 0));   
    (bufimg.getGraphics()).fillRect (0, 0, x, y);

Не имеет эффекта.Одним из возможных методов может быть просто написать каждый пиксель в BufferedImage, но я не уверен, что это лучшее решение.Как бы вы это сделали?

[edit]
В документации по графическим изображениям не рекомендуется использовать clearRect для изображений вне экрана, но я пробовал это с теми же результатами, что и выше.

[edit2]
После экспериментов с кодом MeBigFatGuy (спасибо!), он действительно очищает изображение.Но это также останавливает дальнейшее рисование к этому изображению (или кажется).Например, этот код:

    BufferedImage img = new BufferedImage (600, 600, BufferedImage.TYPE_INT_ARGB);
    Graphics g = img.createGraphics ()    
    g.drawLine (100, 100, 500, 500);
    AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
    g.setComposite(composite);
    g.setColor(new Color(0, 0, 0, 0));
    g.fillRect(0, 0, 600, 600);
    graphicsAI.setColor(new Color (10, 10, 10, 255));
    graphicsAI.drawLine (100, 100, 500, 500);

Ничего не видно на изображении (я рисую изображение в JPanel).Это как-то связано с добавлением альфа-значений?

Ответы [ 6 ]

24 голосов
/ 09 июня 2011

После очистки фона с помощью компоновки CLEAR вам необходимо установить его обратно в SRC_OVER, чтобы снова рисовать в обычном режиме.например:

//clear
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR));
g2.fillRect(0,0,256,256);

//reset composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
//draw
g2.setPaint(Color.RED);
g2.fillOval(50,50,100,100);
9 голосов
/ 15 апреля 2011

Вы можете получить базовый массив int[] вашего BufferedImage (убедитесь, что вы используете совместимый формат: то есть тот, который поддерживается int[]).

Затем заполните int[] с целочисленными значениями, для которых альфа-значение равно 0 (0 будет делать;)

A System.arraycopy будет очень быстрым.

Вы должны знать, что непосредственная запись вint[] на лот быстрее, чем при использовании setRGB .

Теперь BufferedImage немного чёрного искусства в Java: в зависимости от того, что вывыполняя и на какой платформе / JVM вы это делаете, вы можете потерять аппаратное ускорение (которого может в любом случае никогда не было).В дополнение к этому, вы все равно можете совершенно не заботиться об аппаратном ускорении, потому что, возможно, вы не работаете над, скажем, игрой, требующей 60+ FPS для игры и т. Д.

Это очень сложная тема, и существует более одного способа обнажить кошку BufferedImage.Насколько я понимаю, я работаю непосредственно в int[], когда мне нужно возиться на уровне пикселей, потому что я думаю, что это имеет гораздо больший смысл, чем попытка использовать высокоуровневые примитивы рисования, и я действительно не волнует потенциальная потеря аппаратного ускорения.

5 голосов
/ 15 апреля 2011

Если вы приведете объект Graphics к объекту Graphics2D, вы можете установить составной объект через

AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setComposite(composite);
g2d.setColor(new Color(0, 0, 0, 0));
g2d.fillRect(0, 0, 10, 10);
0 голосов
/ 04 июля 2015

Несмотря на то, что он хочет сделать пиксель переднего плана прозрачным, ваш ответ, безусловно, является правильным.

private Color transparent = new Color(0, true);

((Graphics2D) g).setBackground(transparent);

g.clearRect(0, 0, w, h);

устанавливает прозрачный фон.

Кстати: другие ответы в основном мусор или просто FUD.Пожалуйста, не принимайте ответы, которые говорят о «буферизованном изображении, являющемся черным искусством» на техническом форуме.

0 голосов
/ 23 февраля 2015

Установка фона графического объекта Объект, кажется, выполняет свою работу:

g.setBackground(new Color(0, 0, 0, 0));

(по крайней мере, при рисовании изображений для масштабирования)

0 голосов
/ 04 августа 2014

Несмотря на то, что вы говорите, что это не работает, я использовал clearRect довольно хорошо.

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

Начиная с Java 1.1, цвет фона закадровых изображений может быть системно зависимым. Приложения должны использовать setColor с последующим fillRect, чтобы гарантировать, что закадровое изображение очищается до определенного цвет.


Заполняет указанный прямоугольник. Левый и правый края прямоугольник в х и х + ширина - 1. Верхний и нижний края в y и y + высота - 1. Получающийся прямоугольник покрывает область ширины пикселей в высоту по высоте пикселей в высоту. Прямоугольник заполняется с помощью текущий цвет графического контекста.

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

Это чисто предположение, но я думаю, что примечание о закадровых изображениях относится к Graphics объектам, полученным из компонентов вне экрана AWT, поскольку они являются нативными. Я с трудом представляю, как цвет фона BufferedImage может зависеть от системы. Поскольку документ API предназначен для Graphics, это может быть обобщение, не применимое к делу BufferedImage.

Мой код тестирования:

JFrame jf = new JFrame();
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

BufferedImage img = new BufferedImage(200, 300, BufferedImage.TYPE_INT_ARGB);

Graphics2D g = img.createGraphics();

//fill right half with opaque white
g.setColor(Color.WHITE);
g.fillRect(100, 0, 100, 300);

//leave top third as it is

//fill middle third with transparent color
g.setColor(new Color(0, true));
g.fillRect(0, 100, 200, 100);

//clear bottom third with transparent color
g.setBackground(new Color(0, true));
g.clearRect(0, 200, 200, 100);

g.dispose();

jf.add(new JLabel(new ImageIcon(img)));

jf.pack();
jf.setVisible(true);

результат - два белых квадрата, справа вверху. Если белый цвет не был окрашен или clearRect использовался для перезаписи белого, в результате получается светло-серый цвет фона по умолчанию для рамки.

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

Плюс к решению с массивом: а) отсутствие дополнительной памяти и б) независимость от цветовой модели; это должно работать независимо от того, как было настроено изображение.

Минус по сравнению с составным решением состоит в том, что оно позволяет очищать только прямоугольники; настройка композита позволяет очистить любую форму.

...