C读取bmp文件

C读取bmp文件,c,bmp,C,Bmp,我正在尝试将bmp文件读入我的程序,但遇到了一些问题。读入文件后,如果我告诉它打印pBmp->header.fileSize,它会显示16,但如果我在十六进制编辑器中查看,文件大小部分有F6 7A 10 00如果我将值修改为十六进制中的正确文件大小,它会显示F6 7A F6 7A 10 00,但这会运行到resv1中,它应该始终为零。我知道这只是读取1个像素的数据。我遇到的另一个问题是,当我尝试使用while循环来读取像素,直到文件结束时,我得到了一个分割错误。我真的花了几个小时在谷歌上寻找答案

我正在尝试将bmp文件读入我的程序,但遇到了一些问题。读入文件后,如果我告诉它打印pBmp->header.fileSize,它会显示16,但如果我在十六进制编辑器中查看,文件大小部分有F6 7A 10 00如果我将值修改为十六进制中的正确文件大小,它会显示F6 7A F6 7A 10 00,但这会运行到resv1中,它应该始终为零。我知道这只是读取1个像素的数据。我遇到的另一个问题是,当我尝试使用while循环来读取像素,直到文件结束时,我得到了一个分割错误。我真的花了几个小时在谷歌上寻找答案,但我运气不太好

// The BMPHEADER structure.
typedef struct {
    byte        sigB;
    byte        sigM;
    int32_t     fileSize;
    int16_t     resv1;
    int16_t     resv2;
    int32_t     pixelOffset;
} tBmpHeader;

// The BMPINFOHEADER structure.
typedef struct {
    int32_t     size;
    int32_t     width;
    int32_t     height;
    int16_t     colorPlanes;
    int16_t     bitsPerPixel;
    byte        zeros[24];
} tBmpInfoHeader;

typedef uint8_t byte;

typedef struct {
    byte blue;
    byte green;
    byte red;
} tPixel;

// A BMP image consists of the BMPHEADER and BMPINFOHEADER structures, and the 2D pixel array.
typedef struct {
    tBmpHeader      header;
    tBmpInfoHeader  infoHeader;
    tPixel          **pixel;
} tBmp;

tPixel **BmpPixelAlloc(int pWidth, int pHeight)
{
    tPixel **pixels = (tPixel **)malloc (pHeight * sizeof(tPixel *));
    for (int row = 0; row < pHeight; ++row)
    {
        pixels[row] = (tPixel *)malloc(pWidth * sizeof(tPixel));
    }

    printf("pixelAlloc\n"); 

    return pixels;
}

pBmp->pixel = BmpPixelAlloc(pBmp->infoHeader.width, pBmp->infoHeader.height);
if(FileRead(file, &pBmp->pixel, sizeof(tPixel), 1)!=0)
{ 
    errorCode = ErrorFileRead;
}
//BMPHEADER结构。
类型定义结构{
字节sigB;
字节sigM;
int32_t文件大小;
int16_t resv1;
int16_t resv2;
int32_t像素偏移;
}tBmpHeader;
//BMPINFOHEADER结构。
类型定义结构{
int32_t大小;
int32_t宽度;
int32_t高度;
int16色平面;
int16_t Bitsperpix;
字节零[24];
}tBmpInfoHeader;
typedef uint8_t字节;
类型定义结构{
字节蓝色;
字节绿色;
字节红色;
}tPixel;
//BMP图像由BMPHEADER和BMPINFOHEADER结构以及2D像素阵列组成。
类型定义结构{
掘进机割台;
tBmpInfoHeader信息头;
t像素**像素;
}tBmp;
t像素**bmppixellalloc(内宽、内宽)
{
tPixel**像素=(tPixel**)malloc(pHeight*sizeof(tPixel*);
用于(int行=0;行pixel=bmppixellalloc(pBmp->infoHeader.width,pBmp->infoHeader.height);
if(FileRead(file,&pBmp->pixel,sizeof(tPixel),1)!=0)
{ 
errorCode=ErrorFileRead;
}

您不应该对结构使用直接I/O:仅仅因为您以与BMP头相同的顺序声明了您的
结构,就不能保证您的编译器具有端到端的字段,其间没有任何内容

编译器经常遵守平台的对齐限制,这可能会导致它们在字段之间添加填充字节,以确保大字段的起始地址对齐


您需要使用特定于编译器的魔法强制结构“打包”,或者逐字节地将I/O输入到结构中。

检查结构的填充以获取标题。您可能会发现编译器已将
struct
中的
fileSize
值与结构中的4字节边界对齐。如果您输入一些结构元素地址的debug
printf
,就可以看到这一点

我在这里使用您的
struct
运行了一个示例:

typedef struct {
    byte        sigB;
    byte        sigM;
    int32_t     fileSize;
    int16_t     resv1;
    int16_t     resv2;
    int32_t     pixelOffset;
} tBmpHeader;

tBmpHeader hdr;

int main(int argc, char *argv[])
{
    printf("%d\n", sizeof(tBmpHeader) );
    printf("%p hdr\n", &hdr);
    printf("%p sigB\n", &hdr.sigB);
    printf("%p sigM\n", &hdr.sigM);
    printf("%p fileSize\n", &hdr.fileSize);
    printf("%p resv1\n", &hdr.resv1);
    printf("%p resv2\n", &hdr.resv2);
    printf("%p pixelOffset\n", &hdr.pixelOffset);
}
对于输出:

16
0x8049788 hdr
0x8049788 sigB
0x8049789 sigM
0x804978c fileSize
0x8049790 resv1
0x8049792 resv2
0x8049794 pixelOffset
hdr
的开头和
fileSize
元素之间有一个4字节的偏移量,因此
fileSize
之前有两个字节的填充

要做的事情是一次读取一个日期项的标题。您可以通过将读取封装在单个函数中(例如,“readBmpHeader(…)”)来维护代码的某些“结构”。您可以保留
结构
,但可以分别读取每个字段。因此,您可以这样做(为了示例的清晰性,我省略了返回值检查):


你能显示完整的代码吗?你没有main,没有定义FileRead,没有显示检查头的位置。FileSize,没有显示tBmpHeader,等等。看起来你是对的,但我不知道该怎么办。啊,现在可以了,你认为这就是为什么我也有循环的问题吗?@Covertpyro你需要分割你的像素行读取,因为你单独的
malloc
地址不会在连续的内存中。是的,我以前得到的第一个像素的像素数据是正确的,但是现在头工作了,第一个像素是错误的。一位导师告诉我使用while(!feof)循环来填充数组,但这给了我一个分段错误。请参阅代码示例。您确实需要读入保留值才能通过它们。由于像素数据不连续,while(!feof(…)
可能会使您失败。因此,您将覆盖未分配的内存。此外,您不能将
tPixel
作为结构来读取。一次需要一个字节,就像标头一样。您可能需要更新代码并发布新问题。:)
FileRead(file, &pBmp->header.sigB, sizeof(byte), 1)
FileRead(file, &pBmp->header.sigB, sizeof(byte), 1)
FileRead(file, &pBmp->header.fileSize, sizeof(int32_t), 1)
FileRead(file, &pBmp->header.resv1, sizeof(int16_t), 1)
FileRead(file, &pBmp->header.resv2, sizeof(int16_t), 1)
FileRead(file, &pBmp->header.pixelOffset, sizeof(int32_t), 1)