数据与封装格式BMP图像(位图)
Posted 叮咚咕噜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据与封装格式BMP图像(位图)相关的知识,希望对你有一定的参考价值。
梳理了点阵、位图、RGB图像、矢量图这几个之间的区别关系与联系,重点描述了RGB怎么转位图,以及位图的格式
一、概念
1、矢量图
- 使用直线和曲线来描述图形,这些图形的元素是一些点、线、矩形、多边形、圆和弧线等等,它们都是通过数学公式计算获得的。
- 位图和矢量图最简单的区别就是:矢量图可以无限放大,而且不会失真;而位图则不能。
- 像Photoshop(PS)这样主要用于处理位图的软件,我们称之为图像处理软件;专门处理矢量图的软件,我们称之为图形设计软件
2、位图
- 图像又称点阵图或光栅图,它使用我们称为像素(象素,Pixel)的一格一格的小点来描述图像。计算机屏幕其实就是一张包含大量像素点的网格。当我们把位图放大时,每一个像素小点看上去就像是一个个马赛克色块。
- 位图的像素都分配有特定的位置和颜色值。每个像素的颜色信息由RGB组合或者灰度值表示。根据位深度,可将位图分为1、4、8、16、24及32位图像等。每个像素使用的信息位数越多,可用的颜色就越多,颜色表现就越逼真,相应的数据量越大
- BMP图像内部实际上存储的就是RGB数据
3、点阵
- 位深度为 1 的像素位图只有两个可能的值(黑色和白色),所以又称为二值位图
- 点阵即为位深为1的像素位图
二、BMP位图文件结构
BMP文件由4部分组成:
-
位图文件头(bitmap-file header)
-
位图信息头(bitmap-informationheader)
-
颜色表(color table)
-
颜色点阵数据(bits data)
24位真彩色位图没有颜色表,所以只有1、2、4这三部分,看图像属性,位深度,如果是24,就说明图片是24位真彩色,实际就是对RGB数据的
1、位图文件头
- 位图信息头占用14bytes
- 位图文件头分4部分,共14字节:
名称 | 占用空间 | 内容 | 实际数据 |
bfType | 2字节 | 标识,就是“BM”二字 | BM |
bfSize | 4字节 | 整个BMP文件的大小 | 0x000C0036(786486)【与右键查看图片属性里面的大小值一样】 |
bfReserved1/2 | 4字节 | 保留字,没用 | 0 |
bfOffBits | 4字节 | 偏移数,即 位图文件头+位图信息头+调色板 的大小 | 0x36(54) |
- 结构体的定义
typedef struct tagBITMAPFILEHEADER
{
unsigned short int bfType; //位图文件的类型,必须为BM
unsigned int bfSize; //文件大小,以字节为单位
unsigned short int bfReserverd1; //位图文件保留字,必须为0
unsigned short int bfReserverd2; //位图文件保留字,必须为0
unsigned int bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER;
2、位图信息头
- 位图信息头共40字节:
名称 | 占用空间 | 内容 | 实际数据 |
biSize | 4字节 | 位图信息头的大小,为40 | 0x28(40) |
biWidth | 4字节 | 位图的宽度,单位是像素 | 0x200(512) |
biHeight | 4字节 | 位图的高度,单位是像素 | 0x200(512) |
biPlanes | 2字节 | 固定值1 | 1 |
biBitCount | 2字节 | 每个像素的位数 1-黑白图,4-16色,8-256色,24-真彩色 | 0x18(24) |
biCompression | 4字节 | 压缩方式,BI_RGB(0)为不压缩 | 0 |
biSizeImage | 4字节 | 位图全部像素占用的字节数,BI_RGB时可设为0 | 0x0C |
biXPelsPerMeter | 4字节 | 水平分辨率(像素/米) | 0 |
biYPelsPerMeter | 4字节 | 垂直分辨率(像素/米) | 0 |
biClrUsed | 4字节 | 位图使用的颜色数 如果为0,则颜色数为2的biBitCount次方 | 0 |
biClrImportant | 4字节 | 重要的颜色数,0代表所有颜色都重要 | 0 |
作为真彩色位图,我们主要关心的是biWidth和biHeight这两个数值,两个数值告诉我们图像的尺寸。biSize,biPlanes,biBitCount这几个数值是固定的。想偷懒的话,其它的数值可以一律用0来填充。
- 结构体的定义
typedef struct tagBITMAPINFOHEADER
{
int biSize; //该结构大小,字节为单位
int biWidth; //图形宽度以象素为单位
int biHeight; //图形高度以象素为单位
short int biPlanes; //目标设备的级别,必须为1
short int biBitcount; //颜色深度,每个象素所需要的位数
short int biCompression; //位图的压缩类型
int biSizeImage; //位图的大小,以字节为单位
int biXPelsPermeter; //位图水平分辨率,每米像素数
int biYPelsPermeter; //位图垂直分辨率,每米像素数
int biClrUsed; //位图实际使用的颜色表中的颜色数
int biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;
3、颜色表
24位真彩色位图没有颜色表。为了简化,只讨论24位真彩色位图。
4、颜色点阵数据
位图全部的像素,是按照自下向上,自左向右的顺序排列的。
RGB数据也是倒着念的,原始数据是按B、G、R的顺序排列的
三、RGB数据封装成BMP图像
BMP图像内部实际上存储的就是RGB数据。本程序实现了对RGB像素数据的封装处理。通过本程序中的函数,可以将RGB数据封装成为一张BMP图像。
int simplest_rgb24_to_bmp(const char *rgb24path,int width,int height,const char *bmppath){
typedef struct
{
long imageSize;
long blank;
long startPosition;
}BmpHead;
typedef struct
{
long Length;
long width;
long height;
unsigned short colorPlane;
unsigned short bitColor;
long zipFormat;
long realSize;
long xPels;
long yPels;
long colorUse;
long colorImportant;
}InfoHead;
int i=0,j=0;
BmpHead m_BMPHeader={0};
InfoHead m_BMPInfoHeader={0};
char bfType[2]={'B','M'};
int header_size=sizeof(bfType)+sizeof(BmpHead)+sizeof(InfoHead);
unsigned char *rgb24_buffer=NULL;
FILE *fp_rgb24=NULL,*fp_bmp=NULL;
if((fp_rgb24=fopen(rgb24path,"rb"))==NULL){
printf("Error: Cannot open input RGB24 file.\\n");
return -1;
}
if((fp_bmp=fopen(bmppath,"wb"))==NULL){
printf("Error: Cannot open output BMP file.\\n");
return -1;
}
rgb24_buffer=(unsigned char *)malloc(width*height*3);
fread(rgb24_buffer,1,width*height*3,fp_rgb24);
m_BMPHeader.imageSize=3*width*height+header_size;
m_BMPHeader.startPosition=header_size;
m_BMPInfoHeader.Length=sizeof(InfoHead);
m_BMPInfoHeader.width=width;
//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
m_BMPInfoHeader.height=-height;
m_BMPInfoHeader.colorPlane=1;
m_BMPInfoHeader.bitColor=24;
m_BMPInfoHeader.realSize=3*width*height;
fwrite(bfType,1,sizeof(bfType),fp_bmp);
fwrite(&m_BMPHeader,1,sizeof(m_BMPHeader),fp_bmp);
fwrite(&m_BMPInfoHeader,1,sizeof(m_BMPInfoHeader),fp_bmp);
//BMP save R1|G1|B1,R2|G2|B2 as B1|G1|R1,B2|G2|R2
//It saves pixel data in Little Endian
//So we change 'R' and 'B'
for(j =0;j<height;j++){
for(i=0;i<width;i++){
char temp=rgb24_buffer[(j*width+i)*3+2];
rgb24_buffer[(j*width+i)*3+2]=rgb24_buffer[(j*width+i)*3+0];
rgb24_buffer[(j*width+i)*3+0]=temp;
}
}
fwrite(rgb24_buffer,3*width*height,1,fp_bmp);
fclose(fp_rgb24);
fclose(fp_bmp);
free(rgb24_buffer);
printf("Finish generate %s!\\n",bmppath);
return 0;
return 0;
}
调用上面函数的方法如下所示。
simplest_rgb24_to_bmp("lena_256x256_rgb24.rgb",256,256,"output_lena.bmp");
代码主要做了两个工作:
- 将RGB数据前面加上文件头。
- 将RGB数据中每个像素的“B”和“R”的位置互换。
BMP采用的是小端(Little Endian)存储方式。这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。
四、参考
以上是关于数据与封装格式BMP图像(位图)的主要内容,如果未能解决你的问题,请参考以下文章