从 bmp 文件的头部读取

Posted

技术标签:

【中文标题】从 bmp 文件的头部读取【英文标题】:Reading from the header of a bmp file 【发布时间】:2020-04-12 20:55:19 【问题描述】:

我正在编写一个程序来读取 bmp 标头。我编写了一些在main 中工作的代码。如何将此代码实现为自己的功能,然后将其实现到 main 上?

这是整个代码:

#include <stdio.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <stdin.h> 

struct bmp_header  
    uint16_t type; 
    uint32_t size; 
    uint16_t reserved1;     
    uint16_t reserved2;    
    uint32_t offset;        
    uint32_t dib_size;  
    uint32_t width;         
    uint32_t height;        
    uint16_t planes;       
    uint16_t bpp;            
    uint32_t compression;    
    uint32_t image_size;    
    uint32_t x_ppm;         
    uint32_t y_ppm;          
    uint32_t num_colors;     
    uint32_t important_colors; 
; 


void read_bmp(FILE *BMPFile,struct bmp_header* Header)   
    fread(&(Header->type), 2, 1, BMPFile); 
    fread(&(Header->size),4,1,BMPFile); 
    fread(&(Header->reserved1),2,1,BMPFile); 
    fread(&(Header->reserverd2),2,1,BMPFile); 
    fread(&(Header->offset),4,1,BMPFile); 
    fread(&(Header->dib_size),4,1,BMPFile); 
    fread(&(Header->width),4,1,BMPFile); 
    fread(&(Header->height),4,1,BMPFile); 
    fread(&(Header->planes),2,1,BMPFile); 
    fread(&(Header->bpp),2,1,BMPFile); 
    fread(&(Header->compression),4,1,BMPFile); 
    fread(&(Header->image_size),4,1,BMPFile); 
    fread(&(Header->x_ppm),4,1,BMPFile); 
    fread(&(Header->y_pp),4,1,BMPFile); 
    fread(&(Header->num_colors),4,1,BMPFile); 
    fread(&(Header->important_colors),4,1,BMPFile); 
 

int main()  
    FILE *BMPFile = fopen("image.bmp","rb"); 
    if(BMPFile == NULL) 
     
        return; 
     

    struct bmp_header* Header; 
    read_bmp(BMPFile,Header); 
    fclose(BMPFile); 

    return 0; 
 

main 中具有所有读取操作的程序版本的相关部分,按预期工作,报告如下

int main( void )

    FILE *BMPFile = fopen ("lenna.bmp", "rb");

    if (BMPFile == NULL)
    
        return 0;
    

    struct bmp_header Header;

    memset(&Header, 0, sizeof(Header));

    fread(&Header.type, 2, 1, BMPFile);
    fread(&Header.size),4,1,BMPFile); 
    fread(&Header.reserved1),2,1,BMPFile); 
    fread(&Header.reserverd2),2,1,BMPFile); 
    fread(&Header.offset),4,1,BMPFile); 
    fread(&Header.dib_size),4,1,BMPFile); 
    fread(&Header.width),4,1,BMPFile); 
    fread(&Header.height),4,1,BMPFile); 
    fread(&Header.planes),2,1,BMPFile); 
    fread(&Header.bpp),2,1,BMPFile); 
    fread(&Header.compression),4,1,BMPFile); 
    fread(&Header.image_size),4,1,BMPFile); 
    fread(&Header.x_ppm),4,1,BMPFile); 
    fread(&Header.y_pp),4,1,BMPFile); 
    fread(&Header.num_colors),4,1,BMPFile); 
    fread(&Header.important_colors),4,1,BMPFile);

    /* Header fields print section */
    /* ...                         */

【问题讨论】:

我是否正确理解您有工作代码,并且您希望您的工作代码看起来更像您发布的(但工作)?如果是这样,您可以发布工作代码吗?编辑: struct bmp_header 是一个指针,但它从来没有给任何内存使用。所以这是一个问题。 在堆栈中定义了工作函数bmp_header,然后memsetd 为0,其字段地址直接传递给fread。现在你创建了一个指针,但你没有分配内存来指向。 您删除了包含原始代码的页面。没有它,问题是不完整的,我的回答没有意义。我建议进行编辑,将我昨天复制的部分插入您来源的答案中。 【参考方案1】:

每当工作代码停止工作时,关注两个代码版本之间的变化是很有用的。那么,为什么您的原始代码可以正常工作?它看起来像这样:

int main( void )

    FILE *BMPFile = fopen ("lenna.bmp", "rb");

    if (BMPFile == NULL)
    
        return 0;
    

    struct bmp_header Header;

    memset(&Header, 0, sizeof(Header));

    fread(&Header.type, 2, 1, BMPFile);
    ...

    您在 main 的堆栈(作为局部变量)中声明 Header,类型为 struct bmp_header通过这种方式,结构将在所有程序的生命周期内确定分配。 你memset它到0 您将Header 的字段地址直接传递给fread

在新版本的程序中,你有一个函数定义为

void read_bmp(FILE *BMPFile,struct bmp_header* Header);

所以你需要一个指向struct bmp_header 的指针来传递给它。因此,您声明

struct bmp_header* 标头;

并致电read_bmp(BMPFile,Header);

与工作版本有什么不同?嗯,指针!向编译器声明一个指针,它包含一个地址,在本例中是read_bmp() 所需的结构的地址。

但是你从不告诉编译器地址是什么,这样read_bmp() 内的freads 将写入随机位置,从而导致分段错误。


做什么

您需要将一个有效struct bmp_header 地址传递给read_bmp(),并且您有两个选项

    您可以像以前一样在堆栈中分配Header,并通过&amp; 运算符将其地址传递给read_bmp()。这应该是您的第一次尝试,因为它与您的工作解决方案非常相似。
    struct bmp_header Header;

    read_bmp(BMPFile, &Header);
    您可以将Header 声明为指针,但您需要通过malloc 动态分配其内存:
    struct bmp_header * Header = malloc(sizeof(struct bmp_header));

    read_bmp(BMPFile, Header);

【讨论】:

【参考方案2】:

你必须创建 struct bmp_header* 类型的函数。接下来在您的函数中创建 struct bmp_header 指针并为返回的引用分配内存(标头大小 == 54B)。

【讨论】:

虽然文件使用了 54 字节的头部,但 struct bmp_header 由于填充,不一定包含 54 字节。使用sizeof(struct bmp_header) 比使用硬编码 54 更好。

以上是关于从 bmp 文件的头部读取的主要内容,如果未能解决你的问题,请参考以下文章

从 bmp 文件中读取 RGB 像素

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

读取和写入 BMP 文件

用标准c读取某bmp文件的长宽及象素等信息需要哪些函数?

读bmp图片:头文件为66字节。。。怎么用c语言来读取数据啊,网上的代码我看不懂。新手,希望能写明白些

如何在c语言 读取BMP图片的信息