1. 程式人生 > >C++儲存Bitmap圖片

C++儲存Bitmap圖片

關於Bitmap圖片4位元組對齊,Bitmap圖片儲存到磁碟時為什麼需要4位元組對齊,可以參考

關於點陣圖資料怎麼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;
}