繁体   English   中英

Java:用透明像素填充 BufferedImage

[英]Java: Filling a BufferedImage with transparent pixels

我有一个屏幕外的 BufferedImage,用BufferedImage.TYPE_INT_ARGB类型构造。 它可以包含任何东西,我正在寻找一种方法来(相当有效地)用透明像素完全覆盖图像,从而产生一个“不可见”的图像。

使用这样的东西:

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

没有效果。 一种可能的方法可能只是覆盖 BufferedImage 中的每个像素,但我不确定这是最好的解决方案。 你会怎么做?

[编辑]
图形文档建议不要对离屏图像使用 clearRect,但我已经尝试过,结果与上述相同。

[编辑2]
在尝试了 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 合成清除背景后,您需要将其设置回 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[] (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);

尽管你说它不起作用,但我很好地使用了clearRect

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

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


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

它没有明确指出这里是一个将设置矩形的背景色,而其他将与当前颜色的顶部前景色,但它是什么,似乎做的。

这纯粹是猜测,但我认为关于屏幕外图像的说明与从屏幕外 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) 独立于颜色模型; 无论图像如何设置,这都应该有效。

与 Composite 解决方案相比的一个缺点是它只允许清除矩形; 设置复合允许您清除任何类型的形状。

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

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

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

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

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

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

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

将背景设置为透明。

顺便说一句:其他答案大多是垃圾,或者只是FUD。 请不要在技术论坛中接受有关“缓冲图像是妖术”的答案。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM