Why is copyPixelsFromBuffer giving incorrect color? setPixels is correct but slow

南楼画角 提交于 2020-02-02 11:31:08

问题


For my android app I am getting a ByteBuffer from native code. It contains the pixel color values to create a bitmap.

Original image -

I used copyPixelsFromBuffer on bitmap, but I am getting incorrect color on displaying the bitmap.

Here is the code for this approach -

Approach 1

ByteBuffer buffer = ...

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
buffer.rewind();
bitmap.copyPixelsFromBuffer(buffer);

Approx. time - ~0.4 ms
Result - Wrong colors -

Approach 2

Next I tried setPixels. It still gives wrong colors and is more than 10 times slower and uses extra memory for int[]. Please note that buffer.hasArray() is false, so I can't get array from buffer.

ByteBuffer buffer = ...

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
buffer.rewind();

int[] pixels = new int[width * height];

for (int i = 0; i < width * height; i++) {
    int a = buffer.get();
    int r = buffer.get();
    int g = buffer.get();
    int b = buffer.get();
    pixels[i] = a << 24 | r << 16 | g << 8 | b;
}
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

Approx. time - ~4.0 ms
Result - Wrong colors -

Approach 3

This time I used setPixels but with the pixel values taken from IntBuffer representation of ByteBuffer. The colors are correct but the time is still high and there is extra memory allocation.

ByteBuffer buffer = ...
IntBuffer intBuffer = buffer.asIntBuffer();

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
buffer.rewind();

int[] pixels = new int[width * height];

for (int i = 0; i < width * height; i++) {
    pixels[i] = intBuffer.get();
}
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);

Approx. time - ~3.0 ms
Result - Correct colors -

Any hints on why I am getting wrong colors with copyPixelsFromBuffer? I want to use it instead of setPixels as it is faster and does not require extra memory allocation.


回答1:


I figured out the problem - even though the Bitmap.Config is said to be ARGB_8888, it really is RGBA. I think it is a huge bug in android developer documentation and code.

The same issue has been noted in this question - Is Android's ARGB_8888 Bitmap internal format always RGBA?

And the ndk documentation correctly notes the format to be ANDROID_BITMAP_FORMAT_RGBA_8888

Solution is simple - create the buffer with RGBA format. Or on the java side switch the channels, something like below -

for (int i = 0; i < width * height; i++) {
    Byte a = buffer.get();
    Byte r = buffer.get();
    Byte g = buffer.get();
    Byte b = buffer.get();
    bufferCopy.put(r);
    bufferCopy.put(g);
    bufferCopy.put(b);
    bufferCopy.put(a);
}

This is not very efficient code, but gets the job done.



来源:https://stackoverflow.com/questions/47970384/why-is-copypixelsfrombuffer-giving-incorrect-color-setpixels-is-correct-but-slo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!