#include <stdio.h> #include <stdint.h> #include <stdlib.h> int main() { FILE* bmp = NULL; uint32_t offset; uint8_t* temp = NULL; size_t read; unsigned int x_dim = 600,y_dim = 388; bmp = fopen("test_colour.bmp","r"); if (!bmp) return -1; /* Get the image data offset */ fseek(bmp,10,SEEK_SET); fgets((char*)&offset,4,bmp); printf("Offset = %u\n",offset); temp = malloc(3*x_dim*y_dim*sizeof(uint8_t)); if (!temp) return -1; /* Go the the position where the image data is stored */ fseek(bmp,offset,SEEK_SET); /* Copy image data to array */ printf("%u bytes requested!\n",3*x_dim*y_dim); read = fread((void*)temp,sizeof(uint8_t),3*x_dim*y_dim,bmp); printf("%Iu bytes read!\n",read); fclose(bmp); free(temp); return 0; }
我正在使用上面的代码将24位/像素BMP图像的RGB数据读取到数组.根据BMP规范,在偏移10处给出从图像数据开始的文件的开始(在BMP标题之后)的偏移.执行上面的代码时,我得到以下输出.
Offset = 54 698400 bytes requested! 33018 bytes read!
偏移输出似乎是正确的,因为文件大小是698454字节(= 698400 54).但是,fread()返回的值似乎表明不能读取整个图像数据.但是,我随后使用temp数组中的数据将RGB数据转换为灰度并再次将此数据写入BMP文件.目视检查输出图像并不表示任何错误,即看起来我实际上是在第一个地读取整个输入图像,尽管fread()似乎表示不同.
有人可以解释这种行为吗?
解决方法
(我敢打赌你在Windows上)
bmp = fopen("test_colour.bmp","r");
应该
bmp = fopen("test_colour.bmp","rb");
如果在Windows上以文本模式打开文件,则运行时会在碰到0x1a(Ctrl-Z)字节时停止读取,Windows认为该字节是文本文件的EOF标记.即使它没有按下Ctrl-Z,当Windows将CR / LF序列转换为单个LF字符时,您也会收到损坏的数据.
但是,我无法解释为什么你能从阅读的部分文件中获得一个好的图像(幸运的是?).
你可以从缓冲区渲染一个图像,因为fread()实现确实将你请求的字节数(或几乎是这样 – 数字向下舍入到某个块大小的倍数)读入缓冲区,然后它扫描缓冲区查找要转换的CR / LF序列和Ctrl-Z EOF标志.
因此,即使fread()返回33018,缓冲区实际上几乎完全用文件中的数据写入.数据不是100%正确(例如,某些CR字符可能被丢弃)或完整,但在这种情况下,它足够接近以呈现看起来像您期望的图像.
当然,这只是观察这个特定的运行时当前的行为 – 它可能并不总是在将来(甚至在今天的所有系统上)都是这样.