#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()
似乎表示不同。
有人可以解释这种行为吗?
答案 0 :(得分:20)
(我敢打赌你在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字符可能被丢弃)或完整,但在这种情况下,它足够接近以呈现看起来像您期望的图像。
当然,这只是观察这个特定的运行时当前的行为 - 它可能并不总是在将来表现出来(甚至在今天的所有系统上)。