Android:位图到 RGBA 并返回

标签 android graphics bitmap rgba argb

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

相关文章:

c++ - 如何生成位图头数据然后使用C++写入文件

java - 将 Mp3 转换为字节数组再转换为字符串

android - 如何编写基于 xml 布局的自定义 View 类

java - Android Intent/IntentService 的空指针异常

java - Android Fragment刷新不起作用

graphics - 使用 WebGL 而不是桌面 OpenGL

java - Graphics.drawimage 不起作用

OpenGL 正交 View 近/远值

android - 如何在 Android 中调整图像大小?

android - 如何在 Android 中使用双三次插值在 Canvas 上绘制和缩放位图?