位深度
根据位深度不同,bmp数据的存储格式不同
1:单色图,调色板中含有两种颜色,也就是我们通常说的黑白图片32:4G真彩色,一般没有调色板,每4个字节表示一个像素,相对24位真彩图而言,加入了一个透明度,即RGBA模式
也就是说,bmp不能存储16位的灰度图(最大灰度值=65535),16位bmp都是彩色图!只能将16位灰度图线性转换为8位图才能保存为bmp格式,而且要注意保存的不是灰度值,而是其在调色板中的索引值!只有这样,bmp才能正确地被解码!
8位bmp的颜色表
即数据结构tagRGBQUAD的内容,又叫做调色板。为了要把数据流转换为bmp格式,所以要自己填充对应的数据结构,于是就把这部分的内容读取出来,发现是以下内容:
rgbBlue[0] = 0; rgbGreen[0] = 0; rgbRed[0] = 0; rgbReserved[0] = 0;
rgbBlue[1] = 1; rgbGreen[1] = 1; rgbRed[1] = 1; rgbReserved[1] = 0;
...
rgbBlue[255] = 255; rgbGreen[255] = 255; rgbRed[255] = 255; rgbReserved[0] = 0;
因为是灰度图,所以rgb分量相等
位图数据的存储方式
(自下而上,从左到右)
扫描行是由底向上存储的,这就是说,位图数据的第一个字节表示位图左下角的象素,而最后一个字节表示位图右上角的象素。
每行数据按4字节对齐,如果图像宽度不是4的整数倍,要事先补齐,如下代码:
//计算4字节对齐的高和宽 int w1 = (w+3)/4*4; int h1 = (h+3)/4*4; ... //填充bmp数据段,pData memset(pData,0,bmpFileH.bfSize-bmpFileH.bfOffBits); //补齐 //逐行填充 int bits = depth/8; for(int i=0;i<h;i++) //遍历行 { const unsigned char * p0 = pRaw + i*w*bits; //pRaw为原始图像数据,其高和宽为h和w unsigned char * p1 = pData + i*w1*bits; for(int j=0;j<w;j++) //遍历列 { for(int k=0;k<bits;k++) //遍历通道 { *p1++= p0[j*bits+k]; } } } ...记得 tagBmpFile中的bfSize要按照4字节对齐后的高和宽计算,而tagBmpInfo中的biWidth、biHeight则按照原始的高和宽赋值
参考资料:
BMP位图与调色板分析
2、4、8、16、24、32位位图的数据解析与显示