【问题标题】:How to read BMP file in C?如何在 C 中读取 BMP 文件?
【发布时间】:2021-07-06 05:04:15
【问题描述】:

我正在尝试查阅 BMP 的基本信息。为此,我为文件头构建了一个结构,为图像头构建了另一个结构。参考 BMP 值表(http://www.dragonwins.com/domains/getteched/bmp/bmpfileformat.htm),我读取了值并按照指定进行了验证。但是只有bfType读取正确,其他值填写错误信息。 在我的电脑上,sizeof(int) = 4

结构:

typedef struct BmpFileHeader {
   char bfType[2];
   unsigned int bfSize;
   unsigned short int __bfReserved1;
   unsigned short int __bfReserved2;
   unsigned long int bfOffBits;
} BMPFILEHEADER;

typedef struct BmpImageHeader {
   unsigned int biSize;
   int biWidth;
   int biHeight;
   unsigned short int biPlanes;
   unsigned short int biBitCount;
   unsigned int biCompression;
   unsigned int biSizeImage;
   int biXPelsPerMeter;
   int biYPelPerMeter;
   unsigned int biClrUsed;
   unsigned int biClrImportant;  
} BMPIMAGEHEADER;

打印功能:

void printFileHeader(BMPFILEHEADER fileHeader) {
   printf("\nType: %c%c.\n", fileHeader.bfType[0],fileHeader.bfType[1]);
   printf("Size: %d.\n", fileHeader.bfSize);
   printf("Verify (Must be 0 0): %d %d.\n");
   printf("Offset : %d.\n", fileHeader.bfOffBits);
};

void printImageHeader(BMPIMAGEHEADER imageHeader) {
   printf("\nSize of header: %d.\n", imageHeader.biSize);
   printf("Width: %d.\n", imageHeader.biWidth);
   printf("Height: %d.\n", imageHeader.biHeight);
   printf("Color Planes: %d.\n", imageHeader.biPlanes);
   printf("Bits per Pixel: %d.\n", imageHeader.biBitCount);
   printf("Compression: %d.\n", imageHeader.biCompression);
   printf("Image size: %d.\n", imageHeader.biSizeImage);
   printf("Preferred resolution in pixels per meter (X-Y): %d-%d.\n", imageHeader.biXPelsPerMeter, imageHeader.biYPelPerMeter);
   printf("Number color map: %d.\n", imageHeader.biClrUsed);
   printf("Number of significant colors: %d.\n", imageHeader.biClrImportant);
}

主要功能:

int main() {
   FILE *image;
   BMPFILEHEADER header;
   BMPIMAGEHEADER imageHeader;

   image = fopen("test.bmp", "rb");

   if(!image) {
      printf("Could not open the file %s.", "test.bmp");
      fclose(image);
      return 1;
   }

   fread(&header, sizeof(BMPFILEHEADER), 1,image);
   
   printf("File header information:");
   printFileHeader(header);

   if(header.bfType[0] != 'B' || header.bfType[1] != 'M') {
      printf("The file %s is not a valid BMP.", "test.bmp");
      return 1;
   }

   fread(&imageHeader, sizeof(BMPIMAGEHEADER), 1, image);
   
   printf("\nImage header information:");
   printImageHeader(imageHeader);

   if(imageHeader.biSize != 40 || imageHeader.biCompression != 0 || imageHeader.biBitCount != 24) {
      printf("The file %s is not a valid BMP.", "test.bmp");
      fclose(image);
      return 1;
   }

   fclose(image);
   return 0;
}

【问题讨论】:

  • 您的编译器上的sizeof(BMPFILEHEADER)sizeof(BMPIMAGEHEADER) 是什么?根据您发布的链接,它应该是 14 和 40。如果它不同,那么您可能有 struct 对齐或打包问题,这需要编译器特定的补救措施。在这种情况下,请指定您使用的编译器。
  • 结构体的大小没问题。我将 bfOffBits 更改为仅 int。
  • 我已恢复您最近的编辑,因为修复代码中的错误会使整个问题(以及答案)无效。但是,如果您想通过指出错误来回答自己的问题,请随时这样做。有关详细信息,请参阅此官方帮助页面:Can I answer my own question?

标签: c image file fread bmp


【解决方案1】:

结构打包和对齐填充是实现定义的,字节顺序是平台定义的。

如果您的平台的字节顺序与为 BMP(小端序)定义的字节顺序相同,那么您可以使用工具链支持的任何编译器扩展来进行结构打包。例如在 GCC 中:

typedef struct BmpFileHeader {
   char bfType[2];
   unsigned int bfSize;
   unsigned short int __bfReserved1;
   unsigned short int __bfReserved2;
   unsigned long int bfOffBits;
} __attribute__ ((packed)) BMPFILEHEADER; 

typedef struct BmpImageHeader {
   unsigned int biSize;
   int biWidth;
   int biHeight;
   unsigned short int biPlanes;
   unsigned short int biBitCount;
   unsigned int biCompression;
   unsigned int biSizeImage;
   int biXPelsPerMeter;
   int biYPelPerMeter;
   unsigned int biClrUsed;
   unsigned int biClrImportant;  
} __attribute__ ((packed)) BMPIMAGEHEADER;

对于整数值,BMP 的字节顺序是 little-endian;所以对于 x86 和大多数 ARM 平台,您可能不需要担心字节顺序。像素字节顺序不太直接。

但是,对于真正可移植的解决方案,您必须逐字节读取数据并单独加载结构的每个成员 - 即所谓的反序列化

您还可以通过使用stdint.h 数据类型uint8_tuint16_tuint32_tint32_t 等来确保符合标头结构。

【讨论】:

  • 谢谢!这解决了我的问题。我还需要将 bfOffBits 中的 long int 更改为仅 int。
  • @leandror :这正是我推荐使用 stdint.h 类型的原因。 long int 例如在 64 位 Linux、32 位 Linux 和 32/64 位 Windows 之间的宽度不同。
猜你喜欢
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
  • 2012-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多