真彩色BMP图象转256色BMP图函数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
BOOL CTest14Dlg::Trueto256()
{
DWORD SrcBufSize,OffBits,DstBufSize,DstLineBytes;
HLOCAL hImgData;
LPBITMAPINFOHEADER lpImgData;
LPSTR lpPtr;
HLOCAL hTempImgData;
LPBITMAPINFOHEADER lpTempImgData;
LPSTR lpTempPtr;
HDC hDc;
HFILE hf;
LONG x,y;
BITMAPFILEHEADER DstBf;
BITMAPINFOHEADER DstBi;
LOGPALETTE *pPal;
HPALETTE hPalette;
HPALETTE hPrevPalette;
HLOCAL hPal;
WORD i,j;
int Red,Green,Blue,ClrIndex;
DWORD ColorHits[4096];
WORD ColorIndex[4096];
DWORD PalCounts,temp;
long ColorError1,ColorError2;
HBITMAP hBitmap;
BITMAPFILEHEADER bmfHdr; // 位图文件头结构
LPBITMAPINFOHEADER lpBI; file://指向位图信息结构的指针
DWORD dwDIBSize;
char * path=new char [100];
sprintf(path,"D:\\新建文件夹\\日本验证码\\日本验证码\\2.bmp");
CFile file;
CFileException fe;
if (!file.Open(path, CFile::modeRead | CFile::shareDenyWrite, &fe))
{
AfxMessageBox("文件打不开");
return FALSE;
}//打开文件
BITMAPFILEHEADER bf;//定义位图文件头结构
DWORD dwBitsSize;
HANDLE hDIB;
LPSTR pDIB;
BITMAPINFOHEADER *bmhdr;//指向位图信息头结构的指针
BITMAPINFOHEADER bi;
dwBitsSize = file.GetLength();//得到文件长度
if (file.Read((LPSTR)&bf, sizeof(bf)) !=sizeof(bf))
return FALSE;
if (bf.bfType != 0x4d42) //检查是否为BMP文件
return FALSE;
hDIB=(HANDLE) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);//申请缓冲区
if (hDIB == 0)
{
return FALSE;
}
pDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB); //得到申请的缓冲区的指针
if (file.ReadHuge(pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER)) !=dwBitsSize - sizeof(BITMAPFILEHEADER) )
{
::GlobalUnlock((HGLOBAL)hDIB);
hDIB=NULL;
return FALSE;
}//读数据,包括位图信息、位图颜色表、图像像素的灰度值
bmhdr=(BITMAPINFOHEADER*)pDIB;//为指向位图信息头结构的指针付值
memcpy(&bi,pDIB,sizeof(BITMAPINFOHEADER));
::GlobalUnlock((HGLOBAL)hDIB);
if ((*bmhdr).biBitCount!=24) //验证是否为真彩色位图
return FALSE;
//由于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及
//新图的缓冲区大小
DstLineBytes=(DWORD)WIDTHBYTES(bi.biWidth*8);
DstBufSize=(DWORD)(sizeof(BITMAPINFOHEADER)+
256*sizeof(RGBQUAD)+
(DWORD)DstLineBytes*bi.biHeight);
//DstBf和DstBi为新的BITMAPFILEHEADER和BITMAPINFOHEADER
//拷贝原来的头信息
memcpy((char *)&DstBf,(char *)&bf,sizeof(BITMAPFILEHEADER));
memcpy((char *)&DstBi,(char *)&bi,sizeof(BITMAPINFOHEADER));
//
做必要的改变
DstBf.bfSize=DstBufSize+sizeof(BITMAPFILEHEADER);
DstBf.bfOffBits=(DWORD)(256*sizeof(RGBQUAD)+
sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER));
DstBi.biClrUsed=0;
DstBi.biBitCount=8;
//OffBits为到实际位图数据的偏移值
OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);
//SrcBufSize为原图缓冲区的大小
int LineBytes=WIDTHBYTES(bi.biWidth*bi.biBitCount);
SrcBufSize=OffBits+bi.biHeight*LineBytes;
if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL)
{
return FALSE;
}
hImgData=LocalAlloc(LHND,SrcBufSize);
lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);
memcpy(lpImgData,pDIB,dwBitsSize - sizeof(BITMAPFILEHEADER));
lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);
//拷贝位图数据
memcpy(lpTempImgData,lpImgData,OffBits);
//用新的头信息取代旧的头信息
memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER));
//ColorHits为记录颜色使用频率的数组,ColorIndex为记录颜色索引值的
//数组
//先全部清零
memset(ColorHits,0,4096*sizeof(DWORD));
memset(ColorIndex,0,4096*sizeof(WORD));
for(y=0;y
lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
for(x=0;x
//R,G,B各取4位
Blue=(int)(*(lpPtr++) & 0xf0);
Green=(int)(*(lpPtr++) & 0xf0);
Red=(int)(*(lpPtr++) & 0xf0);
//拼成一个12位整数
ClrIndex=(Blue<<4) + Green +(Red >>4);
//相应的数组元素加1
ColorHits[ClrIndex]++;
}
}
PalCounts=0;
//将为零的元素清除出去
for (ClrIndex = 0; ClrIndex < 4096; ClrIndex++)
{
if(ColorHits[ClrIndex]!=0){
ColorHits[PalCounts]=ColorHits[ClrIndex];
//注意调整相应的索引值
ColorIndex[PalCounts]=ClrIndex;
PalCounts++; //颜色数加1
}
}
//用起泡排序将PalCounts种颜色按从大到小的顺序排列
for (i = 0; i < PalCounts-1; i++)
for (j = i + 1; j < PalCounts; j++){
if (ColorHits[j] > ColorHits[i]){
temp = ColorHits[i];
ColorHits[i] = ColorHits[j];
ColorHits[j] = temp;
//注意调整相应的索引值
temp = ColorIndex[i];
ColorIndex[i] = ColorIndex[j];
ColorIndex[j] = (WORD)temp;
}
}
//为新的调色板分配内存
hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) +
256* sizeof(PALETTEENTRY));
pPal =(LOGPALETTE *)LocalLock(hPal);
pPal->palNumEntries =(WORD) 256;
pPal->palVersion = 0x300;
lpTempPtr=(char *)lpTempImgData+sizeof(BITMAPINFOHEADER);
for (i = 0; i < 256; i++) {
//由12位索引值得到R,G,B的最高4位值
pPal->palPalEntry[i].peRed=(BYTE)((ColorIndex[i] & 0x00f) << 4);
pPal->pa
lPalEntry[i].peGreen=(BYTE)((ColorIndex[i] & 0x0f0));
pPal->palPalEntry[i].peBlue=(BYTE)((ColorIndex[i] & 0xf00) >> 4);
pPal->palPalEntry[i].peFlags=(BYTE)0;
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0xf00) >> 4);
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0x0f0));
*(lpTempPtr++)=(unsigned char)((ColorIndex[i] & 0x00f) << 4);
*(lpTempPtr++)=0;
//ColorHits作为颜色记数的作用已经完成了,下面的作用是记录12位索
//引值对应的调色板//中的索引值
ColorHits[i]=i;
}
//其余的颜色依据最小平方误差近似为前256中最接近的一种
if (PalCounts > 256){
for (i = 256; i < PalCounts; i++){
//ColorError1记录最小平方误差,一开始赋一个很大的值
ColorError1=1000000000;
//由12位索引值得到R,G,B的最高4位值
Blue = (long)((ColorIndex[i] & 0xf00) >> 4);
Green = (long)((ColorIndex[i] & 0x0f0));
Red = (long)((ColorIndex[i] & 0x00f) << 4);
ClrIndex = 0;
for (j = 0; j < 256; j++){
//ColorError2计算当前的平方误差
ColorError2=(long)(Blue-pPal->palPalEntry[j].peBlue)*
(Blue-pPal->palPalEntry[j].peBlue)+ (long)(Green-pPal->palPalEntry[j].peGreen)*
(Green-pPal->palPalEntry[j].peGreen)+
(long)(Red-pPal->palPalEntry[j].peRed)*
(Red-pPal->palPalEntry[j].peRed);
if (ColorError2 < ColorError1){ //找到更小的了
ColorError1 = ColorError2;
ClrIndex = j; //记录对应的调色板的索引值
}
}
//ColorHits记录12位索引值对应的调色板中的索引值
ColorHits[i] = ClrIndex;
}
}
if(hPalette!=NULL)
DeleteObject(hPalette);
//产生新的逻辑调色板
hPalette=CreatePalette(pPal);
LocalUnlock(hPal);
LocalFree(hPal);
/*
hDc=GetDC(hWnd);
*/
if(hPalette){
hPrevPalette=SelectPalette(hDc,hPalette,FALSE);
RealizePalette(hDc);
}
for(y=0;y
lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes);
lpTempPtr=(char*)lpTempImgData+
(DstBufSize-DstLineBytes-y*DstLineBytes);
for(x=0;x
Blue=(int)(*(lpPtr++) & 0xf0);
Green=(int)(*(lpPtr++) & 0xf0);
Red=(int)(*(lpPtr++) & 0xf0);
//拼成一个12位整数
ClrIndex=(Blue<<4) + Green +(Red >>4);
for (i = 0; i < PalCounts;i++)
if (ClrIndex == ColorIndex[i]){
//根据12索引值取得对应的调色板中的索引值
*(lpTempPtr++)=(unsigned char)ColorHits[i];
break;
}
}
}
if(hBitmap!=NULL)
DeleteObject(hBitmap);
//产生新的位图
hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,(LONG)CBM_INIT,(LPSTR)lpTempImgData+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD),(LPBITMAPINFO)lpTempImgData,DIB_RGB_COLORS);
if(hPalette && hPrevPalette){
SelectPalette(hDc,hPrevPalette,FALSE);
RealizePalette(hDc);
}
hf=_lcreat("c:\\256.bmp",0);
_lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER));
_lwrite(hf,(LPSTR)lpTempImgData,DstBufSize);
_lclose(hf);
//释放内存和资源
LocalUnlock(hTempImgData);
LocalFree(hTempImgData);
GlobalUnlock(hImgData);
return TRUE;
}