Конвертировать байтовый массив в PNG изображение с альфа

Я прошел через много вопросов здесь и через Интернет в целом и пока не имел никакого успеха.

У меня есть байтовый массив, который представляет необработанные данные, которые должны быть превращены в изображение PNG. У него есть альфа, поэтому мои цвета - RGBA. Насколько я знаю, байтовый массив - это сами необработанные данные изображения, без каких-либо заголовков, метаданных или чего-либо еще, что может быть принято некоторыми библиотеками или методами (этот байтовый массив был декодирован из DXT5).

Как я могу превратить свой массив байтов данных необработанного изображения в изображение PNG с альфа-каналом?

РЕДАКТИРОВАТЬ: Поскольку я понятия не имею, что я делаю в этой области, я могу включить больше кода, чем необходимо для решения проблемы.

Вот что декодирует DXT5:

private void decodeDXT5(ByteBuffer encodedBytes, int position, byte[] decodedBytes, int width, int height, int currentY, int currentX) {
    encodedBytes.order(ByteOrder.LITTLE_ENDIAN);
    encodedBytes.position(position);
    byte alpha0 = encodedBytes.get();
    byte alpha1 = encodedBytes.get();
    byte[] rgb = new byte[6];
    encodedBytes.get(rgb, 0, 6);

    byte[] color0 = RGB565_to_RGB888(encodedBytes.getShort());
    byte[] color1 = RGB565_to_RGB888(encodedBytes.getShort());
    byte[] c = new byte[]{encodedBytes.get(), encodedBytes.get(), encodedBytes.get(), encodedBytes.get()};

    byte[] a = new byte[]{
        (byte) (0x7 & rgb[0]),
        (byte) (0x7 & (rgb[0] >> 3)),
        (byte) (0x7 & (((0x1 & rgb[1]) << 2) + (rgb[0] >> 6))),
        (byte) (0x7 & (rgb[1] >> 1)),
        (byte) (0x7 & (rgb[1] >> 4)),
        (byte) (0x7 & (((0x3 & rgb[2]) << 1) + (rgb[1] >> 7))),
        (byte) (0x7 & (rgb[2] >> 2)),
        (byte) (0x7 & (rgb[2] >> 5)),
        (byte) (0x7 & rgb[3]),
        (byte) (0x7 & (rgb[3] >> 3)),
        (byte) (0x7 & (((0x1 & rgb[4]) << 2) + (rgb[3] >> 6))),
        (byte) (0x7 & (rgb[4] >> 1)),
        (byte) (0x7 & (rgb[4] >> 4)),
        (byte) (0x7 & (((0x3 & rgb[5]) << 1) + (rgb[4] >> 7))),
        (byte) (0x7 & (rgb[5] >> 2)),
        (byte) (0x7 & (rgb[5] >> 5))
    };

    for (int i = 0; i < 16; i++) {
        int e = Math.floorDiv(i, 4);
        decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 0] = c2Value(3 & c[e], color0[0], color1[0]); //red
        decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 1] = c2Value(3 & c[e], color0[1], color1[1]); //green
        decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 2] = c2Value(3 & c[e], color0[2], color1[2]); //blue
        decodedBytes[width * 4 * (height - 1 - currentY - e) + 4 * currentX + ((i - (e * 4)) * 4) + 3] = a2Value(a[i], alpha0, alpha1); //alpha

        c[e] = (byte) (c[e] >> 2);
    }

}

private byte[] RGB565_to_RGB888(short rgb) {
    byte r = (byte) (((rgb & 0xF800) >> 11) * 8);
    byte g = (byte) (((rgb & 0x07E0) >> 5) * 4);
    byte b = (byte) ((rgb & 0x001F) * 8);

    return new byte[]{r, g, b};
}

private byte c2Value(int code, byte color0, byte color1) {
    switch (code) {
        case 0:
            return color0;
        case 1:
            return color1;
        case 2:
        case 3:
            return (byte) ((color0 + color1 + 1) >> 1);
    }
    return color0;
}

private byte a2Value(int code, byte alpha0, byte alpha1) {
    if (alpha0 > alpha1) {
        switch (code) {
            case 0:
                return alpha0;
            case 1:
                return alpha1;
            case 2:
                return (byte) ((6 * alpha0 + 1 * alpha1) / 7);
            case 3:
                return (byte) ((5 * alpha0 + 2 * alpha1) / 7);
            case 4:
                return (byte) ((4 * alpha0 + 3 * alpha1) / 7);
            case 5:
                return (byte) ((3 * alpha0 + 4 * alpha1) / 7);
            case 6:
                return (byte) ((2 * alpha0 + 5 * alpha1) / 7);
            case 7:
                return (byte) ((1 * alpha0 + 6 * alpha1) / 7);
            default:
                LOG.error("a2Value code : " + code);
        }
    } else {
        switch (code) {
            case 0:
                return alpha0;
            case 1:
                return alpha1;
            case 2:
                return (byte) ((4 * alpha0 + 1 * alpha1) / 5);
            case 3:
                return (byte) ((3 * alpha0 + 2 * alpha1) / 5);
            case 4:
                return (byte) ((2 * alpha0 + 3 * alpha1) / 5);
            case 5:
                return (byte) ((1 * alpha0 + 4 * alpha1) / 5);
            case 6:
                return 0;
            case 7:
                return (byte) 0xFF; //why, what, WHY???
            default:
                LOG.error("a2Value code : " + code);
        }
    }

    return alpha0;
}

Который запускается из:

ByteBuffer bbIn = ByteBuffer.allocate(imageDataSize);
bbIn.put(imageData, 0, imageDataSize);
bbIn.position(0);

byte[] decodedImage = new byte[height * width * 4];
int currentX = 0;
int currentY = 0;

int position = 0;
while (position < imageData.length) {
    if ((currentX == width) && (currentY == height)) {
        break;
    }

    decodeDXT5(bbIn, position, decodedImage, width, height, currentY, currentX);

    currentX += 4;
    if (currentX + 4 > width) {
        currentX = 0;
        currentY += 4;
    }
    position += 16;
}

И часть PNG здесь. Это последняя итерация моих поисков, и она пока самая близкая. Размер файла, размеры, форма и т. Д., Все это есть; просто цвета выключены. Там происходит много артефактов; цвета, которые не являются частью изображения. Код PNG выглядит нормально (я пробовал несколько разных порядков смещения полосы, но все они приводят к одному и тому же изображению). Может быть, декодирование DXT5 не так? Или, может быть, на самом деле не все в порядке с PNG. Как я уже сказал, я не знаю, что я здесь делаю, потому что это за пределами моей области. Как упоминалось ранее, это декодированное изображение DXT5 имеет форму RGBA (один байт для каждого).

DataBuffer dataBuffer = new DataBufferByte(decodedImage, decodedImage.length);
int samplesPerPixel = 4;
int[] bandOffsets = {0, 1, 2, 3};

WritableRaster raster = Raster.createInterleavedRaster(dataBuffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
File file = new File("/opt/wildfly/standalone/tmp/temp.png");
ImageIO.write(image, "png", file);

1 ответ

Решение

Отсутствие в Java неподписанных типов для спасения...

Это была проблема с подписанным против неподписанного. Ява не имеет без знака, как мы знаем. На самом деле это была не проблема PNG, а проблема при распаковке из DXT5. Когда речь шла о математике, мне нужно было убедиться, что я работаю с эквивалентом беззнакового типа (поэтому в великой традиции Java используйте следующий самый высокий тип и замаскируйте бит знака).

Другие вопросы по тегам