首页 > 解决方案 > 从 RGB 整数数组生成位图。我的尝试有什么问题?

问题描述

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

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

pixel 是一个 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,这是为什么呢?

标签: javabitmap

解决方案


你需要确保你的标题是正确的。例如,标头中的文件大小字段需要为 4 个字节(参见:BMP 文件格式)。要准确写入正确的字节数,您可以使用DataOutputStream

您需要反转值的字节序。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();
}

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


推荐阅读