0. BMP格式重点介绍
0.1 BMP采用的是小端(Little Endian)存储方式
这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。
0.2 BMP图像的高度与RGB相反
0.3 BMP文件结构
BMP文件是由BITMAPFILEHEADER、BITMAPINFOHEADER、RGB像素数据共3个部分构成,它的结构如下图所示。
//BITMAPFILEHEADER
//BITMAPINFOHEADER
//RGB像素数据
//其中前两部分的结构如下所示。在写入BMP文件头的时候给其中的每个字段赋上合适的值就可以了。
typedef struct tagBITMAPFILEHEADER{
unsigned short int bfType; //位图文件的类型,必须为BM
unsigned long bfSize; //文件大小,以字节为单位
unsigned short int bfReserverd1; //位图文件保留字,必须为0
unsigned short int bfReserverd2; //位图文件保留字,必须为0
unsigned long bfbfOffBits; //位图文件头到数据的偏移量,以字节为单位
}BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER
{
long biSize; //该结构大小,字节为单位
long biWidth; //图形宽度以象素为单位
long biHeight; //图形高度以象素为单位
short int biPlanes; //目标设备的级别,必须为1
short int biBitcount; //颜色深度,每个象素所需要的位数
short int biCompression; //位图的压缩类型
long biSizeImage; //位图的大小,以字节为单位
long biXPelsPermeter; //位图水平分辨率,每米像素数
long biYPelsPermeter; //位图垂直分辨率,每米像素数
long biClrUsed; //位图实际使用的颜色表中的颜色数
long biClrImportant; //位图显示过程中重要的颜色数
}BITMAPINFOHEADER;
1. 代码如下
extern "C"
{
#ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#endif
}
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
}
/**
* Convert RGB24 file to BMP file
* @param rgb24path Location of input RGB file.
* @param width Width of input RGB file.
* @param height Height of input RGB file.
* @param url_out Location of Output BMP file.
*/
int simplest_rgb24_to_bmp(const char* rgb24path, int width, int height,
const char* bmppath) {
typedef struct { //tagBITMAPFILEHEADER关键结构
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) { //bmppath为生成文件
printf("Error: Cannot open output BMP file.\n");
return -1;
}
rgb24_buffer = (unsigned char*)malloc(width * height * 3);
//申请内存空间,大小由BMP图像类型决定
fread(rgb24_buffer, 1, width * height * 3, fp_rgb24);
//一个字节一个字节的把fp_rgb24里面的数据存到rgb24_buffer里面
m_BMPHeader.imageSize = 3 * width * height + header_size;
//文件大小,总的存储RGB数据的加上文件头
m_BMPHeader.startPosition = header_size;//位图文件头到数据的偏移量,以字节为单位
m_BMPInfoHeader.Length = sizeof(InfoHead); //改结构的大小
m_BMPInfoHeader.width = width;//BMP图像宽度以为RGB像素的宽度
//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
m_BMPInfoHeader.height = -height;//BMP图像高度和原RGB是相反的
m_BMPInfoHeader.colorPlane = 1; //目标设备的级别,必须为1
m_BMPInfoHeader.bitColor = 24;//颜色深度,每个像素所需要的位数
m_BMPInfoHeader.realSize = 3 * width * height;//位图的大小
fwrite(bfType, 1, sizeof(bfType), fp_bmp);//把bfType对应的BM写入fp_bmp中
fwrite(&m_BMPHeader, 1, sizeof(m_BMPHeader), fp_bmp);
//继续上面的文件指针,m_BMPHeader写入fp_bmp中
fwrite(&m_BMPInfoHeader, 1, sizeof(m_BMPInfoHeader), fp_bmp);
//继续上面的文件指针,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;
//将RGB数据中每个像素的“R”和“B”的位置互换。
}
}
fwrite(rgb24_buffer, 3 * width * height, 1, fp_bmp);
//继续上面的文件指针,把交换过的RGB数据存到fp_bmp
fclose(fp_rgb24);//关闭流
fclose(fp_bmp);//关闭流
free(rgb24_buffer);//释放内存
printf("Finish generate %s!\n", bmppath);
return 0;
}
int main()
{
simplest_rgb24_to_bmp("lena_256x256_rgb24.rgb", 256, 256, "output_lena.bmp");
return 0;
}
2. 效果
下图为输入: RGB24格式的图像lena_256x256_rgb24.rgb
下图是封装为BMP格式后的图像output_lena.bmp,封装后的图像使用普通的看图软件就可以查看。
用Windows照片查看器打开,效果如下:
参考链接:https://blog.csdn.net/leixiaohua1020/article/details/50534150