开发过程中有时候需要解析bmp数据,下面先简单介绍bmp数据组成,后面附上C语言读取和存储bmp格式图片代码。

典型的位图文件格式通常包含下面几个数据块:

  1. BMP文件头:保存位图文件的总体信息。
  2. 位图信息头:保存位图图像的详细信息。位图信息:保存位图图像的详细信息。
  3. 调色板:保存所用颜色的定义。调色板:保存所用颜色的定义。
  4. 位图数据:保存一个又一个像素的实际图像。位图数据:保存一个又一个像素的实际图像。

1. BMP文件头(14字节)

BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。

这部分是识别信息,典型的应用程序会首先普通读取这部分数据以确保的确是位图文件并且没有损坏。

位图头结构体定义如下:

typedef struct
{uint16_t type;  //位图文件的类型,必须为BM(1-2字节)uint32_t size;  //位图文件的大小,以字节为单位(3-6字节,低位在前)uint16_t reserved1;  //位图文件保留字,必须为0(7-8字节)uint16_t reserved2;  //位图文件保留字,必须为0(9-10字节)uint32_t off_bits;  //位图数据位置的地址偏移,即起始位置,以相对于位图(11-14字节,低位在前)
}__attribute__ ((packed)) bmp_file_header_t;

2. 位图信息头(40字节)

这部分告诉应用程序图像的详细信息,在屏幕上显示图像将会使用这些信息,它从文件的第15个字节开始。

位图信息头结构体定义如下:

typedef struct
{uint32_t size;int32_t width;int32_t height;uint16_t planes;uint16_t bit_count;uint32_t compression;uint32_t size_image;uint32_t x_pels_permeter;uint32_t y_pels_permeter;uint32_t clr_used;uint32_t clr_important;
} bmp_info_header_t;

结构体变量解析如下:

  • uint32_t size; 15-18字节:定义以下用来描述影像的区块(BitmapInfoHeader)的大小,即本结构所占用字节数,它的值是:40
  • int32_t width; 19-22字节:位图宽度,以像素为单位。
  • int32_t height; 23-26字节:位图高度,以像素为单位。
  • uint16_t planes; 27-28字节:保存所用彩色位面的个数。不经常使用。
  • uint16_t bit_count; 29-30字节:保存每个像素的位数,它是图像的颜色深度。常用值是1(双色灰阶)、4(16色灰阶)、8(256色灰阶)和24(彩色)。
  • uint32_t compression; 31-34字节:定义所用的压缩算法。允许的值是0、1、2、3、4、5。
    • 0 - 没有压缩(也用BI_RGB表示)
    • 1 - 行程长度编码 8位/像素(也用BI_RLE8表示)
    • 2 - 行程长度编码4位/像素(也用BI_RLE4表示)
    • 3 - Bit field(也用BI_BITFIELDS表示)
    • 4 - JPEG图像(也用BI_JPEG表示)
    • 5 - PNG图像(也用BI_PNG表示)
  • uint32_t size_image; 35-38字节:位图的大小(其中包含了为了补齐行数是4的倍数而添加的空字节),以字节为单位。这是原始位图数据的大小,不要与文件大小混淆。
  • uint32_t x_pels_permeter; 39-42字节:位图水平分辨率,每米像素数。
  • uint32_t y_pels_permeter; 43-46字节:位图垂直分辨率,每米像素数。
  • uint32_t clr_used; 47-50字节:位图实际使用的颜色表中的颜色数。
  • uint32_t clr_important; 51-54字节:位图显示过程中重要的颜色数,当每个颜色都重要时这个值与颜色数目(clr_used)相等。

3. 调色板

BMP调色板结构体定义如下:

typedef struct _tagRGBQUAD
{BYTE  rgbBlue;       //指定蓝色强度
BYTE  rgbGreen;      //指定绿色强度
BYTE  rgbRed;        //指定红色强度
BYTE  rgbReserved;  //保留,设置为0
} RGBQUAD;

1,4,8位图像才会使用调色板数据,16,24,32位图像不需要调色板数据,即调色板最多只需要256项(索引0 - 255)。

颜色表的大小根据所使用的颜色模式而定:2色图像为8字节;16色图像位64字节;256色图像为1024字节。其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(32位位图的透明度值,一般不需要)。即首先4字节表示颜色号1的颜色,接下来表示颜色号2的颜色,依此类推。

颜色表中RGBQUAD结构数据的个数有biBitCount来确定,当biBitCount=1,4,8时,分别有2,16,256个表项:

  • 当biBitCount=1时,为2色图像,BMP位图中有2个数据结构RGBQUAD,一个调色板占用4字节数据,所以2色图像的调色板长度为2*4为8字节。
  • 当biBitCount=4时,为16色图像,BMP位图中有16个数据结构RGBQUAD,一个调色板占用4字节数据,所以16像的调色板长度为16*4为64字节。
  • 当biBitCount=8时,为256色图像,BMP位图中有256个数据结构RGBQUAD,一个调色板占用4字节数据,所以256色图像的调色板长度为256*4为1024字节。
  • 当biBitCount=16,24或32时,没有颜色表。

4. 位图数据

位图数据记录了位图的每一个像素值。
像素是从下到上、从左到右保存的
每个像素使用一个或者多个字节表示。
如果一个图像水平线的字节数不是4的倍数,这行就使用空字节补齐,通常是ASCII码0

例如:

  1. 一张5 * 6的图片,有30个pixels,因为列数6不是4的倍数,所以会显示成:
    xxxxxx00 xxxxxx00 xxxxxx00 xxxxxx00 xxxxxx00
    其中,x代表调色盘的编号,0代表补齐的空字节

  2. 一张4 * 4的图片,有16个pixels,因为列数刚好是4的倍数,所以会显示成:
    xxxx xxxx xxxx xxxx

C语言读取和存储bmp示例代码

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>typedef struct
{uint16_t type;uint32_t size;uint16_t reserved1;uint16_t reserved2;uint32_t off_bits;
}__attribute__ ((packed)) bmp_file_header_t;typedef struct
{uint32_t size;int32_t width;int32_t height;uint16_t planes;uint16_t bit_count;uint32_t compression;uint32_t size_image;uint32_t x_pels_permeter;uint32_t y_pels_permeter;uint32_t clr_used;uint32_t clr_important;
} bmp_info_header_t;static bmp_file_header_t s_bmp_file_header = { 0x4d42, 0, 0, 0, 0 };
static bmp_info_header_t s_bmp_info_header = { 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0 };static uint8_t s_bmpdata[200 * 200] = { 0 };
static uint32_t s_bmp_col = 0;
static uint32_t s_bmp_row = 0;
char in_file_path[256] = "in.bmp";
char out_file_path[256] = "out.bmp";int32_t bmp_file_to_image(const char *file_path, uint8_t *image, uint32_t *col, uint32_t *row)
{FILE *file = NULL;uint32_t line_width = 0;uint32_t width = 0;uint32_t height = 0;int32_t err = 0;uint8_t buf[200 * 200] = { 0 };char temp[2048] = { 0 };int i = 0;do {if (NULL == file_path || NULL == image){err = -1;break;}printf("[%s] file_path = %s\n", __func__, file_path);file = fopen(file_path, "rb");if (NULL == file){err = -1;break;}fread(&s_bmp_file_header, sizeof(s_bmp_file_header), 1, file);fread(&s_bmp_info_header, sizeof(s_bmp_info_header), 1, file);fread(temp, 4*256, 1, file);width = s_bmp_info_header.width;height = s_bmp_info_header.height;*col = width;*row = height;line_width = (width + 3) / 4 * 4;printf("[%s] line_width = %d, width = %d, height = %d\n", __func__, line_width, width, height);for (i = height - 1; i >= 0; i--){if (line_width == width){fread(buf + i * width, width, 1, file);}else if (line_width > width){fread(buf + i * width, width, 1, file);fread(temp, line_width-width, 1, file);}}memcpy(image, buf, width * height);} while (0);if (file != NULL){fclose(file);}return err;
}int32_t dump_image_to_bmp_file(const char *file_path, uint8_t *image, uint32_t width, uint32_t height)
{FILE *file = NULL;int32_t err = 0;do {if (NULL == file_path || NULL == image){err = -1;break;}uint32_t line_width = (width + 3) / 4 * 4;s_bmp_file_header.off_bits = sizeof(bmp_file_header_t) + sizeof(bmp_info_header_t)+ 4 * 256;s_bmp_file_header.size = s_bmp_file_header.off_bits + line_width * height;s_bmp_info_header.size = sizeof(bmp_info_header_t);s_bmp_info_header.width = width;s_bmp_info_header.height = height;s_bmp_info_header.size_image = line_width * height;printf("[%s] line_width = %d, width = %d, height = %d\n", __func__, line_width, width, height);file = fopen(file_path, "wb");if (NULL == file){err = -1;break;}fwrite(&s_bmp_file_header.type, 1, sizeof(s_bmp_file_header.type), file);fwrite(&s_bmp_file_header.size, 1, sizeof(s_bmp_file_header.size), file);fwrite(&s_bmp_file_header.reserved1, 1, sizeof(s_bmp_file_header.reserved1), file);fwrite(&s_bmp_file_header.reserved2, 1, sizeof(s_bmp_file_header.reserved2), file);fwrite(&s_bmp_file_header.off_bits, 1, sizeof(s_bmp_file_header.off_bits), file);fwrite(&s_bmp_info_header, 1, sizeof(bmp_info_header_t), file);uint8_t alpha = 0;int32_t i;for (i = 0; i < 256; i++){fwrite(&i, 1, sizeof(uint8_t), file);fwrite(&i, 1, sizeof(uint8_t), file);fwrite(&i, 1, sizeof(uint8_t), file);fwrite(&alpha, 1, sizeof(uint8_t), file);}for (i = height - 1; i >= 0; i--){fwrite(image + i * width, 1, width, file);if (line_width > width){uint8_t line_align[4] = { 0 };fwrite(line_align, 1, line_width - width, file);}}fflush(file);} while (0);if (file != NULL){fclose(file);}return err;
}int main()
{int32_t err = 0;err = bmp_file_to_image(in_file_path, s_bmpdata, &s_bmp_col, &s_bmp_row);if (err != 0){return -1;}printf("[%s] s_bmp_col = %d, s_bmp_row = %d\n", __func__, s_bmp_col, s_bmp_row);dump_image_to_bmp_file(out_file_path, s_bmpdata, s_bmp_col, s_bmp_row);return 0;
}

C语言读取和存储bmp格式图片相关推荐

  1. MATLAB编程:简易读取分割存储 tif 格式图片

    MATLAB编程:简易读取分割存储 tif 格式图片 前言 一.介绍 二.MATLAB实现 三.总结 前言   本博主使用的MATLAB版本是2020b,这个版本可以使用许多有趣的扩展APP,本节将会 ...

  2. C语言实现RGB888转BMP格式图片功能

    1.bmp格式介绍 bmp格式图片里实际存储的也是RGB原始数据,可以分为8bit.16bit.24bit.32bit的bmp格式,也就是指bmp图片中保存的RGB是用8bit.16bit.24bit ...

  3. python 存储bmp格式图片

    import numpy as np from PIL import Image #读入数据arr,此处为手动设置 arr = np.array([[0,0,0,0,0],[0,0,0,0,0],[1 ...

  4. C语言读取BMP格式图片

    C语言读取BMP格式图片 BMP 维基百科,自由的百科全书 汉漢▼ 位图 扩展名 .bmp 开发者 Microsoft 格式 图像文件格式  本文介绍的是一种图像文件格式. 关于Unicode的第1区 ...

  5. c语言实现pdf显示图片,C语言读取BMP格式图片.pdf

    C语言读取BMP格式图片 C 语言读取BMP 格式图片 以下摘自维基百科,自由的百科全书 BMP 取自位图BitMaP 的缩写,也称为DIB (与设备无关的位图)是微软视窗图形 子系统(Graphic ...

  6. c语言将两幅bmp格式图片拼接图片

    要将两幅 BMP 格式图片拼接在一起,你需要先打开这两幅图片并读取它们的像素数据.然后,你可以使用每幅图片的像素数据来创建一个新的图像,将两幅图片的像素数据拼接在一起.最后,你可以使用 BMP 文件格 ...

  7. 将BMP 格式图片转换为 JPEG 格式【c语言】

    源码链接: https://blog.csdn.net/qq_44394952/article/details/122587475?spm=1001.2014.3001.5502. 一.任务及目标 利 ...

  8. 将BMP 格式图片转换为 JPEG 格式【c语言源码】

    原理及代码讲解链接: https://blog.csdn.net/qq_44394952/article/details/122587306?spm=1001.2014.3001.5502. 主函数m ...

  9. 【数字图像处理】一.MFC详解显示BMP格式图片

    本文主要是讲述<数字图像处理>系列栏目中的第一篇文章.主要详细介绍了BMP图片格式,同时使用C++和MFC显示BMP格式,主要结合自己的<数字图像处理>课程和以前的项目叙述讲解 ...

最新文章

  1. 年度第一效率神器:你一定不想错过它!
  2. 编程(创客)教育哪家强?图形化编程软件体验报告(慧编程)
  3. 虚拟机开启mysql密码报错_Linux虚拟机下mysql 5.7安装配置方法图文教程
  4. WSDM 2020 | RMRN:社区问答中的深度关联推理模型
  5. mysql存储图片_Python
  6. 网络编程中如何得知一次请求(或响应)的数据已接收完
  7. mysql安装了老版本_Windows环境下MySQL安装教程
  8. 这个太有意思了,程序员可以消遣娱乐
  9. Qt在指定区域内拖动窗口
  10. 使用vs2017 作为matlab2016a b编译器 解决无法找到编译器问题【免费】
  11. 如何从Debian 9 Stretch 升级到 Debian 10 Buster(升级Debian9图文教程)
  12. mysql 5.7 root password 过期
  13. SQL Server - FileTable
  14. 二级域名会不会分散主域名权重
  15. ThinkPhp项目部署到Linux file_put_contents() 报错:failed to open stream: Permission denied
  16. 怎样才能在电脑上下载计算机一级考试软件?
  17. win10计算机本地组策略编辑器,win10本地组策略编辑器打不开最佳解决方法
  18. 云通讯im怎么做php回调,腾讯云IM接入案列(一)
  19. 网络出现异常(只能上QQ不能上网页)
  20. 百家讲坛之易中天品三国MP3全集

热门文章

  1. 晨枫U盘启动盘制作工具V4.0-安装原版XP的方法
  2. UNICODE汉字数据库
  3. Dual Regression Networks for SISR 环境搭建 | 2020Paper | 【❤️Pytorch 实现❤️】
  4. 【Gym - 100482B Farmer 】 思维
  5. 如何玩转信用卡 银行不会告诉你的十个秘密
  6. 使用Feign传输File类型的数据
  7. SQL之ignore关键字
  8. 什么是指用计算机,cat是指计算机的什么
  9. 【吐槽脑洞】关于逛B站时偶然体验的弹幕互动游戏魏蜀吴三国争霸游戏的一些思考
  10. 虽说是递推式,但我还是觉得是逆推法