关于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;
}