Java:用透明像素填充 BufferedImage

发布于 2024-11-01 03:03:29 字数 1025 浏览 1 评论 0原文

我有一个离屏 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 值有关吗?

I have an off-screen BufferedImage, constructed with the type BufferedImage.TYPE_INT_ARGB. It can contain anything, and I'm looking for a way to (fairly efficiently) completely overwrite the image with transparent pixels, resulting in an 'invisible' image.

Using something like this:

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

Has no effect. One possible method might be just to write over every pixel in the BufferedImage, but I'm not sure this is the best solution. How would you do it?

[edit]
The Graphics documentation advises against using clearRect for off-screen images, but I have tried it with the same results as above.

[edit2]
After experimenting with MeBigFatGuy's code (thanks!), it does clear an image. But it also stops further painting to that image (or appears to). This code for example:

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

Results in nothing seen on the image (I'm drawing the image to a JPanel). Is this something to do with the addition of alpha values?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

满地尘埃落定 2024-11-08 03:03:29

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

After you clear the background with the CLEAR composite, you need to set it back to SRC_OVER to draw normally again. ex:

//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);
娇柔作态 2024-11-08 03:03:29

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

然后用 alpha 值为 0 的整数填充 int[](0 即可;)

System.arraycopy非常快。

你要知道,直接写入int[]比使用setRGB很多

现在,BufferedImage 在 Java 中有点像魔法:根据您正在执行的操作以及执行该操作的平台/JVM,您可能会失去硬件加速功能(无论如何,可能从来就不存在)。除此之外,您可能根本不关心硬件加速,因为您可能不会开发需要 60+ FPS 才能玩的游戏等。

这是一个非常复杂的问题主题,并且有不止一种方法可以为 BufferedImage 猫换肤。就我而言,当我必须在像素级别搞乱时,我直接在 int[] 中工作,因为我认为这比尝试使用更高级别的绘图基元更有意义而且我确实真的不关心硬件加速的潜在损失。

You could get the underlying int[] array of your BufferedImage (make sure to use a compatible format: that is, one that is backed by an int[]).

Then fill the int[] with ints whose alpha value are 0 (0 will do ; )

A System.arraycopy will be very fast.

You have to know that directly writing in the int[] is a lot faster than using setRGB.

Now BufferedImage are a bit of a black art in Java: depending on what you're doing and on which platform/JVM you're doing it, you may lose hardware acceleration (which may never have been there in the first place anyway). In addition to that, you may very well not care at all about hardware acceleration anyway because you may not be working on, say, a game requiring 60+ FPS to be playable etc.

This is a very complicated topic and there's more than one way to skin the BufferedImage cat. As far as I'm concerned I work directly in the int[] when I've got to mess at the pixel level because I think it makes much more sense than trying to use higher-level drawing primitives and I do really don't care about the potential lost of hardware acceleration.

不忘初心 2024-11-08 03:03:29

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

If you cast the Graphics object to a Graphics2D object, you can set a Composite object thru

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);
神爱温柔 2024-11-08 03:03:29

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

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

For the sake of completeness, here is a working, testing, and fast function that is cross-platform compliant.

  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;
  }
不打扰别人 2024-11-08 03:03:29

尽管你说它不起作用,但我使用 clearRect 效果很好。

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

从 Java 1.1 开始,屏幕外图像的背景颜色可能会改变
依赖于系统。应用程序应使用 setColor 后跟
fillRect 确保屏幕外图像被清除到特定的位置
颜色。


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

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

Despite you saying it doesn't work, I used clearRect quite fine.

Clears the specified rectangle by filling it with the background color
of the current drawing surface. This operation does not use the
current paint mode.

Beginning with Java 1.1, the background color of offscreen images may
be system dependent. Applications should use setColor followed by
fillRect to ensure that an offscreen image is cleared to a specific
color.


Fills the specified rectangle. The left and right edges of the
rectangle are at x and x + width - 1. The top and bottom edges are at
y and y + height - 1. The resulting rectangle covers an area width
pixels wide by height pixels tall. The rectangle is filled using the
graphics context's current color.

It is not clearly stated here that one will set the rectangle to the background color, while the other will paint with the foreground color on top of the current colors, but it's what it seems to do.

This is pure speculation, but I think the note about offscreen images relates to Graphics objects obtained from offscreen AWT components, as they are native. I can hardly imagine how the background color of a BufferedImage could be system dependent. As the API doc is for Graphics, this could be a generalization not applying to the BufferedImage case.

My testing code:

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

the result is two white squares, top right. Where no white was painted, or clearRect was used to overwrite the white, the result is a light gray, the frame's default background color.

Performance-wise, it's regular drawing. arraycopy might well be faster, I don't know, but at least this is likely hardware accelerated just as any other drawing operation.

A plus point versus the array solution is a) no additional memory and b) independence from the color model; this should work no matter how the image was set up.

A minus point versus the Composite solution is that it only allows clearing rectangles; setting the composite allows you to clear any kind of shape.

找回味觉 2024-11-08 03:03:29

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

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

至少在出于缩放目的绘制图像时)

Setting the background of the graphics Object seems to do the job:

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

(at least when drawing images for scaling purposes)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文