You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

读取BMP文件头数值与微软官方定义不符,求技术排查

BMP文件头读取数值异常问题排查与解决

问题概述

读取BMP文件的BITMAPFILEHEADER和BITMAPINFOHEADER时,得到的数值与官方定义完全不符:例如bfType应为0x4D42(ASCII的"BM"),实际读取到55551,其他字段数值也全部错乱。错误输出如下:

bfType: 55551
bfSize: 1179258880
bfReserved1: 17993
bfReversed2: 256
bfOffBits: 1207959809

biSize: 18432
biWidth: 1477239551
biHeight: 1598243657
biPlanes: 21072
biBitCount: 17999
biCompression: 4541513
biSizeImage: 257
biXPelsPerMeter: 1766606860
biYPelsPerMeter: 268595054
biClrUsed: 1852637184
biClrImportant: 1196585588

错误原因

1. 结构体字节对齐导致的填充字节

微软官方定义的BMP文件头是紧凑1字节对齐的:

  • BITMAPFILEHEADER固定为14字节
  • BITMAPINFOHEADER固定为40字节

但C语言编译器默认会按照结构体成员的最大对齐单位(例如DWORD是4字节)自动插入填充字节,导致自定义结构体的实际大小大于官方定义。比如BITMAPFILEHEADER中,bfType是2字节的WORD,后续bfSize是4字节的DWORD,编译器会在bfType后添加2字节填充以满足对齐要求,最终结构体大小变成16字节而非14字节。读取时会多读填充字节,导致整个数据错位,所有字段数值完全错误。

2. 未验证文件有效性

代码中未在读取后验证bfType是否为0x4D42,无法及时发现读取错误。

解决方案

1. 强制结构体1字节对齐

根据使用的编译器,给结构体添加对齐指令:

针对GCC/Clang编译器

修改bmp.h中的结构体定义,添加__attribute__((packed)):

#include <stdint.h>

typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

typedef struct __attribute__((packed))
{
    WORD   bfType;
    DWORD  bfSize;
    WORD   bfReserved1;
    WORD   bfReserved2;
    DWORD  bfOffBits;
} 
BITMAPFILEHEADER;


typedef struct __attribute__((packed))
{
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} 
BITMAPINFOHEADER;

typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} 
RGBTRIPLE;

针对MSVC编译器

使用#pragma pack指令强制1字节对齐:

#include <stdint.h>

typedef uint8_t  BYTE;
typedef uint32_t DWORD;
typedef int32_t  LONG;
typedef uint16_t WORD;

#pragma pack(push, 1)
typedef struct
{
    WORD   bfType;
    DWORD  bfSize;
    WORD   bfReserved1;
    WORD   bfReserved2;
    DWORD  bfOffBits;
} 
BITMAPFILEHEADER;


typedef struct
{
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount;
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} 
BITMAPINFOHEADER;
#pragma pack(pop)

typedef struct
{
    BYTE  rgbtBlue;
    BYTE  rgbtGreen;
    BYTE  rgbtRed;
} 
RGBTRIPLE;

2. 修正读取逻辑并添加有效性验证

修改main.c中的读取代码,确保读取正确并验证BMP文件标识:

// Public Libraries
#include <stdio.h>
#include <stdlib.h>

// Private Libraries
#include "bmp.h"

// Start
int main(int argc, char* argv[])
{
    if (argc != 4)
    {
        printf("ERROR: Command Line\n");
        printf("Usage: EXE In Out Filter\n\n");
        return 1;
    }

    // Open Original Image
    FILE* Original = fopen(argv[1], "rb");
    if (Original == NULL)
    {
        printf("ERROR: Original Image Can't Be Found\n");
        printf("Check File Name\n\n");
        return 1;
    }
    printf("Image Found!\n\n");

    // Read Bitmap File Header
    BITMAPFILEHEADER BF;
    if (fread(&BF, sizeof(BITMAPFILEHEADER), 1, Original) != 1 || BF.bfType != 0x4D42)
    {
        printf("ERROR: Not a valid BMP file\n");
        fclose(Original);
        return 1;
    }
    printf("Bitmap File Header Read Successfully\n");
    printf("bfType: 0x%X (%d)\n", BF.bfType, BF.bfType);
    printf("bfSize: %u\n", BF.bfSize);
    printf("bfOffBits: %u\n\n", BF.bfOffBits);

    // Read Bitmap Info Header
    BITMAPINFOHEADER BI;
    if (fread(&BI, sizeof(BITMAPINFOHEADER), 1, Original) != 1)
    {
        printf("ERROR: Failed to read Info Header\n");
        fclose(Original);
        return 1;
    }
    printf("Bitmap Info Header Read Successfully\n");
    printf("biSize: %u\n", BI.biSize);
    printf("biWidth: %d\n", BI.biWidth);
    printf("biHeight: %d\n", BI.biHeight);
    printf("biBitCount: %u\n", BI.biBitCount);

    fclose(Original);
    return 0;
}

验证

编译修改后的代码,运行后应该能读取到符合官方定义的数值:例如bfType会显示0x4D42(19778),其他字段数值也会与BMP文件实际信息匹配。

内容的提问来源于stack exchange,提问作者Kervan96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:00:10