it-swarm.com.ru

Java: заполнение BufferedImage прозрачными пикселями

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

Используя что-то вроде этого:

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

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

[Правка]
Графическая документация не рекомендует использовать 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). Это как-то связано с добавлением альфа-значений?

19
JBenson

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

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

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

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

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

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

9
SyntaxT3rr0r

После того, как вы очистите фон с помощью компоновки 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);
24
Josh Marinacci

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

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);
5
MeBigFatGuy

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

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

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

0
Brad Mace

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

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

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


Заполняет указанный прямоугольник. Левый и правый края прямоугольник в x и x + width - 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 может быть быстрее, я не знаю, но, по крайней мере, это, скорее всего, аппаратное ускорение, как и любая другая операция рисования.

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

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

0
Silly Freak

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

приватный цвет прозрачный = новый цвет (0, правда);

((Graphics2D) г) .setBackground (прозрачный);

g.clearRect (0, 0, ш, ч);

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

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

0
user1135940