从BMP文件读取像素时,如果Fread返回0

3
我正在使用以下代码从bmp文件中获取像素。已经在之前的代码中读取了头和调色板,所以我的FILE *指向像素数组的开头。 它可以正确读取第一行,并返回值为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”不同的值?如果是这种情况,则这是预期的,因为已经到达了文件结尾... - Fred
你能否在 if(fread) 块后面注释掉代码?如果指针被破坏,fread 可能会失败。 - Shash316
大家好,感谢你们的帮助,我已经成功让它工作了。我使用了一个开关调用 leer_1bpp / 8bpp / 24bpp(三个不同的函数),具体取决于文件每像素的位数。但是我在开关的每个情况下都缺少了'breaks'。 不知道为什么,但现在它可以工作了。 我想通过调试来检查fread的值,但由于某种原因kdbg在当前上下文中没有符号fread,而在我加入这些breaks之前,它显示了整个fread(.........)返回值。无论如何,它正在正确读取,因为我已经放置了一些ftells来查看它读取了多少字节,一切都很顺利。谢谢! - nitrnitr
1个回答

2
从你的代码中看来,似乎你没有读取图片的width,而是在读取fila_alineada的数量。你提到fila_alineada是由于“padding”而对齐的行大小,但BMP文件应该只有足够的填充来将每一行扩展到4字节的倍数...这个值可以通过将实际像素数组数据大小除以图像中的行数来轻松计算。像素数组数据大小存储在头部的偏移量0x22处。高度,正如您已经正确推断的那样,位于偏移量0x16处。因此,参数fila_alineada几乎是多余的(即,您可以删除它),并且您可能正在错误地计算此值。我建议您仅使用头部中的信息来计算保存图像给定行中信息所需的缓冲区的大小。
其次,如果您仅尝试从文件中复制BITMAPINFOHEADER信息到某个代表性的头结构体中,请记住编译器可能会为字节对齐目的而填充结构体...因此出于安全考虑,您不应该简单地从文件中读取整个头部,然后尝试使用memcpy()将缓冲区写入BITMAPINFOHEADER结构体中。您应该逐个从文件中读取头部值,并将这些值单独存储到任何表示BITMAPINFOHEADER的结构中。否则,如果您采用前者,仅尝试读取文件的前N个字节,并将其复制到一个结构体中,由于字节对齐问题,您可能会复制不正确的值,因此您尝试从该结构体中读回的所有值都将不代表与位图文件相关联的值。

谢谢回答,我已经按照我之前所说的解决了这个问题,不过还是会回答你! :)1)我正在使用fila_alineada来计算每行需要读取的数量,就像我之前所说的那样。如果我有一个宽度为45像素的8bpp bmp,则第一行应该有360位。正如您所说,行大小应为4字节(32位)。由于360不是32的倍数,我所做的是:bitsperrow = width * bitsperpixel if (bitsperrow % 32) bitsperrow += 32 - ( bitsperrow % 32 ) - nitrnitr
我所做的是:bitsperrow = width * bitsperpixel; 如果(bitsperrow % 32) { bitsperrow += 32 - ( bitsperrow % 32 ) } 然后我将bitsperrow除以8,以获取行上的字节数(fila_alineada)。 只需要3行代码! 关于第2点,是的,我知道信息头不是对齐的结构,我必须先读取bmp的幻数,然后再读取其他内容,这样就可以正常工作了。 我在读取它们后使用printf打印了两个标头,它们都有效! 再次感谢:) - nitrnitr
你的计算看起来很好,但是只是说一下,你不必跳过那些麻烦的步骤...只需使用BITMAPINFOHEADER字段偏移0x22来获取像素数据的字节数,然后除以像素行数...这将给出每行的字节数,而无需计算任何填充偏移量。 - Jason
你说得对,我没有想到...再次感谢,我会给你点赞或其他什么的,但我在这里还是新手哈哈。 - nitrnitr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接