C++保存Bitmap图片

关于Bitmap图片4字节对齐,Bitmap图片保存到磁盘时为什么需要4字节对齐,可以参考

https://blog.csdn.net/xiaosuanzaowb/article/details/8067941

关于位图数据怎么4字节对齐:

假如一张2*2的RGB图片如下:

那么它在内存中数据理论应该为(图片数据在内存中是连续的,也就是说一行数据紧接着另一行数据,这里为了直观所以布局成这样)

(0xFF 0x00 0x00) (0x00 0xFF 0x00)

(0x00 0x00 0x00) (0xFF 0xFF 0xFF)

但是位图保存到磁盘时规定图片的数据每行的字节数要能被4整除(具体什么的我也不太清楚,对于我们一般人来说,我认为只要知道有这规定就行),对于上面的这张图片它每行数据为6个字节,显然6除以4还于2,显然没有4字节对齐,所以需要在每行数据后面补充2个字节的数据(随便值为多少,只要时2字节就行),因此补充后上图的数据变成:

(0xFF 0x00 0x00) (0x00 0xFF 0x00) (0x00 0x00)

(0x00 0x00 0x00) (0xFF 0xFF 0xFF)(0x00 0x00)

这样子的话将图片保存到磁盘中时就不会出现问题了。(不管图片每个像素是8字节 16字节 还是24字节都一样


在实际中怎么操作呢,假如我们从摄像头中取出一张2*2的图片如下:

其数据在bitmapData 中,一共6个字节

当我们想要将它保存到磁盘中去时,我们可以调用下面这个函数simple_4ByteAlignment(2,2,bitmapData)(一些说明全在写在下面函数中。)

bool simple_4ByteAlignment(int width, int height, unsigned char * bitmapData)
{
	if (!bitmapData)
	{
		return false;
	}
	unsigned char * fData=0;
	//length 数据的总长度
	//fillCount 每行需要补充的字节数
	int length=0, fillCount=0;

	length = width*3;//这里乘3是因为我们图片为Rgb图片,每个像素占3个字节
	if (length % 4 != 0)//先计算补充字节后,数据的总字节数
	{
		fillCount = 4 - length % 4;
		length += fillCount;
	}
	length *=height;

	//分配相应长度的内存
	fData = (uchar*)malloc(length);

	if (!fData)
	{
		return false;
	}

	memset(fData, 0, length);

	for (size_t i = 0; i < height; i++)
	{
		//由于需要4字节对齐,所以需要对每行进行补充fillCount的字节的数据。
		memcpy(fData+(width*3+ fillCount )*i, bitmapData+width * 3*i, width * 3);
	}

	bool ret=WriteBitmap888ToFile("你要保存的图片的路径.bmp", width, height, (uchar*)fData, length);
	//释放内存  
	free(fData);
	return ret;
}

下面两个为保存图片为bmp格式的函数,一个保存图片为rgb888一个保存为rgb565。

//根据bitmapData的(RGB)数据,保存bitmap  
//filename是要保存到物理硬盘的文件名(包括路径)  
//dateSize 表示图形数据的大小
//bitmapData 数据必须经过4字节对齐
static BOOL WriteBitmap888ToFile(const char * filename, int width, int height, unsigned char * bitmapData, int dateSize)
{

	//填充BITMAPINFOHEADER  
	BITMAPINFOHEADER bitmapInfoHeader;
	memset(&bitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER));
	bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitmapInfoHeader.biWidth = width;
	bitmapInfoHeader.biHeight = height;
	bitmapInfoHeader.biPlanes = 1;
	bitmapInfoHeader.biBitCount = 24;

	bitmapInfoHeader.biCompression = BI_RGB;

	bitmapInfoHeader.biSizeImage = dateSize;


	//填充BITMAPFILEHEADER  
	BITMAPFILEHEADER bitmapFileHeader;
	memset(&bitmapFileHeader, 0, sizeof(BITMAPFILEHEADER));
	bitmapFileHeader.bfType = 0x4d42;   //BM固定为这个
	bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + dateSize;
	bitmapFileHeader.bfReserved1 = 0;
	bitmapFileHeader.bfReserved2 = 0;

	FILE * filePtr = 0;       

	fopen_s(&filePtr, filename, "wb");
	if (NULL == filePtr)
	{
		return FALSE;
	}

	fwrite(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

	fwrite(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);

	fwrite(bitmapData, bitmapInfoHeader.biSizeImage, 1, filePtr);
	fclose(filePtr);
	return TRUE;
}

//根据bitmapData的(RGB)数据,保存bitmap  
//filename是要保存到物理硬盘的文件名(包括路径)  
//dateSize 表示图形数据的大小,
//bitmapData 数据必须经过4字节对齐
static BOOL WriteBitmap565ToFile(const char * filename, int width, int height, unsigned char * bitmapData, int dateSize)
{

	BITMAPFILEHEADER bitmapFileHeader;
	//填充BITMAPINFOHEADER  
	BITMAPINFOHEADER bitmapInfoHeader;

	RGBQUAD bmiColors[3]; //定义调色板

	bitmapFileHeader.bfType = 0x4d42;   //"BM"
	bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 3; 
	bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + dateSize;
	bitmapFileHeader.bfReserved1 = 0;
	bitmapFileHeader.bfReserved2 = 0;


	memset(&bitmapInfoHeader, 0, sizeof(BITMAPINFOHEADER));
	bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitmapInfoHeader.biWidth = width;
	bitmapInfoHeader.biHeight = -height;
	bitmapInfoHeader.biPlanes = 1;
	bitmapInfoHeader.biBitCount = 16;
	bitmapInfoHeader.biCompression = BI_BITFIELDS;
	bitmapInfoHeader.biSizeImage = dateSize;


	bmiColors[0].rgbBlue = 0;
	bmiColors[0].rgbGreen = 0xF8;
	bmiColors[0].rgbRed = 0;
	bmiColors[0].rgbReserved = 0;

	bmiColors[1].rgbBlue = 0xE0;
	bmiColors[1].rgbGreen = 0x07;
	bmiColors[1].rgbRed = 0;
	bmiColors[1].rgbReserved = 0;

	bmiColors[2].rgbBlue = 0x1F;
	bmiColors[2].rgbGreen = 0;
	bmiColors[2].rgbRed = 0;
	bmiColors[2].rgbReserved = 0;


	FILE * filePtr = 0;       

	fopen_s(&filePtr, filename, "wb");
	if (NULL == filePtr)
	{
		return FALSE;
	}

	fwrite(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr);

	fwrite(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr);

	fwrite(bmiColors,3 * sizeof(RGBQUAD), 1, filePtr);

	fwrite(bitmapData, bitmapInfoHeader.biSizeImage, 1, filePtr);
	fclose(filePtr);
	return TRUE;
}


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值