Search code examples
androidbitmapjava-native-interfacealpha-transparencyargb

Access to raw data in ARGB_8888 Android Bitmap


I am trying to access the raw data of a Bitmap in ARGB_8888 format on Android, using the copyPixelsToBuffer and copyPixelsFromBuffer methods. However, invocation of those calls seems to always apply the alpha channel to the rgb channels. I need the raw data in a byte[] or similar (to pass through JNI; yes, I know about bitmap.h in Android 2.2, cannot use that).

Here is a sample:

    // Create 1x1 Bitmap with alpha channel, 8 bits per channel
    Bitmap one = Bitmap.createBitmap(1,1,Bitmap.Config.ARGB_8888);
    one.setPixel(0,0,0xef234567);
    Log.v("?","hasAlpha() = "+Boolean.toString(one.hasAlpha()));
    Log.v("?","pixel before = "+Integer.toHexString(one.getPixel(0,0)));

    // Copy Bitmap to buffer
    byte[] store = new byte[4];
    ByteBuffer buffer  = ByteBuffer.wrap(store);
    one.copyPixelsToBuffer(buffer);

    // Change value of the pixel
    int value=buffer.getInt(0);
    Log.v("?", "value before = "+Integer.toHexString(value));
    value = (value >> 8) | 0xffffff00;
    buffer.putInt(0, value);
    value=buffer.getInt(0);
    Log.v("?", "value after = "+Integer.toHexString(value));

    // Copy buffer back to Bitmap
    buffer.position(0);
    one.copyPixelsFromBuffer(buffer);
    Log.v("?","pixel after = "+Integer.toHexString(one.getPixel(0,0)));

The log then shows

hasAlpha() = true
pixel before = ef234567
value before = 214161ef
value after = ffffff61
pixel after = 619e9e9e

I understand that the order of the argb channels is different; that's fine. But I don't want the alpha channel to be applied upon every copy (which is what it seems to be doing).

Is this how copyPixelsToBuffer and copyPixelsFromBuffer are supposed to work? Is there any way to get the raw data in a byte[]?

Added in response to answer below:

Putting in buffer.order(ByteOrder.nativeOrder()); before the copyPixelsToBuffer does change the result, but still not in the way I want it:

pixel before = ef234567
value before = ef614121
value after = ffffff41
pixel after = ff41ffff

Seems to suffer from essentially the same problem (alpha being applied upon each copyPixelsFrom/ToBuffer).


Solution

  • I realize this is very stale and probably won't help you now, but I came across this recently in trying to get copyPixelsFromBuffer to work in my app. (Thank you for asking this question, btw! You saved me tons of time in debugging.) I'm adding this answer in the hopes it helps others like me going forward...

    Although I haven't used this yet to ensure that it works, it looks like that, as of API Level 19, we'll finally have a way to specify not to "apply the alpha" (a.k.a. premultiply) within Bitmap. They're adding a setPremultiplied(boolean) method that should help in situations like this going forward by allowing us to specify false.

    I hope this helps!