从RGB整数数组生成位图。我的尝试怎么了?

时间:2019-03-11 20:00:11

标签: java bitmap

我想在游戏中添加截图功能。

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

pixels是一个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 :(得分:0)

您需要确保标题正确。例如,标头中的文件大小字段需要为4个字节(请参阅:BMP file format)。要准确写出正确的字节数,可以使用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();
}

从长远来看,最好找到一个可以为您完成所有工作的第三方库。

相关问题