问题
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