0

I have a situation where I need to invert the alpha channel of a VolatileImage

My current implementation is the obvious, but very slow;

public BufferedImage invertImage(VolatileImage v) {
    BufferedImage b = new BufferedImage(v.getWidth(), v.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
    Graphics g = b.getGraphics();
    g.drawImage(v, 0, 0, null);
    for(int i = 0; i < b.getWidth(); i++) {
        for(int(j = 0; j < b.getHeight(); j++) {
            Color c = new Color(b.getRGB(i, j, true));
            c = new Color(c.getRed(), c.getGreen(), c.getBlue(), 255 - c.getAlpha());
            b.setRGB(i, j, c.getRGB());
        }
    }
    return b;
}

This works fine, but is painfully slow. I have large images and need this to be fast. I have messed around with the AlphaComposite but to no avail - this is not really a composting problem as far as I understand.

Given that 255 - x is equivalent to x & 0xff for 0 <= x < 256, can I not do an en-masse XOR over the alpha channel somehow?

lynks
  • 5,599
  • 6
  • 23
  • 42

2 Answers2

2

After a lot of googleing, I came across DataBuffer classes being used as maps into BufferedImages:

DataBufferByte buf = (DataBufferByte)b.getRaster().getDataBuffer();
byte[] values = buf.getData();
for(int i = 0; i < values.length; i += 4) values[i] = (byte)(values[i] ^ 0xff);

This inverts the values of the BufferedImage (you do not need to draw it back over, altering the array values alters the buffered image itself).

My tests show this method is about 20 times faster than jazzbassrob's improvement, which was about 1.5 times faster than my original method.

lynks
  • 5,599
  • 6
  • 23
  • 42
1

You should be able to speed it up by avoiding all the getters and the constructor inside the loop:

for(int i = 0; i < b.getWidth(); i++) {
    for(int(j = 0; j < b.getHeight(); j++) {
        b.setRGB(b.getRGB(i, j) ^ 0xFF000000);
    }
}
devrobf
  • 6,973
  • 2
  • 32
  • 46
  • I replaced the loop contents with `b.setRGB(i, j, b.getRGB(i, j) ^ 0xff000000);` but it is still very slow. Is is not possible to apply this XOR to an array of RGB values? or even the whole image at once? – lynks May 31 '13 at 13:08
  • @lynks I've just been looking at the `getAlphaRaster` method... I'm not putting it as an answer because I'm not sure, but there is a possibility that will be relevant – devrobf May 31 '13 at 13:09
  • Some combination of `int[] BufferedImage.getRGB()` and `WritableRaster.setPixels()` maybe. Just got to avoid the full-pixel loop somehow. – lynks May 31 '13 at 13:13
  • That's what I was wondering. Incidentally, how big/how much time are we talking? – devrobf May 31 '13 at 13:15
  • Around 800x600, and it should really be doing 30 or so per second. – lynks May 31 '13 at 13:17