LEHEADERifhTempImgDataLocalAllocLHNDDstBufSizeNULL MessageBoxhWndquotError alloc memoryquotquotError MessagequotMB_OK MB_ICONEXCLAMATION return FALSElpImgDataLPBITMAPINFOHEADERGlobalLockhImgDatalpTempImgDataLPBITMAPINFOHEADERLocalLockhTempImgData//拷贝头信息和位图数据memcpylpTempImgDatalpImgDataDstBufSize//用新的 BITMAPINFOHEADER 替换原来的头信息memcpylpTempImgDatachar ampDstBisizeofBITMAPINFOHEADER//lpPtr 指向原图的数据lpPtrchar lpImgDatasizeofBITMAPINFOHEADER//lpTempPtr 指向新图的数据lpTempPtrchar lpTempImgDatasizeofBITMAPINFOHEADER//为新的调色板分配内存hPalLocalAllocLHNDsizeofLOGPALETTE NewNumColors sizeofPALETTEENTRYpPal LOGPALETTE LocalLockhPalpPal-gtpalNumEntries WORD NewNumColorspPal-gtpalVersion 0x300ifNumColors0 //真彩色 for i 0 i lt 256 i //灰度从(000)到255255255 pPal-gtpalPalEntryi.peRedBYTEi pPal-gtpalPalEntryi.peGreenBYTEi pPal-gtpalPalEntryi.peBlueBYTEi pPal-gtpalPalEntryi.peFlagsBYTE0 lpTempPtrunsigned chari lpTempPtrunsigned chari lpTempPtrunsigned chari lpTempPtr0 else for i 0 i lt NewNumColors i //带调色板的彩色图 Blueunsigned char lpPtr Greenunsigned char lpPtr Redunsigned char lpPtr YfloatRed0.299Green0.587Blue0.114 GrayBYTEY lpPtr //从原来的调色板中的颜色计算得到 Y 值,写入新的调色板 pPal-gtpalPalEntryi.peRedGray pPal-gtpalPalEntryi.peGreenGray pPal-gtpalPalEntryi.peBlueGray pPal-gtpalPalEntryi.peFlags0 lpTempPtrunsigned charGray lpTempPtrunsigned charGray lpTempPtrunsigned charGray lpTempPtr0 ifhPaletteNULL DeleteObjecthPalette//生成新的逻辑调色板hPaletteCreatePalettepPalLocalUnlockhPalLocalFreehPalhDcGetDChWndifhPalette hPrevPaletteSelectPalettehDchPaletteFALSE RealizePalettehDcifNumColors0 //真彩色图才需要处理位图数据 fory0yltbi.biHeighty lpPtrchar lpImgDataSrcBufSize-LineBytes-yLineBytes lpTempPtrchar lpTempImgDataDstBufSize-DstLineBytes-yDstLineBytes forx0xltbi.biWidthx Blueunsigned char lpPtr Greenunsigned char lpPtr Redunsigned char lpPtr YfloatRed0.299Green0.587Blue0.114 //从位图数据计算得到 Y 值,写入新图中 GrayBYTEY lpTempPtrunsigned charGray ifhBitmapNULL DeleteObjecthBitmap //产生新的位图 hBitmapCreateDIBitmaphDc LPBITMAPINFOHEADERlpTempImgData LONGCBM_INIT LPSTRlpTempImgDatasizeofBITMAPINFOHEADER NewNumColorssizeofRGBQUAD LPBITMAPINFOlpTempImgData DIB_RGB_COLORS ifhPalette ampamp hPrevPalette SelectPalettehDchPrevPaletteFALSE RealizePalettehDc hf_lcreatquotc:gray.bmpquot0 _lwritehfLPSTRampDstBfsizeofBITMAPFILEHEADER _lwritehfLPSTRlpTempImgDataDstBufSize _lclosehf //释放内存和资源 ReleaseDChWndhDc LocalUnlockhTempImgData LocalFreehTempImgData GlobalUnlockhImgData return TRUE3. 真彩图转 256 色图true color to 256 indexed color 我们知道,真彩图中包含最多达 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 种颜色中,则用代替色的索引值填入位图数据中。
下面的两幅图,图 3 是原真彩图,图 4 是用上面的算法转成的 256 色图,可以看出,效果还不错。
图 3. 原真彩图 图 4. 转换后的 256 色图 下面是上述算法的源程序。
BOOL Trueto256HWND hWnd DWORD SrcBufSizeOffBitsDstBufSizeDstLineBytes LPBITMAPINFOHEADER lpImgData LPSTR lpPtr HLOCAL hTempImgData LPBITMAPINFOHEADER lpTempImgData LPSTR lpTempPtr HDC hDc HFILE hf LONG xy BITMAPFILEHEADER DstBf BITMAPINFOHEADER DstBi LOGPALETTE pPal HPALETTE hPrevPalette HLOCAL hPal WORD ij int RedGreenBlueClrIndex DWORD ColorHits4096 WORD ColorIndex4096 DWORD PalCountstemp long ColorError1ColorError2 ifNumColors0 //NumColors 不为零,所以不是真彩图 MessageBoxhWndquotMust be a true color bitmapquotquotError MessagequotMB_OK MB_ICONEXCLAMATION return FALSE //由于颜色位数有可能发生了改变,所以要重新计算每行占用的字节数以及新图 //的缓冲区大小 DstLineBytesDWORDWIDTHBYTESbi.biWidth8 DstBufSizeDWORDsizeofBITMAPINFOHEADER256sizeofRGBQUAD DWORDDstLineBytesbi.biHeight//DstBf 和 DstBi 为新的 BITMAPFILEHEADER 和 BITMAPINFOHEADER//拷贝原来的头信息memcpychar ampDstBfchar ampbfsizeofBITMAPFILEHEADERmemcpychar ampDstBichar ampbisizeofBITMAPINFOHEADER//做必要的改变DstBf.bfSizeDstBufSizesizeofBITMAPFILEHEADERDstBf.bfOffBitsDWORD256sizeofRGBQUADsizeofBITMAPFILEHEADER sizeofBITMAPINFOHEADERDstBi.biClrUsed0DstBi.biBitCount8//OffBits 为到实际位图数据的偏移值OffBitsbf.bfOffBits-sizeofBITMAPFILEHEADER//SrcBufSize 为原图缓冲区的大小SrcBufSizebf.bfSize-sizeofBITMAPFILEHEADERifhTempImgDataLocalAllocLHNDDstBufSizeNULL MessageBoxhWndquotError alloc memoryquotquotError MessagequotMB_OK MB_ICONEXCLAMATION return FALSElpImgDataLPBITMAPINFOHEADERGlobalLockhImgDatalpTempImgDataLPBITMAPINFOHEADERLocalLockhTempImgData//拷贝位图数据memcpylpTempImgDatalpImgDataOffBits//用新的头信息取代旧的头信息memcpylpTempImgDatachar ampDstBisizeofBITMAPINFOHEADER//ColorHits 为记录颜色使用频率的数组,ColorIndex 为记录颜色索引值的数组//先全部清零memsetColorHits04096sizeofDWORDmemsetColorIndex04096sizeofWORDfory0yltbi.biHeighty lpPtrunsigned char lpImgDataSrcBufSize-LineBytes-yLineBytes forx0xltbi.biWidthx //R,G,B 各取 4 位 BlueintlpPtr amp 0xf0 GreenintlpPtr amp 0xf0 RedintlpPtr
上一篇:
VC编程技术600个大型项目源码
下一篇:
混了21年!