【发布时间】:2022-01-15 20:24:53
【问题描述】:
我正在尝试在 C 中翻转 BMP 图像。 我遇到了一个问题,当我尝试读取 BMP 标头时一切正常并且值正确,但是当我尝试读取 DIB 标头时,我得到了除图像大小(原始位图数据)之外的所有值。我得到一个零,考虑到我在 BMP 标头中获得了文件大小,这真的很奇怪。我尝试调试代码并在线查找问题,但没有太大帮助。
这是我的代码:
#include <stdlib.h>
typedef unsigned int int32;
typedef unsigned short int int16;
typedef unsigned char char8;
struct BITMAP_header {
char name[2]; // BM
int32 size;
int garbage; // ?
int32 image_offset; //offset from where the image starts in the file
};
struct DIB_header {
int32 header_size;
int32 width;
int32 height;
int16 colorplanes;
int16 bitsperpixel;
int32 compression;
int32 image_size;
int32 temp[4];
};
struct RGB
{
char8 blue;
char8 green;
char8 red;
};
struct Image {
struct RGB** rgb;
int height;
int width;
};
struct Image readImage(FILE *fp, int height, int width) {
struct Image pic;
pic.rgb = (struct RGB**)malloc(height * sizeof(void*)); // pointer to a row of rgb data (pixels)
pic.height = height;
pic.width = width;
for (int i = height-1; i >=0 ; i--)
{
pic.rgb[i] = (struct RGB*)malloc(width * sizeof(struct RGB)); // allocating a row of pixels
fread(pic.rgb[i], width, sizeof(struct RGB), fp);
}
return pic;
}
void freeImage(struct Image pic) {
for (int i = pic.height -1; i>= 0; i--)
{
free(pic.rgb[i]);
}
free(pic.rgb);
}
void createImage(struct BITMAP_header header, struct DIB_header dibheader, struct Image pic) {
FILE* fpw = fopen("new.bmp", "w");
if (fpw == NULL) {
return 1;
}
fwrite(header.name, 2, 1, fpw);
fwrite(&header.size, 3 * sizeof(int), 1, fpw);
fwrite(&dibheader, sizeof(struct DIB_header), 1, fpw);
int count = 0;
for (int i = pic.height - 1; i >= 0; i--) {
fwrite(pic.rgb[count], pic.width, sizeof(struct RGB), fpw);
count++;
}
fclose(fpw);
}
int openbmpfile() {
FILE* fp = fopen("C:\\Users\\User\\Downloads\\MARBLES.BMP", "rb"); // read binary
if (fp == NULL) {
return 1;
}
struct BITMAP_header header;
struct DIB_header dibheader;
fread(header.name, 2, 1, fp); //BM
fread(&header.size, 3 * sizeof(int), 1, fp); // 12 bytes
printf("First two characters: %c%c\n", header.name[0], header.name[1]);
if ((header.name[0] != 'B') || (header.name[1] != 'M')) {
fclose(fp);
return 1;
}
printf("Size: %d\n", header.size);
printf("Offset: %d\n", header.image_offset);
fread(&dibheader.header_size, sizeof(struct DIB_header) , 1, fp);
printf("Header size: %d\nWidth: %d\nHeight: %d\nColor planes: %d\nBits per pixel: %d\nCompression: %d\nImage size: %d\n",
dibheader.header_size, dibheader.width, dibheader.height, dibheader.colorplanes, dibheader.bitsperpixel,
dibheader.compression, dibheader.image_size);
if ((dibheader.header_size != 40) || (dibheader.compression != 0) || (dibheader.bitsperpixel != 24)) {
fclose(fp);
return 1;
}
fseek(fp, header.image_offset, SEEK_SET);
struct Image image = readImage(fp, dibheader.height, dibheader.width);
createImage(header, dibheader, image);
fclose(fp);
freeImage(image);
return 0;
}
int main() {
openbmpfile();
}
我还尝试通过将文件头大小减小文件大小来手动写入大小,但没有奏效。
提前致谢!
【问题讨论】:
-
确保对齐正确。试试
#pragma pack(push, 1) struct ... #pragma pack(pop)。 -
请不要为特定的 32 位或 16 位整数定义自己的类型别名。使用标准的
uint16_t或uint32_t(在<stdint.h>中定义)。 -
@extratype 我试过了,没用
-
typedef unsigned int int32;让一个已经很痛苦的话题更加混乱:错位的微软遗留问题。