为什么 copyPixelsFromBuffer 给出的颜色不正确?setPixels 正确但速度慢

Vin*_*arg 5 performance android bytebuffer colors bitmap

对于我的 Android 应用程序,我ByteBuffer从本机代码中获取了一个。它包含创建位图的像素颜色值。

原始图像 -

在此输入图像描述

我在位copyPixelsFromBuffer图上使用,但在显示位图时得到的颜色不正确。

这是这种方法的代码 -

方法一

ByteBuffer buffer = ...

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
buffer.rewind();
bitmap.copyPixelsFromBuffer(buffer);
Run Code Online (Sandbox Code Playgroud)

大约。时间- ~0.4 ms
结果- 颜色错误 -
在此输入图像描述

方法2

接下来我尝试了setPixels。它仍然给出错误的颜色,速度慢 10 倍以上,并且需要额外的内存int[]。请注意,这buffer.hasArray()false,所以我无法从缓冲区获取数组。

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);
Run Code Online (Sandbox Code Playgroud)

大约。时间- ~4.0 ms
结果- 颜色错误 -

在此输入图像描述

方法3

这次我使用了setPixels但像素值取自IntBuffer的表示ByteBuffer。颜色是正确的,但时间仍然很长,并且有额外的内存分配。

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);
Run Code Online (Sandbox Code Playgroud)

大约。时间- ~3.0 ms
结果- 正确的颜色 -

在此输入图像描述

关于为什么我得到错误颜色的任何提示copyPixelsFromBuffer?我想使用它而不是因为setPixels它更快并且不需要额外的内存分配。

Vin*_*arg 5

我发现了问题所在——虽然Bitmap.Config是这样说的ARGB_8888,但事实确实如此RGBA。我认为这是 Android 开发人员文档和代码中的一个巨大错误。

在这个问题中也提到了同样的问题 - Is Android's ARGB_8888 Bitmap Internal format always RGBA?

并且 ndk 文档正确地指出了格式ANDROID_BITMAP_FORMAT_RGBA_8888

解决方案很简单 - 创建 RGBA 格式的缓冲区。或者在java端切换通道,如下所示 -

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);
}
Run Code Online (Sandbox Code Playgroud)

这不是非常有效的代码,但可以完成工作。