Android:位图与 RGBA 之间的转换

Fra*_*zoa 5 graphics android bitmap argb rgba

我正在尝试编写一些方法来将 Android 位图转换为 RGBA 字节数组,然后再转换回位图。问题是我似乎没有达到公式,因为颜色总是返回错误。我尝试过几种不同的假设,但没有成功。

所以,这是我认为很好的从 Bitmap 转换为 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;
}
Run Code Online (Sandbox Code Playgroud)

这是旨在从那些未按预期工作的字节创建位图的方法:

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: /sf/answers/3358775381/
    // 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;
}
Run Code Online (Sandbox Code Playgroud)

这是我最后一次实现,尽管我尝试了几种不同的方法但没有成功。我假设 createBitmap 尽管指定了 ARGB_8888 但仍期望 ABGR,因为我已经完成了将所有像素硬编码为以下内容的实验:

0xff_ff_00_00 -> got blue 
0xff_00_ff_00 -> got green
0xff_00_00_ff -> got red
Run Code Online (Sandbox Code Playgroud)

无论如何,也许这个假设是错误的,并且是之前其他一些错误假设的结果。

我认为主要问题可能与有符号数值的使用有关,因为Java中没有无符号数值(好吧,Java 8+中有一些东西,但一方面我认为没有必要使用这些,另一方面,我需要支持的旧版 Android 版本不支持它)。

任何帮助将不胜感激。

预先非常感谢!

Fra*_*zoa 7

我自己解决了。有很多问题,但所有这些都始于这一行:

bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixels));
Run Code Online (Sandbox Code Playgroud)

这似乎以错误的方式混合了颜色成分。也许这与字节顺序有关(小/大印度的东西),无论如何我都使用 setPixels 来解决它:

bitmap.setPixels(pixels, 0, width, 0, 0, width, height); 
Run Code Online (Sandbox Code Playgroud)

这是按预期工作的最终代码,以防万一对其他人有用:

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