C语言代码创建、解析BMP格式图片

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: BMP格式的图片是众多图片格式中的一种,也称为位图数据,BMP结构也比较简单,不需要依赖任何外部库,直接手撸几十行代码即可完成解码编码,非常方便。

一、BMP图片格式介绍

BMP格式的图片是众多图片格式中的一种,也称为位图数据。通常BMP图片是没有压缩的,内部存放的是原始RGB数据,所以BMP文件本身占用的空间比较大。目前在CPU强大的设备上,最常用的格式都是JPG格式,JPG属于压缩格式,占用空间比较小,CPU强大就不在乎压缩和解压消耗的时间。在嵌入式设备上,CPU性能一般较弱,如果要显示图片,使用JPG格式就比较慢,不合适,解码消耗时间太长,造成卡顿,这时候就可以采用BMP格式的图片,不需要解码,直接按照BMP格式的结构读取RGB图形数据即可。而且BMP结构也比较简单,不需要依赖任何外部库,直接手撸几十行代码即可完成解码编码,非常方便。

典型的BMP图像文件由四部分组成:
`
1:文件头
2:图像参数
3:调色板
4:位图数据
`
现在比较常用的是24位真彩色图片,24位真彩色图片就只有3个部分,分别是: 文件头、图像参数、位图数据。这篇文章就介绍24位真彩色(RGB888)的BMP图片如何解码编码。

下面是BMP图片的存储结构:

  1. 文件头: 它包含BMP图像文件的类型、内容尺寸和起始偏移量等信息;
字节顺序 数据结构 描述
1,2 short 高8位为字母’B’,低8位为字母’M’
3,4,5,6 int 文件大小
7,8 short 保留字1
9,10 short 保留字2
11,12,13,14 int 数据部分偏移量
  1. 图像参数,它包含图像的宽、高、压缩方法,以及颜色定义等信息;
字节顺序 数据结构 描述
15,16,17,18 int 当前结构体的大小,通常是40或56
19,20,21,22 int 图像宽度(像素) 0x12~0x15是宽
23,24,25,26 int 图像高度(像素) 0x16~0x19是宽
27,28 short 这个字的值永远是1 说的是两个字节总和是1,
29,30(0x18,0x19) short 每像素占用的位数,即bpp 每个像素所需的位数,必须是1(双色)、4(16色)、8(256色)、24(真彩色)之一
31,32,33,34 int 压缩方式 0x1e~0x21,值是0表示不压缩
35,36,37,38 int 水平分辨率,pixels-per-meter
39,40,41,42 int 垂直分辨率,pixels-per-meter
43,44,45,46 int 垂直分辨率,pixels-per-meter
47,48,49,50 int 引用色彩数
51,52,53,54 int 关键色彩数
  1. 位图数据

位图数据存放的位置由文件头里的第5个参数决定(位图数据偏移量),正常情况下,位图数据就紧接着存放在图像参数的后面。

读取或者写入位图数据的注意事项:

(1) 每行的字节数必须是4的倍数,如果不是,则需要用0补齐。

(2) BMP位图数据的存放是从下到上,从左到右的。先读最后一行,读完后在读倒数第二行。

二、示例代码

2.1 读取BMP图片的参数信息

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

#pragma pack(1) //强制1个字节对齐
//BMP的文件头
struct _BMP_HEAD
{
    char type[2]; //图片的类型 "BM"
    unsigned int size; //文件大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //数据偏移字节(真实像素点数据)
};

//BMP的参数信息
struct _BMP_INFO
{
    unsigned int size; //当前结构体大小
    unsigned int w; //宽度
    unsigned int h; //高度
    unsigned short flag; //固定为1
    unsigned short bit; //像素点的位数
    unsigned int r1; //压缩方式  0
    unsigned int r2; //水平分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //关键色彩
};

int main(int argc,char **argv)
{
    if(argc!=2)
    {
        printf("传入的参数格式: ./a.out <文件名称>\n");
        return 0;
    }
    
    /*1. 打开BMP图片*/
    FILE *fp=fopen(argv[1],"rb");
    if(fp==NULL)
    {
        printf("%s 文件不存在.\n",argv[1]);
        return 0;
    }
    /*2. 读取BMP的文件头*/
    int cnt;
    struct _BMP_HEAD bmp_head;
    cnt=fread(&bmp_head,1,sizeof(struct _BMP_HEAD),fp);
    printf("成功读取:%d 字节.\n",cnt);
    printf("图片类型:%c%c\n",bmp_head.type[0],bmp_head.type[1]);
    printf("文件大小:%d\n",bmp_head.size);
    printf("数据距离文件头的偏移量:%d\n",bmp_head.seek);
    /*3. 读取文件参数信息*/
    struct _BMP_INFO bmp_info;
    cnt=fread(&bmp_info,1,sizeof(struct _BMP_INFO),fp);
    printf("成功读取:%d 字节.\n",cnt);
    printf("当前结构体大小:%d\n",bmp_info.size);
    printf("当前图片宽度:%d\n",bmp_info.w);
    printf("当前图片高度:%d\n",bmp_info.h);
    printf("当前图片颜色位数:%d\n",bmp_info.bit);
    printf("当前图片的压缩情况:%d\n",bmp_info.r1);
    /*4. 关闭文件*/
    fclose(fp);
    return 0;
}

2.2 创建一张纯色图片

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

#pragma pack(1) //强制1个字节对齐
//BMP的文件头
struct _BMP_HEAD
{
    char type[2]; //图片的类型 "BM"
    unsigned int size; //文件大小
    unsigned short  r1; //保留1
    unsigned short  r2; //保留2
    unsigned int seek; //数据偏移字节(真实像素点数据)
};

//BMP的参数信息
struct _BMP_INFO
{
    unsigned int size; //当前结构体大小
    unsigned int w; //宽度
    unsigned int h; //高度
    unsigned short flag; //固定为1
    unsigned short bit; //像素点的位数
    unsigned int r1; //压缩方式  0
    unsigned int r2; //水平分辨率
    unsigned int r3; //垂直分辨率
    unsigned int r4; //垂直分辨率
    unsigned int r5; //引用色彩
    unsigned int r6; //关键色彩
};

int main(int argc,char **argv)
{
    if(argc!=2)
    {
        printf("传入的参数格式: ./a.out <新图片的名称>\n");
        return 0;
    }
    
    /*1. 创建一张BMP图片*/
    FILE *fp=fopen(argv[1],"wb");
    if(fp==NULL)
    {
        printf("%s 文件创建失败.\n",argv[1]);
        return 0;
    }
    /*2. 创建BMP的文件头*/
    int cnt;
    struct _BMP_HEAD bmp_head;
    memset(&bmp_head,0,sizeof(struct _BMP_HEAD));
    //图片的类型
    bmp_head.type[0]='B';
    bmp_head.type[1]='M';
    //文件大小
    bmp_head.size=54+800*480*3;
    //数据偏移量
    bmp_head.seek=54;
    //写文件头
    cnt=fwrite(&bmp_head,1,sizeof(struct _BMP_HEAD),fp);
    printf("成功写入:%d 字节.\n",cnt);

    /*3. 写文件参数信息*/
    struct _BMP_INFO bmp_info;
    memset(&bmp_info,0,sizeof(struct _BMP_INFO));
    //当前结构体大小
    bmp_info.size=sizeof(struct _BMP_INFO);
    //图片的宽度和高度
    bmp_info.w=800;
    bmp_info.h=480;
    //图片的颜色位数
    bmp_info.bit=24;
    //标志位
    bmp_info.flag=1;
    //写入文件参数信息
    cnt=fwrite(&bmp_info,1,sizeof(struct _BMP_INFO),fp);
    printf("成功写入:%d 字节.\n",cnt);

    /*4. 写入位图数据*/
    int w,h;
    int c=0xFF0033; //红色
    for(h=0;h<480;h++)
    {
        for(w=0;w<800;w++)
        {
            fwrite(&c,1,3,fp);
        }
    }
    /*5. 关闭文件*/
    fclose(fp);
    return 0;
}
目录
相关文章
|
3天前
|
敏捷开发 安全 测试技术
软件测试的艺术:从代码到用户体验的全方位解析
本文将深入探讨软件测试的重要性和实施策略,通过分析不同类型的测试方法和工具,展示如何有效地提升软件质量和用户满意度。我们将从单元测试、集成测试到性能测试等多个角度出发,详细解释每种测试方法的实施步骤和最佳实践。此外,文章还将讨论如何通过持续集成和自动化测试来优化测试流程,以及如何建立有效的测试团队来应对快速变化的市场需求。通过实际案例的分析,本文旨在为读者提供一套系统而实用的软件测试策略,帮助读者在软件开发过程中做出更明智的决策。
|
11天前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
|
11天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
11天前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
|
11天前
|
存储 算法 C语言
C语言手撕实战代码_二叉排序树(二叉搜索树)_构建_删除_插入操作详解
这份二叉排序树习题集涵盖了二叉搜索树(BST)的基本操作,包括构建、查找、删除等核心功能。通过多个具体示例,如构建BST、查找节点所在层数、删除特定节点及查找小于某个关键字的所有节点等,帮助读者深入理解二叉排序树的工作原理与应用技巧。此外,还介绍了如何将一棵二叉树分解为两棵满足特定条件的BST,以及删除所有关键字小于指定值的节点等高级操作。每个题目均配有详细解释与代码实现,便于学习与实践。
|
11天前
|
存储 算法 C语言
C语言手撕实战代码_二叉树_构造二叉树_层序遍历二叉树_二叉树深度的超详细代码实现
这段代码和文本介绍了一系列二叉树相关的问题及其解决方案。其中包括根据前序和中序序列构建二叉树、通过层次遍历序列和中序序列创建二叉树、计算二叉树节点数量、叶子节点数量、度为1的节点数量、二叉树高度、特定节点子树深度、判断两棵树是否相似、将叶子节点链接成双向链表、计算算术表达式的值、判断是否为完全二叉树以及求二叉树的最大宽度等。每道题目均提供了详细的算法思路及相应的C/C++代码实现,帮助读者理解和掌握二叉树的基本操作与应用。
|
11天前
|
存储 算法 C语言
C语言手撕实战代码_循环单链表和循环双链表
本文档详细介绍了用C语言实现循环单链表和循环双链表的相关算法。包括循环单链表的建立、逆转、左移、拆分及合并等操作;以及双链表的建立、遍历、排序和循环双链表的重组。通过具体示例和代码片段,展示了每种算法的实现思路与步骤,帮助读者深入理解并掌握这些数据结构的基本操作方法。
|
11天前
|
算法 C语言 开发者
C语言手撕实战代码_单链表
本文档详细介绍了使用C语言实现单链表的各种基本操作和经典算法。内容涵盖单链表的构建、插入、查找、合并及特殊操作,如头插法和尾插法构建单链表、插入元素、查找倒数第m个节点、合并两个有序链表等。每部分均配有详细的代码示例和注释,帮助读者更好地理解和掌握单链表的编程技巧。此外,还提供了判断子链、查找公共后缀等进阶题目,适合初学者和有一定基础的开发者学习参考。
|
11天前
|
存储 算法 C语言
C语言手撕数据结构代码_顺序表_静态存储_动态存储
本文介绍了基于静态和动态存储的顺序表操作实现,涵盖创建、删除、插入、合并、求交集与差集、逆置及循环移动等常见操作。通过详细的C语言代码示例,展示了如何高效地处理顺序表数据结构的各种问题。
|
20天前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
33 1

推荐镜像

更多