Android:位图到 RGBA 并返回

Android: bitmap to RGBA and back

我正在尝试编写几个方法来将 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: 
    // 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));

这似乎以错误的方式混淆了颜色分量。也许它与字节顺序有关(little/big 印度的东西),无论如何我使用 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;
}