我正在尝试编写几个方法来将 Android 位图转换为 RGBA 字节数组,然后再转换回位图。问题是我似乎没有找到公式,因为返回的颜色总是错误的。我尝试了几种不同的假设,但都无济于事。
所以,这是我认为很好的从位图转换为 RGBA 的方法:
public static byte[] bitmapToRgba(Bitmap bitmap) {
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
byte[] bytes = new byte[pixels.length * 4];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
int i = 0;
for (int pixel : pixels) {
// Get components assuming is ARGB
int A = (pixel >> 24) & 0xff;
int R = (pixel >> 16) & 0xff;
int G = (pixel >> 8) & 0xff;
int B = pixel & 0xff;
bytes[i++] = (byte) R;
bytes[i++] = (byte) G;
bytes[i++] = (byte) B;
bytes[i++] = (byte) A;
}
return bytes;
}
这是旨在从那些未按预期工作的字节创建回位图的方法:
public static Bitmap bitmapFromRgba(int width, int height, byte[] bytes) {
int[] pixels = new int[bytes.length / 4];
int j = 0;
// It turns out Bitmap.Config.ARGB_8888 is in reality RGBA_8888!
// Source: https://stackoverflow.com/a/47982505/1160360
// Now, according to my own experiments, it seems it is ABGR... this sucks.
// So we have to change the order of the components
for (int i = 0; i < pixels.length; i++) {
byte R = bytes[j++];
byte G = bytes[j++];
byte B = bytes[j++];
byte A = bytes[j++];
int pixel = (A << 24) | (B << 16) | (G << 8) | R;
pixels[i] = pixel;
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixels));
return bitmap;
}
这是我最后一次实现,尽管我尝试了几种不同的实现,但都没有成功。尽管指定了 ARGB_8888,我还是假设 createBitmap 期望 ABGR,因为我已经完成了将所有像素硬编码为以下内容的实验:
0xff_ff_00_00 -> got blue
0xff_00_ff_00 -> got green
0xff_00_00_ff -> got red
无论如何,这个假设可能是错误的,并且是之前其他错误假设的结果。
我认为主要问题可能与有符号数值的使用有关,因为 Java 中没有无符号数值(好吧,Java 8+ 中有一些东西,但一方面我认为没有必要使用这些,另一方面,我需要支持的旧 Android 版本不支持它)。
任何帮助将不胜感激。
提前致谢!
最佳答案
我自己解决了。有很多问题,但所有这些问题都是从这一行开始的:
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixels));
这似乎以错误的方式混合了颜色成分。也许它与字节顺序(小/大印度的东西)有关,无论如何我都使用 setPixels 来解决它:
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
这是按预期工作的最终代码,以防它对其他人有用:
public static byte[] bitmapToRgba(Bitmap bitmap) {
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888)
throw new IllegalArgumentException("Bitmap must be in ARGB_8888 format");
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
byte[] bytes = new byte[pixels.length * 4];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
int i = 0;
for (int pixel : pixels) {
// Get components assuming is ARGB
int A = (pixel >> 24) & 0xff;
int R = (pixel >> 16) & 0xff;
int G = (pixel >> 8) & 0xff;
int B = pixel & 0xff;
bytes[i++] = (byte) R;
bytes[i++] = (byte) G;
bytes[i++] = (byte) B;
bytes[i++] = (byte) A;
}
return bytes;
}
public static Bitmap bitmapFromRgba(int width, int height, byte[] bytes) {
int[] pixels = new int[bytes.length / 4];
int j = 0;
for (int i = 0; i < pixels.length; i++) {
int R = bytes[j++] & 0xff;
int G = bytes[j++] & 0xff;
int B = bytes[j++] & 0xff;
int A = bytes[j++] & 0xff;
int pixel = (A << 24) | (R << 16) | (G << 8) | B;
pixels[i] = pixel;
}
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
return bitmap;
}
关于Android:位图到 RGBA 并返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59786742/