sizeof(RGBQUAD)+(DWORD)DstLineBytes"bi. biHeight) SteF和 DstBi为新的 BITMAPFILEHEADER和 BITMAPINFOHEADER ∥拷贝原来的头信息 memcpy((char *)&DstBf, (char *)&bf, sizeof( BI TMAPFILEHEADER): memcpy((char *)&Dst Bi, (char *)&bi, sizeof( BITMAPINFOHEADER)) ∥(必要的改变 DstBf. bfSize=Dst BufSize+sizeof(BITMAPFILEHEADER) DstBf. bfoffBits=(DWORD)(NewNum Colors*sizeof(RGBQUAD)+ sizeof( BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER) DstBi biclrUsed=o Dstbi bibitcountNewBitcount ∥原图的缓冲区的大小 SrcOffBits-bf. bfoffBits-sizeof(BITMAPFILEHEADER) SrcBufSize=SrcOffBits+bi bi Height *Line Bytes, if((hTemplmg Data=LocalAlloc(LHND, Dst BufSize))==NULL) Message Box(hWnd, Error alloc memory! " Error Message", MB OK MB ICONEXCLAMATION return False lplmg Data=(LPBITMAPINFOHEADER)GlobalLock(hlmg Data) IpTemplmg Data=(LPBITMAPINFOHEADER)LocalLock(hTemplmg Data); ∥拷贝头信息和位图数据 memcpy(lp Templmg Data, lplmg Data, DstBufSize); ∥)新的 BITMAPINFOHEADER替换原来的头信息 emcpy(lp Templmg Data, (char *)&DstBi, sizeof( BITMAPINFOHEADER)) IpPt指向原图的数据 lpPtr=(char *)lplmg Data+sizeof( BITMAPINFOHEADER) IpTempPtr指向新图的数据 lpTempPtr=(char *)lp Templmg Datatsizeof( BITMAPINFOHEADER) ∥新的调色板分配内存 hPal=Local Alloc( LHND, sizeof(LOGPALETTE)+ NewNum Colors s sizeof(PALETTEENTRY)) pPal=(LOGPALETTE *)LocalLock(hPal) pPal->pal NumEntries=( WORD) NewNumColors pPal->pal Version =0X300 f( Num Colors==0)∥真彩色
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)(NewNumColors*sizeof(RGBQUAD)+ sizeof(BITMAPFILEHEADER)+ sizeof(BITMAPINFOHEADER)); DstBi.biClrUsed=0; DstBi.biBitCount=NewBitCount; //原图的缓冲区的大小 SrcOffBits=bf.bfOffBits- sizeof(BITMAPFILEHEADER); SrcBufSize=SrcOffBits+bi.biHeight*LineBytes; if((hTempImgData=LocalAlloc(LHND,DstBufSize))==NULL) { MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK| MB_ICONEXCLAMATION); return FALSE; } lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData); lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData); //拷贝头信息和位图数据 memcpy(lpTempImgData,lpImgData,DstBufSize); //用新的 BITMAPINFOHEADER 替换原来的头信息 memcpy(lpTempImgData,(char *)&DstBi,sizeof(BITMAPINFOHEADER)); //lpPtr 指向原图的数据 lpPtr=(char *)lpImgData+sizeof(BITMAPINFOHEADER); //lpTempPtr 指向新图的数据 lpTempPtr=(char *)lpTempImgData+sizeof(BITMAPINFOHEADER); //为新的调色板分配内存 hPal=LocalAlloc(LHND,sizeof(LOGPALETTE) + NewNumColors * sizeof(PALETTEENTRY)); pPal =(LOGPALETTE *)LocalLock(hPal); pPal->palNumEntries =(WORD) NewNumColors; pPal->palVersion = 0x300; if(NumColors==0) //真彩色
for(i=0,i<256;i++){∥灰度从(0,0,0)到(25525255 pPal->palPal Entry[i]- peRed=(BYTE)i pPal->palPal Entry[i]. peGreen=(BYTE)i pPal->palPal[i]-peBlue=(BYTE)i; )0, *(pTempPtr++) =(unsigned char ) (Ip *(IpTempPtr++) =(unsigned char )1; *(Ip else for(i=0,i< NewNum Colors;i++){∥/带调色板的彩色图 Blue=(unsigned char )(*lpPtr++); reen(unsigned char )("lpPtr++); Red=(unsigned char )("lpPtr++); Y=(foat)Red*0.299Gren*0.587+Blue*0.114); Gray=(BYTE)Y IpPtr++ 从原来的调色板中的颜色计算得到Y值,写入新的调色板 pPal->palPalEntryli]- peRed=Gray oPal->palPalEntryli].-pe Green=Gray; Pal->palPalEntry[i]-peFlags=0 *(IpTempPtr+)=(unsigned char )Gray (pTempPtr++ =(unsigned char)Gray (IpTempPtr++ =(unsigned char )Gray; "(pTempPtr++)=( if(hPalet DeleteObject(hPalette) ∥生成新的逻辑调色板 pAlette Local Unlock (hPal) Dc=GetDC (hWnd) if(pAlette)i hPrev Palette=SelectPalette(h alette, FALSE) RealizePalette(hDc)
for (i = 0; i < 256; i++) { //灰度从(0,0,0)到(255,255,255) pPal->palPalEntry[i].peRed=(BYTE)i; pPal->palPalEntry[i].peGreen=(BYTE)i; pPal->palPalEntry[i].peBlue=(BYTE)i; pPal->palPalEntry[i].peFlags=(BYTE)0; *(lpTempPtr++)=(unsigned char)i; *(lpTempPtr++)=(unsigned char)i; *(lpTempPtr++)=(unsigned char)i; *(lpTempPtr++)=0; } else for (i = 0; i < NewNumColors; i++) { //带调色板的彩色图 Blue=(unsigned char )(*lpPtr++); Green=(unsigned char )(*lpPtr++); Red=(unsigned char )(*lpPtr++); Y=(float)(Red*0.299+Green*0.587+Blue*0.114); Gray=(BYTE)Y; lpPtr++; //从原来的调色板中的颜色计算得到 Y 值,写入新的调色板 pPal->palPalEntry[i].peRed=Gray; pPal->palPalEntry[i].peGreen=Gray; pPal->palPalEntry[i].peBlue=Gray; pPal->palPalEntry[i].peFlags=0; *(lpTempPtr++)=(unsigned char)Gray; *(lpTempPtr++)=(unsigned char)Gray; *(lpTempPtr++)=(unsigned char)Gray; *(lpTempPtr++)=0; } if(hPalette!=NULL) DeleteObject(hPalette); //生成新的逻辑调色板 hPalette=CreatePalette(pPal); LocalUnlock(hPal); LocalFree(hPal); hDc=GetDC(hWnd); if(hPalette){ hPrevPalette=SelectPalette(hDc,hPalette,FALSE); RealizePalette(hDc);
if(NumColors=0)∥真彩色图才需要处理位图数据 for(y=0; y<bi. biHeight; y++)4 lpPtr=(char *)lplmg Data+(SrcBufSize-LineBytes-y*Line Bytes); ( DstBufSize-DstLine Bytes-y* DstLine Bytes) for(x=0 X<bi bi Width, x++) Blue=(unsigned char )(lpPtr++) Green=(unsigned char )(*lpPtr++); nar )("lpPtr++) Y=( float)(Red*0.299Gren*0.587+Bue*0.114) ∥从位图数据计算得到Y值,写入新图中 Gray=(BYTE)Y lpTempPtr++)=(unsigned char )Gray; DeleteObject(h Bitmap) 广产生新的位图 hBitmap=CreateDIBitmap(hDc, (LPBITMAPINFOHEADER)lp Templmg Data (LONG)CBM INIT. (LPSTR)lp Templmg Data+ sizeof( BITMAPINFOHEADER)+ NewNum Colors*sizeof(RGBQUAD) (LPBITMAPINFO)IpTemplmgD DIB RGB COLORS) if(pAlette & hPrevPalette)4 SelectPalette(hDc, hPrevPalette, FALSE) RealizePalette(hDc) hf- Creat("c: gray. bmp",0) Iwrite(hf, (LPSTR)&DstBf, sizeof( BITMAPFILEHEADER)) Iwrite(hf, (LPSTR)IpTemplmg Data, Dst BufSize); Iclose(hf) ∥释放内存和资源 Released(hWnd, hDc) LocalUnlock(hTemplmg Data) Local Free(hTemplmg Data);
} if(NumColors==0) //真彩色图才需要处理位图数据 for(y=0;y<bi.biHeight;y++){ lpPtr=(char *)lpImgData+(SrcBufSize-LineBytes-y*LineBytes); lpTempPtr=(char*)lpTempImgData+ (DstBufSize-DstLineBytes-y*DstLineBytes); for(x=0;x<bi.biWidth;x++){ Blue=(unsigned char )(*lpPtr++); Green=(unsigned char )(*lpPtr++); Red=(unsigned char )(*lpPtr++); Y=(float)(Red*0.299+Green*0.587+Blue*0.114); //从位图数据计算得到 Y 值,写入新图中 Gray=(BYTE)Y; *(lpTempPtr++)=(unsigned char)Gray; } } if(hBitmap!=NULL) DeleteObject(hBitmap); //产生新的位图 hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData, (LONG)CBM_INIT, (LPSTR)lpTempImgData+ sizeof(BITMAPINFOHEADER)+ NewNumColors*sizeof(RGBQUAD), (LPBITMAPINFO)lpTempImgData, DIB_RGB_COLORS); if(hPalette && hPrevPalette){ SelectPalette(hDc,hPrevPalette,FALSE); RealizePalette(hDc); } hf=_lcreat("c:\\gray.bmp",0); _lwrite(hf,(LPSTR)&DstBf,sizeof(BITMAPFILEHEADER)); _lwrite(hf,(LPSTR)lpTempImgData,DstBufSize); _lclose(hf); //释放内存和资源 ReleaseDC(hWnd,hDc); LocalUnlock(hTempImgData); LocalFree(hTempImgData);
Global Unlock(hmg Data) return tRUe 53真彩图转256色图 我们知道,真彩图中包含最多达24种颜色,怎样从中选出256种颜色,又要使颜色的失真 比较小,这是一个比较复杂的问题。一种简单的做法是将R:G:B以3:3:2表示,即取 R,G的高3位,B的高两位,组成一个字节,这样就可以表示256种颜色了,但不难想象, 这种方法的失真肯定很严重 我们下面介绍的算法能够比较好地实现真彩图到256色图的转换。它的思想是:准备一个长 度为4096的数组,代表40%6种颜色。对图中的每一个象素,取R、G、B的最高四位,拼 成一个12位的整数,对应的数组元素加1。全部统计完后,就得到了这4096种颜色的使用 频率。其中,可能有一些颜色一次也没用到,即对应的数组元素为零(假设不为零的数组元 素共有 PalCounts个)。将这些为零的数组元素清除出去,使得前 PalCounts个元素都不为零。 将这 PalCounts个数按从大到小的顺序排列(这里我们使用起泡排序)。这样,前256种颜色 就是用的最多的颜色,它们将作为调色板上的256种颜色。对于剩下的 PalCounts256种颜 色并不是简单地丢弃,而是用前256种颜色中的一种来代替,代替的原则是找有最小平方误 差的那个。再次对图中的每一个象素,取R、G、B的最高四位,拼成一个12位的整数 如果对应值在前256种颜色中,则直接将该索引值填入位图数据中,如果是在后 AcoUnts-256种颜色中,则用代替色的索引值填入位图数据中 下面的两幅图中,图5.3是原真彩图,图54是用上面的算法转换成的256色图,可以看出, 效果还不错。 图53原真彩图 图54转换后的256色图 下面是上述算法的源程序。 BOOL Trueto256(HWND hwnd) DWORD SrcBufSize, OffBits, Dst BufSize, DstLineBy LPBITMAPINFOHEADER IplmgData
GlobalUnlock(hImgData); return TRUE; } 5.3 真彩图转 256 色图 我们知道,真彩图中包含最多达 2 24 种颜色,怎样从中选出 256 种颜色,又要使颜色的失真 比较小,这是一个比较复杂的问题。一种简单的做法是将 R:G:B 以 3:3:2 表示,即取 R,G 的高 3 位,B 的高两位,组成一个字节,这样就可以表示 256 种颜色了,但不难想象, 这种方法的失真肯定很严重。 我们下面介绍的算法能够比较好地实现真彩图到 256 色图的转换。它的思想是:准备一个长 度为 4096 的数组,代表 4096 种颜色。对图中的每一个象素,取 R、G、B 的最高四位,拼 成一个 12 位的整数,对应的数组元素加 1。全部统计完后,就得到了这 4096 种颜色的使用 频率。其中,可能有一些颜色一次也没用到,即对应的数组元素为零(假设不为零的数组元 素共有 PalCounts 个)。将这些为零的数组元素清除出去,使得前 PalCounts 个元素都不为零。 将这 PalCounts 个数按从大到小的顺序排列(这里我们使用起泡排序)。这样,前 256 种颜色 就是用的最多的颜色,它们将作为调色板上的 256 种颜色。对于剩下的 PalCounts-256 种颜 色并不是简单地丢弃,而是用前 256 种颜色中的一种来代替,代替的原则是找有最小平方误 差的那个。再次对图中的每一个象素,取 R、G、B 的最高四位,拼成一个 12 位的整数, 如果对应值在前 256 种颜色中,则直接将该索引值填入位图数据中,如果是在后 PalCounts-256 种颜色中,则用代替色的索引值填入位图数据中。 下面的两幅图中,图 5.3 是原真彩图,图.54 是用上面的算法转换成的 256 色图,可以看出, 效果还不错。 图 5.3 原真彩图 图 5.4 转换后的 256 色图 下面是上述算法的源程序。 BOOL Trueto256(HWND hWnd) { DWORD SrcBufSize,OffBits,DstBufSize,DstLineBytes; LPBITMAPINFOHEADER lpImgData;
LPSTR IpPr HLOCAL tEmpl LPBITMAPINFOHEADER lp TemplmgData; LPSTR lpTempPtr HFILE LONG x,y, BITMAPFILEHEADER DstBf BITMAPINFOHEADER Dst Bi LOGPALETTE HPALETTE hPrev Palette HLOCAL WORD Red green Blue. Clrlnde DWORD Color Hits( 4096 ColorIndex[4096 Pal Counts, temp Color Error l Color Error2 if( Num Colors!=0){/ Num Colors不为零,所以不是真彩图 Message Box(hWnd, Must be a true color bitmap ! " "Error Message" MB OK MB ICONEXCLAMATION) return falses ∥于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及 ∥新图的缓冲区大小 DstLineBytes=(DWORD)WIDTHBYTES(bibi Width*8); Dst BufSize=(DWORD)(sizeof( BITMAPINFOHEADER)+ 256*sizeof(RGBQUAD)+ (DWORD)DstLine Bytes*bi. biHeight); SteF和 Dstbi为新的 BITMAPFILEHEADER和 BITMAPINFOHEADER ∥拷贝原来的头信息 memcpy((char *)&DstBf, (char *)&bf, sizeof( BITMAPFILEHEADER)); memcpy((char *)&Dst Bi, (char *)&bi, sizeof(BITMAPINFOHEADER)) ∥做必要的改变 DstBf. bfSize=Dst BufSize+sizeof( BITMAPFILEHEADER) DstBf. bfoffBits=(DWORD)(256*sizeof(RGBQUAD)+ sizeof( BITMAPFILEHEADEl +sizeof(BITMAPINFOHEADER))
LPSTR lpPtr; HLOCAL hTempImgData; LPBITMAPINFOHEADER lpTempImgData; LPSTR lpTempPtr; HDC hDc; HFILE hf; LONG x,y; BITMAPFILEHEADER DstBf; BITMAPINFOHEADER DstBi; LOGPALETTE *pPal; HPALETTE hPrevPalette; HLOCAL hPal; WORD i,j; int Red,Green,Blue,ClrIndex; DWORD ColorHits[4096]; WORD ColorIndex[4096]; DWORD PalCounts,temp; long ColorError1,ColorError2; if(NumColors!=0){ //NumColors 不为零,所以不是真彩图 MessageBox(hWnd,"Must be a true color bitmap!","Error Message", MB_OK|MB_ICONEXCLAMATION); 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));