为什么在创建像素数据阵列时,位图图像不能被 4 整除且宽度大于 32 像素会导致错误的线扫描?

问题描述

我找到了 Alejandro Rodriguez 关于如何创建简单位图阅读器的教程。它使用 fseek 和 fread 来读取 24 位位图的头部分,找到宽度、高度和数据偏移等相关信息,并扫描位图的数据部分。 https://elcharolin.wordpress.com/2018/11/28/read-and-write-bmp-files-in-c-c/

它有效,而且重量轻,但是当位图图像大小超过 32 像素 && 包含超过 1 行 && 宽度不能被 4 整除时开始失败。为了存储效率,位图被填充为可整除为 4 个字节。当宽度可以被四整除时,问题不存在,但是...如果我给函数一个位图,其中包含一个宽度为 42 像素、高度为 2 像素的图像,第一条扫描线读取正确,但是连续的行开始拾取应该跳过的不需要的垃圾填充。

一张 42 像素的图像在每行的末尾会有 2 像素的填充。此函数适用于 24 位深度像素,这意味着每个像素 3 个字节,在本示例中总共填充 6 个字节。

从 imageFile 的标头解析的信息似乎始终正确。我已经仔细检查了 paddedRowSize 的计算值是否正确,并且它始终显示正确的理论计算值。几个星期以来,我一直在咀嚼这个问题,但无法弄清楚。我希望有人可以深入了解发生了什么问题...

在使用 fseek 和 fread 遍历文件以扫描 imageFile 的数据部分的 for 循环中,一定存在问题导致某些填充字节在被读入 currentRowPointer 时被拾取。为什么会这样?请释放你的圣人智慧。

这是有问题的函数以及细节:

#include <stdio.h>
#include <stdlib.h>
    
#define DATA_OFFSET_OFFSET 0x000A
#define WIDTH_OFFSET 0x0012
#define HEIGHT_OFFSET 0x0016
#define BITS_PER_PIXEL_OFFSET 0x001C
 
typedef unsigned int int32;
typedef short int16;
typedef unsigned char byte;
 
void ReadImage(const char *fileName,byte **pixels,int32 *width,int32 *height,int32 *bytesPerPixel)
{
        FILE *imageFile = fopen(fileName,"rb");
        int32 dataOffset;
        fseek(imageFile,DATA_OFFSET_OFFSET,SEEK_SET);
        fread(&dataOffset,4,1,imageFile);
        fseek(imageFile,WIDTH_OFFSET,SEEK_SET);
        fread(width,HEIGHT_OFFSET,SEEK_SET);
        fread(height,imageFile);
        int16 bitsPerPixel;
        fseek(imageFile,BITS_PER_PIXEL_OFFSET,SEEK_SET);
        fread(&bitsPerPixel,2,imageFile);
        *bytesPerPixel = ((int32)bitsPerPixel) / 8;
 
        
        // This is the line of line of code causing my issuesint paddedRowSize = 
        //4 * (((*width) + 3) / 4) * (*bytesPerPixel);
        //Correct line of code that makes it all work:
        int paddedRowSize = (((*width) * (*bytesPerPixel) + 3) / 4) * 4;
        int unpaddedRowSize = (*width)*(*bytesPerPixel);
        int totalSize = unpaddedRowSize*(*height);
        *pixels = (byte*)malloc(totalSize);
        int i = 0;
        byte *currentRowPointer = *pixels+((*height-1)*unpaddedRowSize);
        for (i = 0; i < *height; i++)
        {
                fseek(imageFile,dataOffset+(i*paddedRowSize),SEEK_SET);
            fread(currentRowPointer,unpaddedRowSize,imageFile);
            currentRowPointer -= unpaddedRowSize;
        }
 
        fclose(imageFile);
}

int main() {

  uint32_t width;
  uint32_t height;
  uint32_t bytesPerPixel;
  byte *pixels;

  ReadImage("please_work.bmp",&pixels,&width,&height,&bytesPerPixel);
}


解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)