Генерация растрового изображения из массива целых чисел RGB. Что не так с моей попыткой? - PullRequest
1 голос
/ 11 марта 2019

Я хочу добавить в игру функцию скриншота.

int width = 320;
int height = width / 4*3;

пикселей - это int [], содержащее 76800 значений RGB int, соответствующих каждому пикселю, присутствующему на экране в любое время

public static void buildBitmap() {      
    File f = new File("C:/scr/game_name" + LocalDate.now().toString() +".bmp");
    try(FileOutputStream fos = new FileOutputStream(f)){
        fos.write(66);  
        fos.write(77);

        fos.write(230428);     //width * height * 3
        fos.write(0);
        fos.write(0);
        fos.write(0);

        fos.write(0);
        fos.write(0);

        fos.write(0);
        fos.write(0);

        fos.write(26);
        fos.write(0);
        fos.write(0);
        fos.write(0);


        fos.write(12);
        fos.write(0);
        fos.write(0);
        fos.write(0);

        fos.write(320);
        fos.write(0);
        fos.write(240);
        fos.write(0);

        fos.write(1);
        fos.write(0);

        fos.write(24);
        fos.write(0);            

        for(int y = height-1; y > 0; y--) {
            for(int x = 0; x < width-1; x++){              
               fos.write(pixels[x + y * width] & 0xFF);     //blue
               fos.write((pixels[x + y * width] >> 8) & 0xFF);  //green
               fos.write((pixels[x + y * width] >> 16) & 0xFF); //red
            }
        }

        fos.write(0);
        fos.write(0);
    }catch(IOException e) {
        e.printStackTrace();
    }
    System.out.println("Screenshot saved to " + f);
}

Вложенный цикл, который должен заполнить запись в файл фактическими данными изображения, выполняется для перебора массива снизу вверх: слева направо, для преобразования значения RGB int в отдельный синий, зеленый, красный и записи их в файл. (в таком порядке).

Это математически чистый звук, и получающееся изображение, хотя и искаженное и изуродованное, по крайней мере, узнаваемо из игры. Что не так с моим кодом?

Кроме того, выходное изображение имеет ширину 64, почему это так?

1 Ответ

0 голосов
/ 12 марта 2019

Вы должны убедиться, что ваши заголовки верны. Например, поле размера файла в заголовке должно быть 4 байта (см .: Формат файла BMP ). Для записи точного количества байтов вы можете использовать DataOutputStream .

Вам необходимо изменить endianess значений. Java с прямым порядком байтов, а файлы BMP с прямым порядком байтов. (См. Все звонки на reverseBytes в коде).

Ваши циклы игнорируют последний байт в каждом ряду и последний ряд.

Вы также игнорируете шаг растрового изображения. Это дополнительные байты заполнения в конце каждой строки. Поскольку ваш пример имеет ширину 320 пикселей, лишних байтов не бывает, но для обработки нечетных размеров вы должны их обработать.

File f = new File("C:/scr/game_name" + LocalDate.now().toString() +".bmp");
try (FileOutputStream fos = new FileOutputStream(f)){
    DataOutputStream dos = new DataOutputStream(fos);

    int header_size = 14 + 40;  // Size of both headers
    int width = 320;
    int height = 240;
    short bpp = 24;
    // Calculate the stride
    int stride = 4 * ((width * bpp + 31) / 32);

    // BITMAPFILEHEADER
    dos.writeByte(66);                                // B
    dos.writeByte(77);                                // M
    int fileSize = (stride * height) + header_size;
    dos.writeInt(Integer.reverseBytes(fileSize));     // Actual size of entire file
    dos.writeShort(0);                                // Reserved
    dos.writeShort(0);                                // Reserved
    dos.writeInt(Integer.reverseBytes(header_size));  // starting address of bitmap image data

    // BITMAPINFOHEADER
    dos.writeInt(Integer.reverseBytes(40));           // Size of header
    dos.writeInt(Integer.reverseBytes(width));        // Width
    dos.writeInt(Integer.reverseBytes(height));       // Height
    dos.writeShort(Short.reverseBytes((short)1));     // Color planes
    dos.writeShort(Short.reverseBytes(bpp));          // BPP
    dos.writeInt(0);                                  // Compression method
    dos.writeInt(0);                                  // Image size
    dos.writeInt(0);                                  // Horizontal res
    dos.writeInt(0);                                  // Vertical res
    dos.writeInt(0);                                  // Number of colors
    dos.writeInt(0);                                  // Important colors

    for (int y = height - 1; y >= 0; y--) {
        for(int x = 0; x < width; x++) {
            dos.writeByte(pixels[x + y * width] & 0xFF);         //blue
            dos.writeByte((pixels[x + y * width] >> 8) & 0xFF);  //green
            dos.writeByte((pixels[x + y * width] >> 16) & 0xFF); //red
        }
        // Add padding bytes
        for (int s = width * 3; s < stride; s++) {
           dos.writeByte(0);
        }
    }
    fos.close();
}
catch(IOException e) {
    e.printStackTrace();
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...