bmp的解析:
bmp的解析比较简单,参考bmp的文件格式几个正确的将bmp文件解析出来,只是要注意:每一扫描行的字节数必需是4的整倍数,也就是DWORD对齐的。如果你想确保图像的扫描行DWORD对齐可使用下面的代码:(((width*biBitCount)+31)>>5)
bmp的编码:
对于24位bmp编码难度不大,因为没有调色板,所以直接将内存内的像素值按bmp的文件格式写入即可。
对于8位bmp编码,主要的困难是产生调色板,调色板有了,直接将数据区的像素定位到调色板的像素即可。调色板的生成主要有两步:一 分别取rgb的高四位(或5位),合并为一个word,对图像的每个像素都如此处理。二 参见聚类算法的K-MEANS算法对处理过后的图像数据处理取得调色板和图像像素在调色板中的index。细说下第二步:由于第一步的处理,图像像素最多覆盖2的(4*3)次方个色,即4096,统计这4096色在图像出现的次数;将这4096色按是用次数排序;统计使用的颜色,次数大于0为是用过;将前256色(使用的颜色》256)写入调色板;图像中的像素的index是该像素与调色板中的像素差距最小的那个。
C++ 代码如下
int iCover = 1struct COLORCOVER { unsigned short usedTimes; // 该颜色被是用次数 unsigned short colorIndex; // 代表颜色值 }; // 创建取高位后的颜色覆盖域,并初始化 COLORCOVER* colorCover = new COLORCOVER[iCover]; memset(colorCover,0,sizeof(COLORCOVER)*iCover); for(i=0; i// 统计每种颜色是用次数 for(i=0; i // 是用的颜色数 int iUsedColor = 0; for(i=0; i if(colorCover[i].usedTimes>0) iUsedColor++; } // 根据覆盖颜色是用的次数排序,冒泡排序 bool flag; COLORCOVER tmp; int j; for(i=1; i false; for(j=0;j if(colorCover[j].usedTimes true; } } if(!flag){ break; } } // 前256色即是调色板的内容 for(i=0; iint tmp = i*4; colorPlate[tmp] = (unsigned char)((colorCover[i].colorIndex & 0xf)char)((colorCover[i].colorIndex>>iBit & 0xf)char)((colorCover[i].colorIndex>>(iBit*2))// 对当前colorCover的颜色的排序序号进行记录,即记录这些颜色在调色板中的位置 unsigned char *index = new unsigned char[iCover]; memset(index,0,sizeof(char)*iCover); if (iUsedColor for (i = 0; i int tmp = colorCover[i].colorIndex; index[tmp] = i; } }else{//为第256之后的颜色在前256种颜色中找一个最接近的 for (i = 0; i int colorIndex, tmp, tmp1; for (i = 256; i for (int j = 1; j if (tmp > tmp1) { tmp = tmp1; colorIndex = j; } } index[colorCover[i].colorIndex] = colorIndex; } } // 生成数据区 int iLineData = ((biWidth * biBitCount + 31) & ~31) >> 3; for(i=0; i int tmp = biWidth * (biHeight -1 - i); for(j=0; j
mageData图像的rgba值;biBitCount 图像位数,此为8;biWidth,biHeight是图像的宽,高;Square 是计算两像素的平方差的函数。
对于4位bmp的生成类似8位bmp.
对于1位bmp,调色板只有两个色:白色和黑色。对于图像的每个像素,(r+g+b)/3>128?白色:黑色。