Android: растровое изображение в RGBA и обратно - PullRequest
0 голосов
/ 17 января 2020

Я пытаюсь написать пару методов для преобразования растрового изображения 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;
}

Это моя последняя реализация, хотя я пробовал несколько разных без успеха. Я предполагаю, что createBitmap ожидает ABGR, несмотря на указание ARGB_8888, потому что я провел эксперименты, жестко кодирующие все пиксели для таких вещей, как:

0xff_ff_00_00 -> got blue 
0xff_00_ff_00 -> got green
0xff_00_00_ff -> got red

В любом случае, возможно, это предположение неверно и является следствием какого-то другого ошибочного ранее.

Я думаю, что основная проблема может быть связана с использованием значений числовых c со знаком, поскольку в Java нет беззнаковых значений (ну, в Java 8+ есть что-то, но с одной стороны Я не думаю, что это необходимо, и с другой стороны, оно не поддерживается более старыми Android версиями, которые мне нужно поддерживать).

Любая помощь будет очень признательна.

Заранее большое спасибо!

1 Ответ

1 голос
/ 17 января 2020

Я решил это сам. Есть ряд проблем, но все они начались с этой строки:

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;
}
...