音视频:04.RGB转BMP

376 阅读2分钟

BMP

BMP格式是以重图片格式。文件由三个部分组成:文件头,信息头,rgb数据。

文件头(14字节) + 信息头(40字节) = 54 字节

文件头(14字节)

名称占用空间内容示例数据
bfType2字节标识,就是“BM”BM
bfSize4字节整个 BMP 文件的大小0x000C0036(786486)
bfReserved12字节保留字0
bfReserved22字节保留字0
bfOffBits4字节偏移数,即位图文件头 位图信息头 调色板的大小0x36(54)

信息头(40字节)

名称占用空间内容示例数据
biSize4字节位图信息头的大小,为4040
biWidth4字节位图的宽度,单位是像素1920
biHeight4字节位图的高度,单位是像素1080
biPlanes2字节固定值11
biClrUsed4字节位图使用的颜色数如果为0,则颜色数为2的biBitCount次方0
biBitCount2字节每个像素的位数 1-黑白图,4-16色,8-256色,24-真彩色,32-带alpha通道32
biSizeImage4字节位图全部像素占用的字节数,BI_RGB时可设为01920 x 1080 x 4
biCompression4字节压缩方式,BI_RGB(0)为不压缩0
biClrImportant4字节重要的颜色数,0代表所有颜色都重要0
biXPelsPerMeter4字节水平分辨率(像素/米)2835
biYPelsPerMeter4字节垂直分辨率(像素/米)2835
//参数:pdata是rgb32数据,width,height是图片的宽与高
void SaveRgb2Bmp(const uint8_t * pdata, int width, int height)
{
	int size = width * height * 4 * sizeof(char); //这里乘以4,是因为rgb32数据是rgba的数据,一共有四个分量。

	BITMAPFILEHEADER bfh;
	bfh.bfType = (WORD)0x4d42;
	bfh.bfSize = size + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bfh.bfReserved1 = 0;
	bfh.bfReserved2 = 0;
	bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

	BITMAPINFOHEADER bih;
	bih.biSize = sizeof(BITMAPINFOHEADER);
	bih.biWidth = width;
	bih.biHeight = -height;//!!!
	bih.biPlanes = 1;
	bih.biClrUsed = 0;
	bih.biBitCount = 32;
	bih.biSizeImage = size;
	bih.biCompression = 0;
	bih.biClrImportant = 0;
	bih.biXPelsPerMeter = 2835;
	bih.biYPelsPerMeter = 2835;

	FILE * fp = nullptr;
	fopen_s(&fp, "Screen.bmp", "wb");
	if (!fp) return;

	fwrite(&bfh, 8, 1, fp);
	fwrite(&bfh.bfReserved2, sizeof(bfh.bfReserved2), 1, fp);
	fwrite(&bfh.bfOffBits, sizeof(bfh.bfOffBits), 1, fp);
	fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fp);
	fwrite(pdata, size, 1, fp);
	fclose(fp);
}

上面代码有个细节:bih.biHeight = -height;

为什么是负的?原因如下:

  • RGB24 文件中存储的顺序是 RGB, RGB, RGB ...... RGB
  • BMP 文件中 RGB 数据存储的顺序是 BGR, BGR, BGR ... BGR
  • 发现RGB文件与BMP存储RGB数据的时候是相反的,所以我们的biHeight需要为负数。biHeight 为正,位图自底向顶扫描,biHeight 为负,位图自顶向底扫描。

参考博客:blog.csdn.net/binglingziy…