如何使用 C++ 正确计算 BMP 图像中每个像素的字节数?

Posted

技术标签:

【中文标题】如何使用 C++ 正确计算 BMP 图像中每个像素的字节数?【英文标题】:How to properly calculate no of bytes per pixel in BMP image using C++? 【发布时间】:2015-02-02 06:15:53 【问题描述】:

我正在尝试使用从 struct BITMAPINFOHEADER 收集的信息来计算 BMP 图像中的像素数,从而计算每个像素的字节数。但是每当我运行我的代码时,我都会得到每个像素的字节数 = 0

struct BITMAPFILEHEADER             // File header

char bfType[2];                   // File type: should be BM ( 0x42 0x4D ) 
int bfSize;                       // File size in bytes
short bfReserved1;                // Reserved - for what i have no idea :P 
short bfReserved2;                // -||-
int bfOffBits;                    // Offset, adress of the beginning of the information about image (pixels )
;

struct BITMAPINFOHEADER             // Bitmap header

unsigned int biSize;              // Size of this header
unsigned int biWidth;             // Width of image ( in pixels)
unsigned int biHeight;            // Height of this image ( in pixels )
unsigned short biPlanes;          // Numer of color planes, always 1
unsigned short biBitCount;        // Number of bytes for pixel.  Possibility values :1,4,8,16, 24 and 32
unsigned int biCompression;       // Used compression (0 -none)
unsigned int biSizeImage;         // Size of image 
signed int biXPelsPerMeter;       // Horizontal resolution of the image (pixel per meter)
signed int biYPelsPerMeter;       // Vertical resolution of the image (pixel per meter)
unsigned int biClrUsed;           // Number of colors in the color palette, or 0 to default to 2^n ( 0- no palette)
unsigned int biClrImportant;      // Number of important colors used
 ;

struct Pixel
unsigned int blue;  // or double?
unsigned int green;
unsigned int red;
//unsigned char reserved;
;


void Image::conversiontoBRG(const char* filename)

ifstream brgfile;
brgfile.open(filename, ios::in | ios::binary);


char *bmpheadinfo = new char[sizeof(BITMAPFILEHEADER)];
brgfile.read(bmpheadinfo, sizeof(BITMAPFILEHEADER));
BITMAPFILEHEADER* bmpheader = (BITMAPFILEHEADER*)bmpheadinfo;

cout << "File type : " << bmpheader->bfType << endl;
cout << "File size : " << bmpheader->bfSize << endl;
cout << "File Offset for the beginning of image info : " << bmpheader->bfOffBits << endl << endl;


bmpheadinfo = new char[sizeof(BITMAPINFOHEADER)];
brgfile.read(bmpheadinfo, sizeof(BITMAPINFOHEADER));
BITMAPINFOHEADER* bmpinfo = (BITMAPINFOHEADER*)bmpheadinfo;

cout << "File Header Size : " << bmpinfo->biSize << endl;
cout << "Width : " << bmpinfo->biWidth << endl;
cout << "Height : " << bmpinfo->biHeight << endl;
cout << "No of bytes per pixel : " << bmpinfo->biBitCount << endl;
cout << "Used compression: " << bmpinfo->biCompression << endl;
cout << "Image size: " << bmpinfo->biSizeImage << endl;
cout << "Horizontal resolution: " << bmpinfo->biXPelsPerMeter << endl;
cout << "Vertical resolution: " << bmpinfo->biYPelsPerMeter << endl;
cout << "Number of colors in the color palette: " << bmpinfo->biClrUsed << endl;
cout << "Number of important colors used: " << bmpinfo->biClrImportant << endl;

我正在尝试处理名为 index.bmp 的位图图像

尺寸:275x184 宽度:275 像素 高度:184 像素 位深:24 名称:index.bmp 项目类型:BMP 文件 大小:148 KB

但是每当我运行上面的代码时,我都会得到以下输出。我不确定我哪里出错了。请帮帮我。

File type : BMVS
File size : 2
File Offset for the beginning of image info : 2621440

File Header Size : 18022400
Width : 12058624
Height : 65536
No of bytes per pixel : 0
Used compression: 1394606080
Image size: 2
Horizontal resolution: 0
Vertical resolution: 0
Number of colors in the color palette: 0
Number of important colors used: 973078528

【问题讨论】:

12058624 是 0xB80000。 0xB8 是 184。18022400 是 0x1130000。 0x113 是 275。您不同步。 BMVS 是大端十六进制的 0x424d5653。字符串VS 出现是因为bfType 不是像TonyD 所说的以空结尾的字符串,而是bfSize 的2 个MSB。由于您没有指定填充,因为对齐bfSize 从下一个 4 字节边界开始并以大端读取 2 或 0x02000000。因此它的实际值为0x00025356 = 152,406 bytes = 148.834KB 只需使用#pragma pack(push, 1)#pragma pack(pop) 宏。你会得到你期望的结果。 @PureProgrammer Legends2k 已经回答了这个问题,不,它不会起作用,因为它只是解决了代码中的一个问题 @LưuVĩnhPhúc 对不起,我没想到。但是,我认为bfType 应该是unsigned short 的类型,对吧? 【参考方案1】:

legends2k 也提到了包装问题:

你没有考虑字节序(谷歌它,然后在你的代码中使用ntohs等),

1234563为BITMAPINFOHEADER做类似的事情

也不要只打印 bfType - 作为一个数组,它会衰减到 const char* 对应 &lt;&lt;,而且它不是 NUL 终止的,所以你会得到垃圾额外字符。

李>

【讨论】:

由于在忽略填充字节时会导致访问未对齐,因此支持提及 SIGBUS。【参考方案2】:

BMP 文件的标头数据中没有填充位,而您的 structs 已被定义为没有紧密打包的宏;这将导致您的文件数据成员和struct 数据成员未正确对齐。修复此问题,您将能够正确查看字段

#pragma pack(push, 1)       // macro to avoid padding bytes within a struct

struct BITMAPFILEHEADER             // File header

    char bfType[2];                   // File type: should be BM ( 0x42 0x4D ) 
    int bfSize;                       // File size in bytes
    short bfReserved1;                // Reserved - for what i have no idea :P 
    short bfReserved2;                // -||-
    int bfOffBits;                    // Offset, adress of the beginning of the information about image (pixels )
;

struct BITMAPINFOHEADER             // Bitmap header

    unsigned int biSize;              // Size of this header
    unsigned int biWidth;             // Width of image ( in pixels)
    unsigned int biHeight;            // Height of this image ( in pixels )
    unsigned short biPlanes;          // Numer of color planes, always 1
    unsigned short biBitCount;        // Number of bytes for pixel.  Possibility values :1,4,8,16, 24 and 32
    unsigned int biCompression;       // Used compression (0 -none)
    unsigned int biSizeImage;         // Size of image 
    signed int biXPelsPerMeter;       // Horizontal resolution of the image (pixel per meter)
    signed int biYPelsPerMeter;       // Vertical resolution of the image (pixel per meter)
    unsigned int biClrUsed;           // Number of colors in the color palette, or 0 to default to 2^n ( 0- no palette)
    unsigned int biClrImportant;      // Number of important colors used
;

#pragma pack(pop)         // stop doing the tight packing

可以验证现在没有填充位了

std::cout << sizeof BITMAPFILEHEADER << '\n';

现在将打印14;通过禁用宏来尝试,您会看到超过 14 个的内容。在this live example 上显示16

【讨论】:

以上是关于如何使用 C++ 正确计算 BMP 图像中每个像素的字节数?的主要内容,如果未能解决你的问题,请参考以下文章

逐像素编辑 bmp [C++]

用C或C++怎样提取出bmp图像的像素点信息值?用LSB算法做信息隐藏,位图是24位的。

C++ - 从 BMP 文件中读取每个像素的位数

我如何正确调整位图的大小?

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

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