文章目录

  • 一、bmp相关概念
    • 位图Bitmap 与 矢量图Vector---用点表示 还是 用公式表示
    • bmp(Bitmap-File)---一种非压缩图形文件位图格式,后缀bmp
  • 二、bmp文件格式
    • 2.1 位图文件头bitmap-file header---用于进行文件的识别,14字节
    • 2.2 位图信息头bitmap information header---图像的详细信息,40字节
    • 2.3 调色板color palette(可选)
    • 2.4 位图存储数据data bits
  • 三、代码示例---从jpeg图片转化到bmp图片
  • 参考

一、bmp相关概念

位图Bitmap 与 矢量图Vector—用点表示 还是 用公式表示

计算机能以位图和矢量图格式显示图像。位图又称点阵图或光栅图,它使用我们称为像素(象素,Pixel)的一格一格的小点来描述图像。计算机屏幕其实就是一张包含大量像素点的网格。当我们把位图放大时,每一个像素小点看上去就像是一个个马赛克色块。矢量图 使用直线和曲线来描述图形,这些图形的元素是一些点、线、矩形、多边形、圆和弧线等等,它们都是通过数学公式计算获得的。位图和矢量图最简单的区别就是:矢量图可以无限放大,而且不会失真;而位图则不能。

bmp(Bitmap-File)—一种非压缩图形文件位图格式,后缀bmp

Bitmap-File图形文件是Windows采用的图形文件格式,在Windows环境下运行的所有图像处理软件都支持BMP图像文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。Windows 3.0以后的BMP文件都是指设备无关位图(DIB,device-independent bitmap)。BMP位图文件默认的文件扩展名是.BMP,有时它也会以.DIB或.RLE作扩展名。
bmp本身是非压缩的,相对jpeg这类压缩的图片size要大得多,但这也是它的特点,设备无关化,无需任何算法处理,何以在任何设备上显示。

二、bmp文件格式

BMP格式的文件从头到尾依次是:1、bmp文件头(bmp file header),共14字节;2、位图信息头(bitmap information),共40字节;3、调色板(color palette),可选;4、位图数据(data bits);
我们使用如下这张图片进行距离分析:

2.1 位图文件头bitmap-file header—用于进行文件的识别,14字节

typedef struct {
unsigned short int type; /* 文件类型 常见BM(0x42,0x4d) */
unsigned int size;/* 文件大小 */
unsigned short int reserved1, reserved2; /* 保留位 */
unsigned int offset;/* 数据区在文件中的位置偏移量byte */
} bmp_file_header;


0~ 1字节:0x42,0x4d,字符BM,表示文件类型;2~ 5字节:0xc0036 = 786468 = 768kB,和文件大小一样;6~ 9字节:保留位;A~ D字节:0x36 = 54,表示54字节开始是真实的数据偏移;

2.2 位图信息头bitmap information header—图像的详细信息,40字节

typedef struct { unsigned int biSize; /* 位图信息头的大小 */ int biWidth; /* 位图的宽度,单位是像素 */int biHeight; /* 位图的高度,单位是像素, 如果该值是一个负数表示倒向位图 */unsigned short int biPlanes; /* 为目标设备说明位面数,其值将总是被设为1 */unsigned short int biBitCount; /* 说明bit数/像素,其值为1、4、8、16、24、或32 */unsigned int biCompression; /* 压缩的类型,常见是0表示非压缩,见下表 */unsigned int biSizeImage; /* 图像的大小,当用BI_RGB格式-非压缩时,可设置为0 */unsigned int biXPelsPerMeter; /* 水平分辨率,用像素/米表示 */unsigned int biYPelsPerMeter; /* 垂直分辨率,用像素/米表示 */unsigned int biClrUsed; /* 使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项) */unsigned int biClrImportant; /* 对图像显示有重要影响的颜色索引的数目,如果是0表示都重要 */
} bmp_info_header;

压缩字段:


0~ 3字节:0x28=40 ,文件头长度40字节;4~ 7字节:0x200 = 512,图像宽度;8~ 11字节:0x200 = 512,图像高度;12~ 13字节:0x1固定;14~ 15字节:0x18=24 bit每像素;16~ 19字节:0x0 非压缩;20~ 23字节:0xc0000=786432字节,文件数据长度;

2.3 调色板color palette(可选)

当前这个文件没有调色板(从文件头看出data数据从54bit开始,而文件头+信息头已经54bit了)。
调色板怎么理解?我们常见的像素数据本身代表了这个像素的RGB数值,比如RGB888这种格式,位宽24bit,R、G、B分别占用8bit组成一个像素。还有另一种方法,类似hash表,像素内容存储的是一个索引坐标,通过索引去一个数据数组中找到真正的RGB具体数值,而这个数据数组就是调色板 。调色板可以包含很多条目,条目个数就是图像中所使用的颜色的个数。每个条目用来描述一种颜色,包含4个字节,其中三个表示蓝色、绿色和红色,第四个字节没有使用(大多数应用程序将它设为0);对于每个字节,数值0表示该颜色分量在当前的颜色中没有使用,而数值255表示这种颜色分量使用最大的强度。

typedef struct  {unsigned char rgbBlue;unsigned char rgbGreen;unsigned char rgbRed;unsigned char rgbReserved;
} rgb_quad;

调色版的本质就是,当画面颜色种类较少,可以用更少的空间存储文件。

2.4 位图存储数据data bits

从文件头可以看到,54字节开始是真实的数据。从文件信息头上看,是RGB非压缩的图像,每个像素24字节,即R、G、B分别占用8bit组成一个像素,默认存储数据位B、G、R顺序(低地址到高地址),这个和jpeg不同。全部数据组成了接下来的内容。注意,通常bmp的像素是从下到上、从左到右保存的,相当于第一个数据其实是最后一行第一个点。每一行的大小都向上取整为4字节(32位DWORD)的倍数,来保证每一行的起始地址必须为4的倍数;

三、代码示例—从jpeg图片转化到bmp图片

以下为我写的一个jpeg转bmp图片的c代码。jpeg不熟悉可以看我这篇文章:https://blog.csdn.net/runafterhit/article/details/119300530
几个前提:这里我默认只支持rgb888这种位宽的格式,写死了bit深度24bit,没有考虑bmp每行4字节对齐(分辨率选择保证),比较简单,没有用调色板缩小文件size。
几个注意要点:1、bmp的每个点是BRG,而jpeg是RGB,每个点数据需要反序;2、bmp是从最后一行到第一行,也需要反序;

#include "stdio.h"
#include "stdlib.h"
#include "jpeglib.h"
#include <setjmp.h>
#include <string.h>
struct my_error_mgr {struct jpeg_error_mgr pub;    /* "public" fields */jmp_buf setjmp_buffer;        /* for return to caller */
};
typedef struct my_error_mgr * my_error_ptr;
void my_error_exit (j_common_ptr cinfo) {my_error_ptr myerr = (my_error_ptr) cinfo->err;(*cinfo->err->output_message) (cinfo);longjmp(myerr->setjmp_buffer, 1);
}#pragma pack(1)
typedef struct { unsigned short int type; /* 文件类型 常见BM(0x42,0x4d) */ unsigned int size;/* 文件大小 */ unsigned short int reserved1, reserved2; /* 保留位 */ unsigned int offset;/* 数据区在文件中的位置偏移量byte */
} bmp_file_header;typedef struct { unsigned int biSize; /* 位图信息头的大小 */ unsigned int biWidth; /* 位图的宽度,单位是像素 */unsigned int biHeight; /* 位图的高度,单位是像素, 如果该值是一个负数表示倒向位图 */unsigned short int biPlanes; /* 为目标设备说明位面数,其值将总是被设为1 */unsigned short int biBitCount; /* 说明bit数/像素,其值为1、4、8、16、24、或32 */unsigned int biCompression; /* 压缩的类型,常见是0表示非压缩,见下表 */unsigned int biSizeImage; /* 图像的大小,当用BI_RGB格式-非压缩时,可设置为0 */unsigned int biXPelsPerMeter; /* 水平分辨率,用像素/米表示 */unsigned int biYPelsPerMeter; /* 垂直分辨率,用像素/米表示 */unsigned int biClrUsed; /* 使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项) */unsigned int biClrImportant; /* 对图像显示有重要影响的颜色索引的数目,如果是0表示都重要 */
} bmp_info_header;
#pragma pack()void write_bmp_file_header(FILE *outfile, unsigned int size) {bmp_file_header bfheader = {0};bfheader.type = 0x4d42; /* 文件类型 常见BM(0x42,0x4d) */ bfheader.size = size + 0x36;/* 文件大小,数据data大小+文件头+信息头 */ bfheader.offset = 0x36;/* 数据区在文件中的位置偏移量byte */ fwrite(&bfheader, sizeof(bmp_file_header), 1, outfile);return;
}void write_bmp_info_header(FILE *outfile, unsigned int size, int width, int height) {bmp_info_header bfinfo = {0};bfinfo.biSize = 0x28; /* 位图信息头的大小 */ bfinfo.biWidth = width; /* 位图的宽度,单位是像素 */bfinfo.biHeight = height; /* 位图的高度,单位是像素 */bfinfo.biPlanes = 1; /* 为目标设备说明位面数,其值将总是被设为1 */bfinfo.biBitCount = 24; /* 说明bit数/像素,其值为1、4、8、16、24、或32 */bfinfo.biCompression = 0; /* 压缩的类型,常见是0表示非压缩 */bfinfo.biSizeImage = size; /* 图像的大小,当用BI_RGB格式-非压缩时,可设置为0 */bfinfo.biXPelsPerMeter = 0; /* 水平分辨率,用像素/米表示 */bfinfo.biYPelsPerMeter = 0; /* 垂直分辨率,用像素/米表示 */bfinfo.biClrUsed = 0; /* 使用的彩色表中的颜色索引数 */bfinfo.biClrImportant = 0; /* 对图像显示有重要影响的颜色索引的数目 */fwrite(&bfinfo, sizeof(bmp_info_header), 1, outfile);return;
}int main(int argc, char *argv[]) {if (argc < 2) {printf("please intput like: ./a.out xxx.jpeg\n");}// 打开输入文件FILE *infile = fopen(argv[1], "rb");if (infile == NULL) {printf("intput file %s open failed!\n", argv[1]);return -1;}// 创建输出文件FILE *outfile = fopen("./output.bmp", "w+");if (outfile == NULL) {printf("out file open failed!\n");return -1;}// 定义cinfo数据结构,libjpeg定义的解码器上下文struct jpeg_decompress_struct cinfo;// 设置报错回调,如果libjpeg解析过程出错,会调用struct my_error_mgr jerr;cinfo.err = jpeg_std_error(&jerr.pub);if (setjmp(jerr.setjmp_buffer)) {printf("set jmp error failed!\n");fclose(infile);return -1;}// 1.jpeg开始解码准备// 创建解码器jpeg_create_decompress(&cinfo);// 设置解码器输入,绑定文件jpeg_stdio_src(&cinfo, infile);// 读取文件头,这一步之后cinfo中文件信息才可信jpeg_read_header(&cinfo, TRUE);// 开始解码,默认输出是RGB,还可以cinfo.out_color_space设置jpeg_start_decompress(&cinfo);// 计算输出的行stride,jpeg库是按行往外读取,要计算每行读取多少数据int row_stride = cinfo.output_width * cinfo.output_components;// 调用libjpeg内存申请接口,申请一个一行长的bufferJSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);// 申请一个完整的buffer存储jpeg的输出char *jpegout = malloc(cinfo.output_height * row_stride);// 2.写bmp文件文件头和信息头write_bmp_file_header(outfile, cinfo.output_height * row_stride);write_bmp_info_header(outfile, cinfo.output_height * row_stride, cinfo.output_width, cinfo.output_height);// 3.读取jpeg解码内容,写到bmp文件中// 循环从libjpeg读取行 到 buffer,然后将buffer内容写入内存while (cinfo.output_scanline < cinfo.output_height) {jpeg_read_scanlines(&cinfo, buffer, 1);char *src = buffer[0];char *dst = jpegout + (cinfo.output_scanline - 1) * row_stride;int index;// 排序调整,jpeg是RGB顺序,bmp是BRG,再放入内存时需要调整for (index = 0; index < cinfo.output_width; index++) {*(dst + index*3 + 2) = *(src + index*3);*(dst + index*3 + 1) = *(src + index*3 + 1);*(dst + index*3) = *(src + index*3 + 2);}}// bmp从最后一行开始存数据,一直存到第一行,因此需要调整顺序int i;for (i = cinfo.output_height - 1; i >=0; i--) {fwrite(jpegout + i * row_stride, row_stride, 1, outfile);}// 释放内存free(jpegout);// 关闭全部文件close(infile);close(outfile);return 0;
}
// 编译
gcc sample_jpeg.c -ljpeg
// 测试,查看输出的output.bmp文件
./a.out ./test3.jpeg

参考

维基百科:https://chi.jinzhao.wiki/wiki/BMP
https://blog.csdn.net/qingchuwudi/article/details/25785307

图形图像基础 之 bmp介绍相关推荐

  1. 图形图像基础 之 png介绍

    文章目录 一.png相关概念 png---一种无损压缩算法的位图格式 png和bmp.jpeg图片比较 libpng---一款C语言编写的读写PNG文件的跨平台的库 二.png文件格式---文件标签+ ...

  2. 图形图像基础 之 jpeg介绍

    一.[概念]jpeg相关概念简介 jpeg-一种影像有损压缩标准方法 后缀jpg/jpeg JPEG(Joint Photographic Experts Group 联合图像专家小组)是一种针对照片 ...

  3. 4.图形图像素材编辑

    4.图形图像素材编辑 图形.图像是人类视觉所感受到的一种具象化的信息,是多媒体信息的主要类型,也是信息传递最基本.最常见的方式.它可以形象.生动和直观地表达大量的信息,具有文字和声音无可比拟的优点.图 ...

  4. OpenCV图形图像击中击不中HITMISS变换处理基础知识

    ☞ ░ 前往老猿Python博客 https://blog.csdn.net/LaoYuanPython ░ 博文传送门: 老猿关于HTM变换的博文目录请见: https://blog.csdn.ne ...

  5. 图形和图像计算机基础知识,计算机图形图像基础

    <计算机图形图像基础>是2011-03-01浙江大学出版社出版的图书,作者是程辉,田少煦.[1] 书    名 计算机图形图像基础 作    者 程辉,田少煦ISBN 9787308083 ...

  6. 一个C#函数学完C#图形图像编程基础

    老师说C#主要用于 1.winform开发 2.网络 3.驱动 在图形图像处理上用的比较少,不过书里有图形图像编程这一章节,为了系统的学完C#编程基础,以及为了能够更熟悉C#的特性,再加上今天晚上闲的 ...

  7. 游戏编程入门(4):绘制图形图像

    接上文 游戏编程入门(3):绘制基本 GDI 图形 除了经典的矢量图形游戏之外,游戏开发人员都使用图形图像来在视觉上展示游戏的图形部分.本文将介绍如何加载和显示图形图像. 本章内容包括: 位图图像的基 ...

  8. 计算机视觉————(CV)图像基础以及数字图像处理基础

    1.数字图像 客观世界中,以自然形式呈现出的图像通常称作物理图像,也叫做连续图像,图像信号值是连续变化的.因为计算机只可以识别离散数字,因此物理图像需要经过处理转化为数字形式,即数字图像,才可以使用. ...

  9. 计算机中常用的矢量图形文件,第3章 电脑图像基础知识.ppt

    <第3章 电脑图像基础知识.ppt>由会员分享,可在线阅读,更多相关<第3章 电脑图像基础知识.ppt(15页珍藏版)>请在人人文库网上搜索. 1.第03章 电脑图像基础知识, ...

最新文章

  1. jquerymobile知识点三:弹出层popup
  2. 【问题收集·中级】关于XMPP使用Base传送图片
  3. Garbage Collection Optimization for High-Throughput and Low-Latency Java Applications--转载
  4. sonar 集群环境工作机制的深入理解
  5. [dp]leetcode 746. Min Cost Climbing Stairs
  6. 微信小程序:冒泡事件及其阻止
  7. 截取usb数据包,控制usb设备----Relay设备
  8. 黄俊:电商系统的一些心得分享
  9. “华为杯”中国研究生数学建模竞赛 记录
  10. Apabi Reader 4.0.1正式发布!
  11. JavaScript第6章上机练习2(使用jQuery美化英雄联盟简介页)上机练习3(制作非缘勿扰页面特效)
  12. 网站设计(3常用标签)
  13. 四元数与欧拉角的转换
  14. 远程服务器如何共享电脑文件共享,远程控制实现文件共享 -电脑资料
  15. Qt5.12.6 + VS2019添加图片资源文件
  16. 金三银四,是纵马一跃,还是稳如老狗!
  17. AODV=DSR+DSDV
  18. Ramps 1.4升级Marlin2.0.x改12864显示屏并添加打印机箱体温度显示
  19. 最全的基于c++的serialport.cpp与serialport.h类文件(解析版)
  20. 关于在线评论有用性的论文研读笔记---10篇

热门文章

  1. 云海轻站常见问题整理
  2. ckpt下载 deeplabv3_煮酒论英雄:深度学习CV领域最瞩目的成果top46
  3. 联芯 1860平台 icn6211 mipi to RGB 转换芯片 调试 和 st7789 LCD调试spi 9bit 模式
  4. [国家集训队2012]tree(陈立杰)
  5. 基于C#的AE二次开发之图层右键菜单打开属性表及图层相关操作
  6. 粒子群算法及其Python实现
  7. vue + 百度地图 +点位标注
  8. 益聚星荣:22岁董明珠秘书回应走红:现在内心是非常惶恐的,自己只是一个普通的打工人
  9. vue 数字滚动递增效果
  10. Centos7.2静默安装oracle11gR2