写入 .bmp 文件时的字节转换

3

我不确定我的电脑是否在欺骗我,还是我太累了找不到这个错误。几个小时甚至几天,我一直试图用纯C语言编写一个位图文件。我对格式和填充没有任何问题,但是内容有问题。下面是一个最小可行示例。

int main() {
    FILE *file;
    int w = 256;
    int h = 15;
    int pad = (4 - ((3 * w) % 4)) % 4;

    int filesize = 54 + (3 * w + pad) * h;

    // Create file header
    unsigned char bmpfileheader[14] = { 'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };

    bmpfileheader[2] = (unsigned char)(filesize);
    bmpfileheader[3] = (unsigned char)(filesize >> 8);
    bmpfileheader[4] = (unsigned char)(filesize >> 16);
    bmpfileheader[5] = (unsigned char)(filesize >> 24);

    // Create Info Header
    unsigned char bmpinfoheader[40] = { 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0 };

    bmpinfoheader[4] = (unsigned char)(w);
    bmpinfoheader[5] = (unsigned char)(w >> 8);
    bmpinfoheader[6] = (unsigned char)(w >> 16);
    bmpinfoheader[7] = (unsigned char)(w >> 24);
    bmpinfoheader[8] = (unsigned char)(h);
    bmpinfoheader[9] = (unsigned char)(h >> 8);
    bmpinfoheader[10] = (unsigned char)(h >> 16);
    bmpinfoheader[11] = (unsigned char)(h >> 24);

    // Create content
    // Allocate memory dynamically
    unsigned char *bmpcontent = (unsigned char *)calloc(filesize - 54, sizeof(unsigned char));

    int index;

    // map data values onto blue-red scale
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w; i++)
        {
            index = 3 * i + (3 * w + pad) * j;

            // blue
            *(bmpcontent + index) = 255-i;
        }
   }

    // Write to file
    file = fopen("test.bmp", "w");

    fwrite(bmpfileheader, sizeof(bmpfileheader[0]), 14, file);
    fwrite(bmpinfoheader, sizeof(bmpinfoheader[0]), 40, file);
    fwrite(bmpcontent, sizeof(bmpcontent[0]), filesize - 54, file);

    fclose(file);

    // free memory
    free(bmpcontent);

    return 0;
}

当我填充每个像素的“蓝色字节”时,使用“255-i”的值,我希望在每行中得到从深蓝色到黑色平滑渐变的效果。但是实际上我得到了这样的结果:example1 您可以看到,每行都存在一个字节偏移,导致每一行中的颜色发生变化,并且每隔三行出现一个像素偏移。奇怪的是,只有当我尝试将“13”写入文件时才会出现这种情况。通过16进制编辑器,我发现在下一个值进入文件之前,第二个“13”被写入文件中。当我将宽度减小到240(此时位图内容变为14至255之间)时,我得到了平滑的图片而没有任何偏移:example2 您可能会认为,在写入“13”时出现此故障是纯粹的巧合,也许确实如此。但我还尝试将数据写入文件中,其中“13”出现在非确定性位置,结果出现完全相同的效果。
我已经束手无策了,请帮帮我!!!
1个回答

3
这是因为在Windows中,值为13对应于换行符。Windows的换行符是\r\n,它对应于十六进制0D0A。由于你试图写入0D,它被视为换行符,因此它被写入文件作为0D0A。这样做是为了确保如果你只在字符串中放置\n,它将正确地被写入文件作为\r\n。因此,要解决这个问题,你应该确保以二进制模式写入文件,这可以防止这个“特性”向文件写入额外的字节。在这里查看更多信息:Strange 0x0D being added to my binary file 要使用二进制模式,只需在你的fopen中用"wb"替换"w",它就能正常工作。我刚才验证了这一点,输出是正确的。

test.bmp

在其他平台上,这个问题首先不会发生,因此此修复程序只适用于Windows平台,并且仅在该平台上需要使用。

根据fwrite man page,在mode描述下,b标志仅供兼容使用,并且在所有符合POSIX标准的系统上都会被忽略,包括Linux。该操作者未指示其所开发的平台。 - hookenz
它在Linux上原封不动地运行。由于fopen默认为二进制模式。 - hookenz
1
据我所知,@Matt OP的问题只发生在Windows上。b标志只是修复了向文件写入额外0A的问题。在Linux或Mac上,他首先就不会遇到这个问题。我更新了我的答案以澄清这一点。 - Random Davis
1
这是一个很好的答案! - hookenz

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