Java:使用透明像素填充BufferedImage

时间:2011-04-15 05:26:15

标签: java image transparency 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)。这是否与添加alpha值有关?

7 个答案:

答案 0 :(得分:24)

使用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);

答案 1 :(得分:9)

您可以获取int[]的基础BufferedImage数组(请确保使用兼容的格式:即由int[]支持的格式。)

然后使用其alpha值为0(0将执行;)

的整数填充int[]

System.arraycopy 非常快

您必须知道直接在int[]中写字比使用 setRGB 更快批次

现在BufferedImage在Java中是一种黑色艺术:取决于你正在做什么以及你正在做什么平台/ JVM,你可能失去硬件加速(无论如何,可能从未出现在那里)。除此之外,你可能完全不关心硬件加速,因为你可能没有工作,比如说需要60+ FPS才能玩的游戏等。

这是一个非常复杂的主题,并且有多种方法可以对BufferedImage猫进行换肤。就我而言我直接在int[]工作,因为我觉得它比使用更高级别的绘图原语更有意义而且我做真的不关心硬件加速的潜在损失。

答案 2 :(得分:5)

如果将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);

答案 3 :(得分:0)

尽管你说它不起作用,但我使用clearRect非常好。

  

通过填充背景颜色来清除指定的矩形   当前绘图表面。此操作不使用   目前的油漆模式。

     

从Java 1.1开始,屏幕外图像的背景颜色可能会出现   取决于系统。应用程序应使用setColor后跟   fillRect确保将屏幕外图像清除为特定图像   颜色。


  

填充指定的矩形。左边和右边   矩形位于x和x +宽度 - 1.顶部和底部边缘位于   y和y + height - 1.生成的矩形覆盖区域宽度   像素宽高高像素高。矩形填充使用   图形上下文的当前颜色。

这里没有明确说明,将矩形设置为背景颜色,而另一个将绘制,其中前景色位于当前颜色之上,但它似乎做了什么。

这是纯粹的推测,但我认为关于屏幕外图像的说明与从屏幕外AWT组件获得的Graphics对象有关,因为它们是原生的。我很难想象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可能会更快,我不知道,但至少这可能是硬件加速,就像任何其他绘图操作一样。

相对于阵列解决方案的加分是a)没有额外的记忆和b)独立于颜色模型;无论图像如何设置,这都应该有效。

与复合解决方案相比,减号是它只允许清除矩形;设置复合材料可以清除任何形状。

答案 4 :(得分:0)

设置图形对象的背景似乎可以完成工作:

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

(至少在为缩放目的绘制图像时)

答案 5 :(得分:0)

尽管他想将前景像素设置为透明,但你的答案肯定是正确的答案。

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

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

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

将背景设置为透明。

BTW:其他答案主要是垃圾或简单的FUD。请不要接受在科技论坛中谈论“缓冲图像是黑色艺术”的答案。

答案 6 :(得分:0)

为了完整起见,这是一个跨平台兼容的工作,测试和快速功能。

  static public BufferedImage createTransparentBufferedImage(int width, int height) {
     // BufferedImage is actually already transparent on my system, but that isn't
     // guaranteed across platforms.
     BufferedImage bufferedImage = new BufferedImage(width, height, 
                        BufferedImage.TYPE_INT_ARGB);
     Graphics2D graphics = bufferedImage.createGraphics();

     // To be sure, we use clearRect, which will (unlike fillRect) totally replace
     // the current pixels with the desired color, even if it's fully transparent.
     graphics.setBackground(new Color(0, true));
     graphics.clearRect(0, 0, width, height);
     graphics.dispose();

     return bufferedImage;
  }