C++儲存Bitmap圖片
阿新 • • 發佈:2019-01-01
關於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; }