简体   繁体   English

Java:用透明像素填充 BufferedImage

[英]Java: Filling a BufferedImage with transparent pixels

I have an off-screen BufferedImage, constructed with the type BufferedImage.TYPE_INT_ARGB .我有一个屏幕外的 BufferedImage,用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.一种可能的方法可能只是覆盖 BufferedImage 中的每个像素,但我不确定这是最好的解决方案。 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.图形文档建议不要对离屏图像使用 clearRect,但我已经尝试过,结果与上述相同。

[edit2] [编辑2]
After experimenting with MeBigFatGuy's code (thanks!), it does clear an image.在尝试了 MeBigFatGuy 的代码后(谢谢!),它确实清除了图像。 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).结果在图像上看不到任何东西(我正在将图像绘制到 JPanel)。 Is this something to do with the addition of alpha values?这与添加 alpha 值有关吗?

After you clear the background with the CLEAR composite, you need to set it back to SRC_OVER to draw normally again.用 CLEAR 合成清除背景后,您需要将其设置回 SRC_OVER 才能再次正常绘制。 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);

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[] ).您可以获得BufferedImage的底层int[]数组(确保使用兼容的格式:即由int[]支持的格式)。

Then fill the int[] with ints whose alpha value are 0 (0 will do ; )然后用 alpha 值为 0 的整数填充int[] (0 可以;)

A System.arraycopy will be very fast. System.arraycopy非常快。

You have to know that directly writing in the int[] is a lot faster than using setRGB .你要知道,在直接写入int[]很多比使用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).现在BufferedImage有点像 Java 中的黑色艺术:根据你在做什么以及你在哪个平台/JVM 上做,你可能会失去硬件加速(无论如何可能从来没有出现过)。 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.除此之外,您可能根本不关心硬件加速,因为您可能没有在工作,例如,需要 60+ FPS 才能玩的游戏等。

This is a very complicated topic and there's more than one way to skin the BufferedImage cat.这是一个非常复杂的主题,有不止一种方法可以为BufferedImage猫设置皮肤。 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.就我而言,当我不得不在像素级别搞砸时,我直接在int[]工作,因为我认为这比尝试使用更高级别的绘图基元更有意义,而且我确实不这样做关心硬件加速的潜在损失。

If you cast the Graphics object to a Graphics2D object, you can set a Composite object thru如果将 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);

Despite you saying it doesn't work, I used clearRect quite fine.尽管你说它不起作用,但我很好地使用了clearRect

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.从 Java 1.1 开始,屏幕外图像的背景颜色可能取决于系统。 Applications should use setColor followed by fillRect to ensure that an offscreen image is cleared to a specific color.应用程序应使用 setColor 后跟 fillRect 以确保将屏幕外图像清除为特定颜色。


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.矩形的左右边缘位于 x 和 x + 宽度 - 1。顶部和底部边缘位于 y 和 y + 高度 - 1。生成的矩形覆盖区域宽度像素宽 x 高度像素高。 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.这纯粹是猜测,但我认为关于屏幕外图像的说明与从屏幕外 AWT 组件获得的Graphics对象有关,因为它们是原生的。 I can hardly imagine how the background color of a BufferedImage could be system dependent.我很难想象BufferedImage的背景颜色是如何依赖于系统的。 As the API doc is for Graphics , this could be a generalization not applying to the BufferedImage case.由于 API 文档适用于Graphics ,这可能是不适用于BufferedImage情况的概括。

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.如果没有绘制白色,或者使用clearRect覆盖白色,结果是浅灰色,即框架的默认背景色。

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.我不知道arraycopy可能会更快,但至少这可能是硬件加速,就像任何其他绘图操作一样。

A plus point versus the array solution is a) no additional memory and b) independence from the color model;与阵列解决方案相比的一个优点是 a) 没有额外的内存和 b) 独立于颜色模型; 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;与 Composite 解决方案相比的一个缺点是它只允许清除矩形; setting the composite allows you to clear any kind of shape.设置复合允许您清除任何类型的形状。

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) (至少在为缩放目的绘制图像时)

Despite that he wants to set the foreground pixel to transparent, your answer is definitively the correct answer. 尽管他想将前景像素设置为透明,但您的答案肯定是正确的答案。

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

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

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

sets the background to transparent. 将背景设置为透明。

BTW: The other answers are mostly rubbish or simply FUD. 顺便说一句:其他答案大多是垃圾,或者只是FUD。 Please don't accept answers which talk about "buffered image being black art" in a tech forum. 请不要在技术论坛中接受有关“缓冲图像是妖术”的答案。

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

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

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