Java:用透明像素填充buffereimage



我有一个屏幕外的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值的添加有关吗?

使用clear composite清除背景后,需要将其设置为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);

您可以获得BufferedImage的底层int[]数组(确保使用兼容的格式:即由int[]支持的格式)。

然后用alpha值为0的int填充int[](0也可以;)

System.arraycopy非常快。

你必须知道直接在int[]中写入比使用setRGB快得多。

现在BufferedImage在Java中有点黑魔法:取决于你在做什么以及你在哪个平台/JVM上做它,你可能会失去硬件加速(可能从一开始就没有)。除此之外,你可能根本不关心硬件加速,因为你可能并不是在制作一款需要60+ FPS才能玩的游戏。

这是一个非常复杂的话题,有不止一种方法来给BufferedImage猫剥皮。就我而言,我直接在int[]中工作,当我在像素级别上搞砸了,因为我认为这比尝试使用更高级别的绘图原语更有意义,我做真的不关心硬件加速的潜在损失。

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

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

  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;
  }

尽管你说它不工作,我使用clearRect相当好。

用背景色填充指定矩形,从而清除指定矩形当前绘图表面的。该操作不使用当前绘制模式

从Java 1.1开始,屏幕外图像的背景颜色可能系统依赖。应用程序应该使用setColor和fillRect以确保将屏幕外图像清除到指定的颜色。


填充指定的矩形。的左右边缘矩形是x和x + width - 1。顶部和底部边缘是相等的Y和Y +高- 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)独立于颜色模型;无论图像是如何设置的,这都应该有效。

与复合解决方案相比,一个缺点是它只允许清除矩形;

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

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

(至少在绘制图像用于缩放时)

最新更新