我尝试用 c++ 编写一个 bmp 文件,但是 bmp 文件的宽度和高度似乎会影响结果,有时我得到了一个错误的 bmp 文件

Posted

技术标签:

【中文标题】我尝试用 c++ 编写一个 bmp 文件,但是 bmp 文件的宽度和高度似乎会影响结果,有时我得到了一个错误的 bmp 文件【英文标题】:I try to write a bmp file in c++, but the bmp file's width and height seems to affect the result,sometimes I got a bad bmp file 【发布时间】:2015-10-30 14:22:35 【问题描述】:

正如标题中所描述的那样。代码如下所示

#include <Windows.h>
#include <string>

using namespace std;

#define WIDTH  90
#define HEIGHT 180

class Test 
public:
    static bool ShowWithBMP(string filename) 
        BITMAPFILEHEADER    bmfh;           // bitmap file header  
        BITMAPINFOHEADER    bmih;           // bitmap info header (windows)  

        const int OffBits = 54;

        bmfh.bfReserved1 = 0;
        bmfh.bfReserved2 = 0;
        bmfh.bfType = 0x4d42;   //"BM"
        bmfh.bfOffBits = OffBits;      
        bmfh.bfSize = WIDTH * HEIGHT * 3 + OffBits;

        memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
        bmih.biSize = 40;               
        bmih.biPlanes = 1;
        bmih.biSizeImage = 0;
        bmih.biBitCount = 24;
        bmih.biCompression = BI_RGB;
        bmih.biWidth = WIDTH;
        bmih.biHeight = HEIGHT;


        FILE* file = fopen(filename.c_str(), "w");
        fwrite((const void*)&bmfh, sizeof(BITMAPFILEHEADER), 1, file);
        fwrite((const void*)&bmih, sizeof(BITMAPINFOHEADER), 1, file);


        for (int row = 0; row < HEIGHT; ++row)
        
            // RGB 24 BITS  
            for (int col = 0; col < WIDTH; ++col)
            
                int index = row * WIDTH + col;
                RGBTRIPLE pix;

                pix.rgbtRed = 0;
                pix.rgbtGreen = 0;
                pix.rgbtBlue = 0; 
                fwrite((const void*)&pix, sizeof(RGBTRIPLE), 1, file);
            
        
        fclose(file);
        return true;
       
;

int main() 
    Test::ShowWithBMP("test.bmp");
    system("pause");
    return 0;

当我将 WIDTH 设置为 90 并将 HEIGHT 设置为 180 时,输出文件“test.bmp”似乎是一个错误的文件,我无法打开它,但是当我将 WIDTH 设置为 100 并且将 HEIGHT 设置为 180 时,它变得正确.它出什么问题了?当我尝试使用 C++ 编写 bmp 文件时有什么限制吗?

【问题讨论】:

对于c++ 中的常量不要首选#define,而是首选const type name;(例如const int WIDTH = 90;)。最终,您可能不希望它们成为常量。 Bitmap file header size的可能重复 非常感谢。我已更正。但是bmp文件有什么问题呢?我复制网站里的代码,然后我看MSDN自己重写了,还是不行.....T T 【参考方案1】:

根据记忆(大约 20 年前),BMP format 本质上包含像素数据的 DIB 格式。每个像素行需要是 4 字节的倍数(即整数个 DWORD);因此,您需要确保在每一行的末尾都有适当的填充。

【讨论】:

【参考方案2】:

这是您的函数,其中包含应该可以工作的修复

static bool ShowWithBMP(string filename) 
    BITMAPFILEHEADER    bmfh;           // bitmap file header  
    BITMAPINFOHEADER    bmih;           // bitmap info header (windows)  

    const int OffBits = 54;

    bmfh.bfReserved1 = 0;
    bmfh.bfReserved2 = 0;
    bmfh.bfType = 0x4d42;   //"BM"
    bmfh.bfOffBits = OffBits; 

    DWORD bitmapLineSize = ((WIDTH * 3 + 3) / 4) * 4; //size of a row in bytes (ceil(WIDTH * 3 / 4) * 4)
    bmfh.bfSize = bitmapLineSize * HEIGHT + OffBits;

    memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
    bmih.biSize = 40;               
    bmih.biPlanes = 1;
    bmih.biSizeImage = 0;
    bmih.biBitCount = 24;
    bmih.biCompression = BI_RGB;
    bmih.biWidth = WIDTH;
    bmih.biHeight = HEIGHT;

    DWORD paddingSize = bitmapLineSize - 3 * WIDTH;//extra 0 to 3 bytes per line to write

    FILE* file = fopen(filename.c_str(), "w");
    fwrite((const void*)&bmfh, sizeof(BITMAPFILEHEADER), 1, file);
    fwrite((const void*)&bmih, sizeof(BITMAPINFOHEADER), 1, file);


    for (int row = 0; row < HEIGHT; ++row)
    
        // RGB 24 BITS  
        for (int col = 0; col < WIDTH; ++col)
        
            int index = row * WIDTH + col;
            RGBTRIPLE pix;

            pix.rgbtRed = 0;
            pix.rgbtGreen = 0;
            pix.rgbtBlue = 0; 
            fwrite((const void*)&pix, sizeof(RGBTRIPLE), 1, file);
        

        if (paddingSize > 0)
        
            //write out the rest of the bitmap line filled with zeros
            DWORD padding = 0;
            fwrite((const void*)&padding, paddingSize, 1, file);
        
    
    fclose(file);
    return true;
   

【讨论】:

非常感谢!对我有很大帮助 欢迎您。最好分配整个位图或其中的一部分(N 行),然后先填充内存缓冲区,然后将其写入磁盘,而不是逐个像素地写入。 fwrite 具有将数据保存在缓冲区中的机制,直到缓冲区已满或使用 fflush 或 fclose 时,所以我认为两者都可以 X0

以上是关于我尝试用 c++ 编写一个 bmp 文件,但是 bmp 文件的宽度和高度似乎会影响结果,有时我得到了一个错误的 bmp 文件的主要内容,如果未能解决你的问题,请参考以下文章

读取 BMP 文件 C++(读取 BMP 标头时出现问题)

在 C++ 中读取 .bmp 文件

用c ++读取BMP文件的所有字节并旋转图片

如何使用 C++ 创建 BMP 文件?

已有一个bmp图片用标准c获取其任意点(给定坐标)像素信息?

C++如何把位图保存到数组中