安卓的ARGB_8888位图内部格式是否总是RGBA?

5

我正在尝试使用Bitmap.Config.ARGB_8888在Android中创建Bitmap,并在从外部源接收到字节后这样做。据我所知,在不使用JNI的情况下,设置Bitmap中的原始字节最快的方法是使用copyPixelsFromBuffer()方法,但是问题在于缓冲区中字节的正确顺序。

经过一些试验和错误,尽管Config.ARGB_8888建议正确的ARGB顺序,但似乎Bitmap使用的内部格式是RGBA。您可以使用以下方法在Activity中测试此行为,即在onCreate()中(我已在Android 4.4.4中进行了测试,虽然该方法测试的是copyPixelsToBuffer(),但根据我的测试,copyPixelsFromBuffer()的行为相同):

private void testBitmap() {
    // one pixel bitmap
    Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);

    // as per javadoc, the int value is in ARGB format, so A=0xFF, R=0x11, G=0x22, B=0x33
    bitmap.setPixel(0, 0, 0xFF112233);

    ByteBuffer buffer = ByteBuffer.allocateDirect(4);   // 4 bytes for the single pixel
    bitmap.copyPixelsToBuffer(buffer);
    buffer.position(0);

    // prints "Bytes: 0x11 0x22 0x33 0xFF"  (RGBA)
    System.out.println(String.format(Locale.ENGLISH, "Bytes: %s %s %s %s",
            toHexString(buffer.get()),
            toHexString(buffer.get()),
            toHexString(buffer.get()),
            toHexString(buffer.get())
    ));
}

private static String toHexString(byte b) {
    return Integer.toHexString(b & 0xFF).toUpperCase();
}

我的问题是:这个内部格式是否有文档记录?如果没有,那么我们怎么知道上面的代码在未来的Android版本中不会出现问题?或者也许有其他建议来复制Bitmap中的原始字节吗?


这与 ByteBuffer#order() 有关吗?只是猜测... - pskink
@pskink 不是这样的。无论缓冲区的字节顺序如何,结果都是相同的。如果这是一个字节顺序问题,我会期望输出不同,即 BGRA。我提到的格式只在 alpha 通道上有所不同。 - c.s.
哦,确实,我错过了你得到的是RGBA,而不是你说的BGRA,你能否改用int[] arr = new int[1]; bitmap.getPixels(arr, 0, 1, 0, 0, 1, 1); Log.d(TAG, "test: " + Integer.toHexString(arr[0])); - pskink
@pskink 我可能可以做到,但是我对字节的情况感兴趣,因为Java文档提到涉及缓冲区的复制操作会按原样复制数据,而getPixels()/setPixels()则将字节转换为打包的int。我正在寻找尽可能避免转换的方法。 - c.s.
2
我看到了,似乎这只是他们命名那些 ARGB_* 常量的方式,对于 ndk 来说,它们更加精确:https://developer.android.com/ndk/reference/group___bitmap.html#gaea286a2d4c61ae2abb02b51500499f13 - pskink
2个回答

4

由于最近我也被这个问题搞糊涂了,所以想更新一下答案。

调用setPixels()copyPixelsFromBuffer()时的行为确实反映了高级API中颜色表示方式与位图中实际字节顺序之间的区别。这在Bitmap类中有所记录(至少现在是这样),但并不容易理解。

setPixels()提供了更高级别的接口,它期望像资源和Color类等其他高级别接口一样使用整数,因此可以按ARGB 如此记录。 您可以轻松地执行以下操作:bitmap.setPixel(0,0,Color.RED)。Color类在此处提到的顺序为:

int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);

内部表示为RGBA,正如您从copyPixelsFromBuffer()发现的那样。这在Bitmap.Config有所暗示,如下所示,并且在NDK Bitmap头文件中也以其枚举名命名为ANDROID_BITMAP_FORMAT_RGBA_8888:
int color = (A & 0xff) << 24 | (B & 0xff) << 16 | (G & 0xff) << 8 | (R & 0xff);

0

谢谢。我知道RGBA可能很常用,但是如果我能找到一些官方的关于Bitmap类的说明,我会更加放心。 - c.s.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接