Fread 返回 0,从 BMP 文件中读取像素

Posted

技术标签:

【中文标题】Fread 返回 0,从 BMP 文件中读取像素【英文标题】:Fread returning 0, reading pixels from BMP file 【发布时间】:2011-08-02 02:07:41 【问题描述】:

我正在使用此代码从 bmp 文件中获取像素。我已经阅读了前几行的标题和调色板,所以我的 FILE * 指向像素数组的开头。 它读取第一行 OK,返回 1000,这是应该的,但是当它尝试读取第二行像素时,它返回 0。

这是接收 FILE * ,读取像素行并尝试将它们保存到 bmp_type 的函数。 fila_alineada 是对齐的行大小,由于填充,必须这样做。

bool leer_pixels_8bpp(   FILE *fbmp, bmp_t *imagen,
                            const uint32_t fila_alineada,
                            const bool btopdown )
int32_t i;
long x, y;
int32_t height, width, contador;
uint8_t *ptmp;

uint8_t bufferfila[fila_alineada];

height = imagen->infoheader.height;
width  = imagen->infoheader.width;
contador  = height;

i = btopdown ? 1 : -1;
y = btopdown ? 0 : ( height - 1 );

for ( ; contador--; y += i ) /* row loop */

    /* reading row */
    if ( fread( bufferfila, sizeof( uint8_t ), fila_alineada, fbmp ) != fila_alineada )
        /* HERE is the PROBLEM, it reads ok once, but in the second loop it returns 0 */
        fprintf( stderr, "Error reading pixels row.\n" );
        return false;
    

    ptmp = bufferfila;
        /* saving pixels into bmp_t */
    for ( x = 0L; x < width; x++ )
    
        imagen->pixels[y][x] = imagen->paleta.colores[ *ptmp++ ];
    



return true;

我尝试过使用不同的 bmp!问题就在这里,还是我应该考虑查看整个代码? 希望有人可以帮助我,在此先感谢。

【问题讨论】:

您确定它返回 0,还是返回一个不同于 fila_alineada 的值?如果是这种情况,那么预计文件已到达结尾... 你能把 if(fread) 块后面的代码注释掉吗?如果指针损坏,fread 可能会失败。 大家好,感谢您的帮助,我设法让它工作了。我正在使用一个调用 leer_1bpp / 8bpp / 24bpp 的开关(3个不同的功能),具体取决于每个像素的文件位。但是我错过了开关的每种情况下的“中断”。不知道如何,但它现在正在工作。我想检查调试它以查看 fread 的值,但由于某种原因,kdbg 说在当前上下文中没有符号 fread,在我放置这些中断之前它显示了整个 fread(.........) 返回值。无论如何,它读取正常,因为我已经放了一些 ftells 来查看它读取了多少字节并且一切正常。谢谢! 【参考方案1】:

从您的代码看来,您没有阅读图像的width 是什么……而是阅读了fila_alineada 的数量。您提到 fila_alineada 是由于“填充”而对齐的行大小,但是 BMP 文件应该只在末尾有足够的填充以将每一行扩展到 4 字节的倍数......尽管这应该是一个值通过将实际像素阵列数据大小除以图像中的行数,很容易从 BITMAPINFOHEADER 计算出来。像素数组数据大小存储在标头中的偏移量 0x22 处。我确信您已经正确推断出高度在偏移量 0x16 处。所以参数fila_alineada 是非常多余的(即,您可以删除它),并且您可能错误地计算了这个值。我会简单地使用标题中的信息来计算将信息保存在图像的给定行中所需的缓冲区大小。

其次,如果您只是尝试将文件中的 BITMAPINFOHEADER 信息复制到作为一些代表性标头结构的缓冲区中,请记住,编译器可能出于字节对齐的目的填充了该结构......因此为了安全起见您不应该简单地从文件中读取整个标题然后尝试使用memcpy() 将缓冲区写入 BITMAPINFOHEADER 结构的原因。您应该从文件中逐一读取标头值,并将这些值单独存储到表示 BITMAPINFOHEADER 的任何结构中。否则,如果您执行前者,只需尝试读取文件的前 N ​​个字节,并将其复制到一个结构中,您最终可能会因为字节对齐问题而复制不正确的值,因此所有您尝试从该结构中读取的值将不代表与您的位图文件关联的值。

【讨论】:

感谢您的回答,我已经解决了上面所说的问题,无论如何我会回答您的! :) 1) 正如我所说,我正在使用 fila_alineada 来计算我每行必须读取的数量。如果我有一个 8bpp bmp,宽度为 45 像素,第一行应该有 360 位。如您所说,行大小应为 4 字节(32 位)。因为 360 不是 32 的倍数,所以我要做的是: bitsperrow = width * bitsperpixel if (bitsperrow % 32) bitsperrow += 32 - ( bitsperrow % 32 ) 我所做的是:bitsperrow = width * bitsperpixel; if (bitsperrow % 32) bitsperrow += 32 - ( bitsperrow % 32 ) 然后我将 bitsperrow 除以 8 以获得行上的字节数 (fila_alineada)。它只有3行!关于 2),是的,我知道,infoheader 不是对齐的结构,我必须先读取 bmp 的幻数,然后再读取其他的,它工作正常。阅读它们后,我用 printf 打印了两个标题并且它们有效!再次感谢:) 您的计算看起来不错,但只是说,您不必跳过那些圈...只需使用 BITMAPINFOHEADER 字段偏移量 0x22 即可获取像素数据的字节数,然后除以通过像素行数...这将为您提供每行的字节数,而无需计算任何填充偏移量。 你说得对,我没想到...再次感谢,我会给你积分或其他东西,但我是新来的哈哈。

以上是关于Fread 返回 0,从 BMP 文件中读取像素的主要内容,如果未能解决你的问题,请参考以下文章

C++ - 从 BMP 文件中读取每个像素的位数

使用 fread() 读取 BMP 的文件头

如何用c语言printf输出bmp图片的像素信息。

读取android中图像的所有像素块的准确颜色

C++:使用 fread 和 fwrite 循环复制 bmp,导致输出 bmp 填充输入 bmp 中第一个颜色

C: fread() 在读取 .raw 文件时总是返回 0