C++保存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; }