文件头信息的格式定义可以参考这里,读取文件信息有两种方式,第一种方式是定义一个字符串,使用read函数将图像信息读取到字符串中,然后自己去提取想要的数据。这种方法需要我们提前知道图像文件头的格式定义,很麻烦且容易出错,适合初学阶段使用,熟悉了之后即可过渡使用第二种方式;第二种方式是使用bmp结构体,结构体可以自行定义,也可以去网上找,百度一大堆。定义结构体变量存储文件头信息这种方式的优点是格式清晰,代码可读性好。
我找的结构体如下,原文链接在这。
//文件头结构体
typedef struct
{
unsigned char bfType[2]; //文件类型
unsigned long bfSize; //位图大小
unsigned short bfReserved1; //位0
unsigned short bfReserved2; //位0
unsigned long bfOffBits; //到数据偏移量
} BitMapFileHeader;
函数如下:
/*
*函数功能:解析bmp图片
*参数列表:path:要解析的图片的pathname
*返回值 :错误时返回-1,解析正确返回0
*/
int bmp_analyze(unsigned char *path)
{
int fd = -1;
BitMapFileHeader fHeader;
//打开bmp图片
fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open %s error.\n", path);
return -1;
}
//读取文件头信息
read(fd, &fHeader, sizeof(fHeader));
printf("bfSize:%ld\n", fHeader.bfSize);
printf("bfOffBits:%ld\n", fHeader.bfOffBits);
//关闭打开的文件
close(fd);
return 0;
}
执行结果如下:
显示bfSize(文件大小)为28,这显然是不对的。根据WinHex查看图片可以看到,实际数据为0x36 0x20 0x1C 0x00,而在BMP文件中数据存储方式为小端模式(低地址存放低字节),因此实际bfSize为1843254(0x1C2036
)个字节。
下面开始查找问题。
将读取到的信息都打印出来,分析原始数据。
int bmp_analyze(unsigned char *path)
{
int fd = -1, i;
BitMapFileHeader fHeader;
//打开bmp图片
fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open %s error.\n", path);
return -1;
}
//读取文件头信息
read(fd, &fHeader, sizeof(fHeader));
printf("bfSize:%ld\n", fHeader.bfSize);
printf("bfOffBits:%ld\n", fHeader.bfOffBits);
//将读取到的信息打印出来
for (i = 0; i < sizeof(fHeader); i++) {
printf("%x ", *((unsigned char *)&fHeader + i));
}
printf("\n");
//关闭打开的文件
close(fd);
return 0;
}
这时就可以看到读取的结果,数据大小为16字节!而结构体中的数据大小为14字节!这就牵扯到字节对齐问题了,其实好早以前就知道这个概念,单纯的以为就是以牺牲空间为代价去提高处理器存取效率,没想到会对上层有影响!把结构体变量当成字符串去存储数据的方法也是我第一次使用,然后就遇到了这个问题。
这里扯一下字节对齐,以前也看了好多资料,总结一下就四点:
解决办法:取消字节对齐。
取消字节对齐的两种方法:
#pragma pack ()
__attribute__((packed))
结构体定义于是被修改为了:
typedef struct
{
unsigned char bfType[2]; //文件类型
unsigned long bfSize; //位图大小
unsigned short bfReserved1; //位0
unsigned short bfReserved2; //位0
unsigned long bfOffBits; //到数据偏移量
} __attribute__((packed)) BitMapFileHeader;
原链接本来默认就取消了字节对齐,但是一开始并不了解具体深意,于是就被我删掉了,看来还是得加上。
调试结果如下图:
到这里就显示正常了,1843254就是0x1C2036,还有一个问题是伪指令#pragma pack ()没效果,不知道是gcc的问题还是什么其他的问题。