#include "stdafx.h" #include "EnBitmap.h" #include #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #define new DEBUG_NEW #endif const int HIMETRIC_INCH = 2540; enum { FT_BMP, FT_ICO, FT_JPG, FT_GIF, FT_UNKNOWN }; CEnBitmap::CEnBitmap() { } CEnBitmap::~CEnBitmap() { } BOOL CEnBitmap::LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst, COLORREF crBack) { ASSERT(m_hObject == NULL); // only attach once, detach on destroy if (m_hObject != NULL) return FALSE; return Attach(LoadImageResource(uIDRes, szResourceType, hInst, crBack)); } BOOL CEnBitmap::LoadImage(LPCTSTR szImagePath, COLORREF crBack) { //如果原先存在就去除 if (m_hObject != NULL) { DeleteObject(); Detach(); } return Attach(LoadImageFile(szImagePath, crBack)); } HBITMAP CEnBitmap::LoadImageFile(LPCTSTR szImagePath, COLORREF crBack) { int nType = GetFileType(szImagePath); switch (nType) { // the reason for this is that i suspect it is more efficient to load // bmps this way since it avoids creating device contexts etc that the // IPicture methods requires. that method however is still valuable // since it handles other image types and transparency case FT_BMP: return (HBITMAP)::LoadImage(NULL, szImagePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); case FT_UNKNOWN: return NULL; default: // all the rest { USES_CONVERSION; IPicture* pPicture = NULL; HBITMAP hbm = NULL; HRESULT hr = OleLoadPicturePath(LPOLESTR(szImagePath), NULL, 0, crBack, IID_IPicture, (LPVOID *)&pPicture); if (pPicture) { hbm = ExtractBitmap(pPicture, crBack); pPicture->Release(); } return hbm; } } return NULL; // can't get here } HBITMAP CEnBitmap::LoadImageResource(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst, COLORREF crBack) { BYTE* pBuff = NULL; int nSize = 0; HBITMAP hbm = NULL; // first call is to get buffer size if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, 0, nSize)) { if (nSize > 0) { pBuff = new BYTE[nSize]; // this loads it if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, pBuff, nSize)) { IPicture* pPicture = LoadFromBuffer(pBuff, nSize); if (pPicture) { hbm = ExtractBitmap(pPicture, crBack); pPicture->Release(); } } delete[] pBuff; } } return hbm; } IPicture* CEnBitmap::LoadFromBuffer(BYTE* pBuff, int nSize) { bool bResult = false; HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize); void* pData = GlobalLock(hGlobal); memcpy(pData, pBuff, nSize); GlobalUnlock(hGlobal); IStream* pStream = NULL; IPicture* pPicture = NULL; if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) == S_OK) { HRESULT hr = OleLoadPicture(pStream, nSize, FALSE, IID_IPicture, (LPVOID *)&pPicture); pStream->Release(); } return pPicture; // caller releases } BOOL CEnBitmap::GetResource(LPCTSTR lpName, LPCTSTR lpType, HMODULE hInst, void* pResource, int& nBufSize) { HRSRC hResInfo; HANDLE hRes; LPSTR lpRes = NULL; int nLen = 0; bool bResult = FALSE; // Find the resource hResInfo = FindResource(hInst, lpName, lpType); if (hResInfo == NULL) return false; // Load the resource hRes = LoadResource(hInst, hResInfo); if (hRes == NULL) return false; // Lock the resource lpRes = (char*)LockResource(hRes); if (lpRes != NULL) { if (pResource == NULL) { nBufSize = SizeofResource(hInst, hResInfo); bResult = true; } else { if (nBufSize >= (int)SizeofResource(hInst, hResInfo)) { memcpy(pResource, lpRes, nBufSize); bResult = true; } } UnlockResource(hRes); } // Free the resource FreeResource(hRes); return bResult; } HBITMAP CEnBitmap::ExtractBitmap(IPicture* pPicture, COLORREF crBack) { ASSERT(pPicture); if (!pPicture) return NULL; CBitmap bmMem; CDC dcMem; CDC* pDC = CWnd::GetDesktopWindow()->GetDC(); if (dcMem.CreateCompatibleDC(pDC)) { long hmWidth; long hmHeight; pPicture->get_Width(&hmWidth); pPicture->get_Height(&hmHeight); int nWidth = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH); int nHeight = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH); if (bmMem.CreateCompatibleBitmap(pDC, nWidth, nHeight)) { CBitmap* pOldBM = dcMem.SelectObject(&bmMem); if (crBack != -1) dcMem.FillSolidRect(0, 0, nWidth, nHeight, crBack); HRESULT hr = pPicture->Render(dcMem, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, NULL); dcMem.SelectObject(pOldBM); } } CWnd::GetDesktopWindow()->ReleaseDC(pDC); return (HBITMAP)bmMem.Detach(); } int CEnBitmap::GetFileType(LPCTSTR szImagePath) { CString sPath(szImagePath); sPath.MakeUpper(); if (sPath.Find(_T(".BMP")) > 0) return FT_BMP; else if (sPath.Find(_T(".ICO")) > 0) return FT_ICO; else if (sPath.Find(_T(".JPG")) > 0 || sPath.Find(_T(".JPEG")) > 0) return FT_JPG; else if (sPath.Find(_T(".GIF")) > 0) return FT_GIF; // else return FT_UNKNOWN; } ///////////////////////////////////////////////////////////////////// // Converts a bitmap to a region // // BitmapToRegion : Create a region from the "non-transparent" pixels of a bitmap // Author : Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998. // // hBmp : Source bitmap // cTransparentColor : Color base for the "transparent" pixels (default is black) // cTolerance : Color tolerance for the "transparent" pixels. // // A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is // greater or equal to the corresponding value in cTransparentColor and is lower or equal to the // corresponding value in cTransparentColor + cTolerance. // HRGN CEnBitmap::BitmapToRegion(COLORREF cTransparentColor, COLORREF cTolerance) { HBITMAP hBmp = (HBITMAP)GetSafeHandle(); HRGN hRgn = NULL; if (hBmp) { // Create a memory DC inside which we will scan the bitmap content HDC hMemDC = CreateCompatibleDC(NULL); if (hMemDC) { // Get bitmap size BITMAP bm; ::GetObject(hBmp, sizeof(bm), &bm); // Create a 32 bits depth bitmap and select it into the memory DC BITMAPINFOHEADER RGB32BITSBITMAPINFO = { sizeof(BITMAPINFOHEADER), // biSize bm.bmWidth, // biWidth; bm.bmHeight, // biHeight; 1, // biPlanes; 32, // biBitCount BI_RGB, // biCompression; 0, // biSizeImage; 0, // biXPelsPerMeter; 0, // biYPelsPerMeter; 0, // biClrUsed; 0 // biClrImportant; }; VOID * pbits32; HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0); if (hbm32) { HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32); // Create a DC just to copy the bitmap into the memory DC HDC hDC = CreateCompatibleDC(hMemDC); if (hDC) { // Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits) BITMAP bm32; ::GetObject(hbm32, sizeof(bm32), &bm32); while (bm32.bmWidthBytes % 4) bm32.bmWidthBytes++; // Copy the bitmap into the memory DC HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp); BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY); // For better performances, we will use the ExtCreateRegion() function to create the // region. This function take a RGNDATA structure on entry. We will add rectangles by // amount of ALLOC_UNIT number in this structure. #define ALLOC_UNIT 100 DWORD maxRects = ALLOC_UNIT; HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects)); RGNDATA *pData = (RGNDATA *)GlobalLock(hData); pData->rdh.dwSize = sizeof(RGNDATAHEADER); pData->rdh.iType = RDH_RECTANGLES; pData->rdh.nCount = pData->rdh.nRgnSize = 0; SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); // Keep on hand highest and lowest values for the "transparent" pixels BYTE lr = GetRValue(cTransparentColor); BYTE lg = GetGValue(cTransparentColor); BYTE lb = GetBValue(cTransparentColor); BYTE hr = min(0xff, lr + GetRValue(cTolerance)); BYTE hg = min(0xff, lg + GetGValue(cTolerance)); BYTE hb = min(0xff, lb + GetBValue(cTolerance)); // Scan each bitmap row from bottom to top (the bitmap is inverted vertically) BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes; for (int y = 0; y < bm.bmHeight; y++) { // Scan each bitmap pixel from left to right for (int x = 0; x < bm.bmWidth; x++) { // Search for a continuous range of "non transparent pixels" int x0 = x; LONG *p = (LONG *)p32 + x; while (x < bm.bmWidth) { BYTE b = GetRValue(*p); if (b >= lr && b <= hr) { b = GetGValue(*p); if (b >= lg && b <= hg) { b = GetBValue(*p); if (b >= lb && b <= hb) // This pixel is "transparent" break; } } p++; x++; } if (x > x0) { // Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region if (pData->rdh.nCount >= maxRects) { GlobalUnlock(hData); maxRects += ALLOC_UNIT; hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE); pData = (RGNDATA *)GlobalLock(hData); } RECT *pr = (RECT *)&pData->Buffer; SetRect(&pr[pData->rdh.nCount], x0, y, x, y + 1); if (x0 < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0; if (y < pData->rdh.rcBound.top) pData->rdh.rcBound.top = y; if (x > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x; if (y + 1 > pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y + 1; pData->rdh.nCount++; // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too // large (ie: > 4000). Therefore, we have to create the region by multiple steps. if (pData->rdh.nCount == 2000) { HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); ::DeleteObject(h); } else hRgn = h; pData->rdh.nCount = 0; SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); } } } // Go to next row (remember, the bitmap is inverted vertically) p32 -= bm32.bmWidthBytes; } // Create or extend the region with the remaining rectangles HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); ::DeleteObject(h); } else hRgn = h; // Clean up GlobalFree(hData); SelectObject(hDC, holdBmp); DeleteDC(hDC); } ::DeleteObject(SelectObject(hMemDC, holdBmp)); } DeleteDC(hMemDC); } } return hRgn; } BOOL CEnBitmap::Draw(CDC *pDC, LPRECT r) { CDC dc; dc.CreateCompatibleDC(pDC); CBitmap * bmp = dc.SelectObject(this); pDC->BitBlt(r->left, r->top, r->right - r->left, r->bottom - r->top, &dc, 0, 0, SRCCOPY); dc.SelectObject(bmp); return TRUE; } // TransparentBlt - Copies a bitmap transparently onto the destination DC // hdcDest - Handle to destination device context // nXDest - x-coordinate of destination rectangle's upper-left corner // nYDest - y-coordinate of destination rectangle's upper-left corner // nWidth - Width of destination rectangle // nHeight - height of destination rectangle // hBitmap - Handle of the source bitmap // nXSrc - x-coordinate of source rectangle's upper-left corner // nYSrc - y-coordinate of source rectangle's upper-left corner // colorTransparent - The transparent color // hPal - Logical palette to be used with bitmap. Can be NULL /************************************************************************/ /* 函数:TransparentBlt[8/23/2016 IT]; /* 描述:将透明位图拷贝到目标; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEnBitmap::TransparentBlt(IN CDC &dc, IN CRect rc, IN UINT colorTransparent) { CDC pDC; pDC.CreateCompatibleDC(&dc); HBITMAP hOldBmp = (HBITMAP) ::SelectObject(pDC.m_hDC, m_hObject); ::TransparentBlt(dc.GetSafeHdc(), rc.left, rc.top, rc.Width(), rc.Height(), pDC.GetSafeHdc(), 0, 0, GetWidth(), GetHeight(), colorTransparent); ::SelectObject(pDC.m_hDC, hOldBmp); pDC.DeleteDC(); } // DrawGreyScale - Draws a bitmap in Grey scale // pDC - Pointer to target device context // hDIB - Handle of device-independent bitmap // void CEnBitmap::DrawGreyScale(CDC *pDC) { CPalette pal; CPalette *pOldPalette = 0; HBITMAP hBmp = (HBITMAP)this->GetSafeHandle(); // allocate memory for extended image information BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8]; memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8); bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // get extended information about image (length, compression, length of color table if exist, ...) DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS); // allocate memory for image data (colors) LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4]; res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS); int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed : 1 << bmInfo.bmiHeader.biBitCount; int nWidth = bmInfo.bmiHeader.biWidth; int nHeight = bmInfo.bmiHeader.biHeight; // Compute the address of the bitmap bits LPVOID lpDIBBits; if (bmInfo.bmiHeader.biBitCount > 8) lpDIBBits = (LPVOID)((LPDWORD)(pBits + bmInfo.bmiHeader.biClrUsed) + ((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0)); else lpDIBBits = (LPVOID)(pBits + nColors); // Create the palette if needed if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && nColors <= 256) { // The device supports a palette and bitmap has color table // Allocate memory for a palette UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors); LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; pLP->palVersion = 0x300; pLP->palNumEntries = nColors; for (int i = 0; i < nColors; i++) { int nGrey = Grey(bmInfo.bmiColors[i].rgbRed, bmInfo.bmiColors[i].rgbGreen, bmInfo.bmiColors[i].rgbBlue); pLP->palPalEntry[i].peRed = nGrey; pLP->palPalEntry[i].peGreen = nGrey; pLP->palPalEntry[i].peBlue = nGrey; pLP->palPalEntry[i].peFlags = 0; } pal.CreatePalette(pLP); delete[] pLP; // Select the palette pOldPalette = pDC->SelectPalette(&pal, FALSE); pDC->RealizePalette(); } else { // Modify the bitmaps pixels directly // Note : This ends up changing the DIB. If that is not acceptable then // copy the DIB and then change the copy rather than the original if (bmInfo.bmiHeader.biBitCount == 24 || bmInfo.bmiHeader.biBitCount == 32) { BYTE *dst = (BYTE*)lpDIBBits; int Size = nWidth*nHeight; while (Size--) { int nGrey = Grey(dst[2], dst[1], dst[0]); dst[0] = (BYTE)nGrey; dst[1] = (BYTE)nGrey; dst[2] = (BYTE)nGrey; dst += 4; } } else if (bmInfo.bmiHeader.biBitCount == 16) { WORD *dst = (WORD*)lpDIBBits; int Size = nWidth*nHeight; while (Size--) { BYTE b = (BYTE)((*dst)&(0x1F)); BYTE g = (BYTE)(((*dst) >> 5)&(0x1F)); BYTE r = (BYTE)(((*dst) >> 10)&(0x1F)); int nGrey = Grey(r, g, b); *dst++ = ((WORD)(((BYTE)(nGrey) | ((WORD)((BYTE)(nGrey)) << 5)) | (((DWORD)(BYTE)(nGrey)) << 10))); } } } // Draw the image ::SetDIBitsToDevice(pDC->m_hDC, // hDC 0, // XDest 0, // YDest nWidth, // nDestWidth nHeight, // nDestHeight 0, // XSrc 0, // YSrc 0, // nStartScan nHeight, // nNumScans lpDIBBits, // lpBits &bmInfo, // lpBitsInfo DIB_RGB_COLORS); // wUsage if (pOldPalette) pDC->SelectPalette(pOldPalette, FALSE); } // // DitherBlt : Draw a bitmap dithered (3D grayed effect like disabled buttons in toolbars) into a destination DC // Author : Jean-Edouard Lachand-Robert (iamwired@geocities.com), June 1997. // // hdcDest : destination DC // nXDest : x coordinate of the upper left corner of the destination rectangle into the DC // nYDest : y coordinate of the upper left corner of the destination rectangle into the DC // nWidth : width of the destination rectangle into the DC // nHeight : height of the destination rectangle into the DC // hbm : the bitmap to draw (as a part or as a whole) // nXSrc : x coordinates of the upper left corner of the source rectangle into the bitmap // nYSrc : y coordinates of the upper left corner of the source rectangle into the bitmap // void CEnBitmap::DitherBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HBITMAP hbm, int nXSrc, int nYSrc) { ASSERT(hdcDest && hbm); ASSERT(nWidth > 0 && nHeight > 0); // Create a generic DC for all BitBlts HDC hDC = CreateCompatibleDC(hdcDest); ASSERT(hDC); if (hDC) { // Create a DC for the monochrome DIB section HDC bwDC = CreateCompatibleDC(hDC); ASSERT(bwDC); if (bwDC) { // Create the monochrome DIB section with a black and white palette struct { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[2]; } RGBBWBITMAPINFO = { { // a BITMAPINFOHEADER sizeof(BITMAPINFOHEADER), // biSize nWidth, // biWidth; nHeight, // biHeight; 1, // biPlanes; 1, // biBitCount BI_RGB, // biCompression; 0, // biSizeImage; 0, // biXPelsPerMeter; 0, // biYPelsPerMeter; 0, // biClrUsed; 0 // biClrImportant; }, { { 0x00, 0x00, 0x00, 0x00 }, { 0xFF, 0xFF, 0xFF, 0x00 } } }; VOID *pbitsBW; HBITMAP hbmBW = CreateDIBSection(bwDC, (LPBITMAPINFO)&RGBBWBITMAPINFO, DIB_RGB_COLORS, &pbitsBW, NULL, 0); ASSERT(hbmBW); if (hbmBW) { // Attach the monochrome DIB section and the bitmap to the DCs SelectObject(bwDC, hbmBW); SelectObject(hDC, hbm); // BitBlt the bitmap into the monochrome DIB section BitBlt(bwDC, 0, 0, nWidth, nHeight, hDC, nXSrc, nYSrc, SRCCOPY); // Paint the destination rectangle in gray FillRect(hdcDest, CRect(nXDest, nYDest, nXDest + nWidth, nYDest + nHeight), GetSysColorBrush(COLOR_3DFACE)); // BitBlt the black bits in the monochrome bitmap into COLOR_3DHILIGHT bits in the destination DC // The magic ROP comes from the Charles Petzold's book HBRUSH hb = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT)); HBRUSH oldBrush = (HBRUSH)SelectObject(hdcDest, hb); BitBlt(hdcDest, nXDest + 1, nYDest + 1, nWidth, nHeight, bwDC, 0, 0, 0xB8074A); // BitBlt the black bits in the monochrome bitmap into COLOR_3DSHADOW bits in the destination DC hb = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW)); ::DeleteObject(SelectObject(hdcDest, hb)); BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, bwDC, 0, 0, 0xB8074A); ::DeleteObject(SelectObject(hdcDest, oldBrush)); } VERIFY(DeleteDC(bwDC)); } VERIFY(DeleteDC(hDC)); } } // CreateReservedPalette - Create a palette using the PC_RESERVED flag // Limit the colors to 236 colors // Returns - Handle to a palette object // hDIB - Handle to a device-independent bitmap // HPALETTE CEnBitmap::CreateReservedPalette(CDC *pDC) { HPALETTE hPal = NULL; // handle to a palette HBITMAP hBmp = (HBITMAP)this->GetSafeHandle(); // get image properties //BITMAP bmp = { 0 }; //::GetObject( hBmp, sizeof(BITMAP), &bmp ); // allocate memory for extended image information BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8]; memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8); bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // get extended information about image (length, compression, length of color table if exist, ...) DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS); // allocate memory for image data (colors) LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4]; res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS); int nWidth = bmInfo.bmiHeader.biWidth; int nHeight = bmInfo.bmiHeader.biHeight; int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed : 1 << bmInfo.bmiHeader.biBitCount; if (nColors > 256) return NULL; // No Palette //allocate memory block for logical palette UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors); LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; // Initialize the palette version pLP->palVersion = 0x300; // If it is a 256 color DIB, then let's find the most used 236 colors // and make a palette out of those colors if (nColors > 236) { typedef struct _tagBESTCOLORS { DWORD dwColorCnt; //Count of how many times a color is used BOOL bDontUse; //Should we use this color? } BESTCOLORS; BESTCOLORS bc[256]; BYTE dwLeastUsed[20]; // Least used color indices LPSTR lpBits; // pointer to D.I. bits of a DIB int nWidth, nHeight, nBytesPerLine, cx, cy; ::ZeroMemory(bc, 256 * sizeof(BESTCOLORS)); lpBits = (LPSTR)(pBits + nColors); nWidth = bmInfo.bmiHeader.biWidth; nHeight = bmInfo.bmiHeader.biHeight; nBytesPerLine = ((((bmInfo.bmiHeader.biWidth * bmInfo.bmiHeader.biBitCount) + 31) & ~31) / 8); // Traverse through all of the bits in the bitmap and place the // color count of each color in the BESTCOLORS array for (cy = 0; cy < nHeight; cy++) for (cx = 0; cx < nWidth; cx++) bc[*(LPBYTE)(lpBits + cy*nBytesPerLine + cx)].dwColorCnt++; // Let's arbitrarily place the first few colors in the "Least Used" list. int nReject = nColors - 236; for (cx = 0; cx < nReject; cx++) { bc[cx].bDontUse = TRUE; dwLeastUsed[cx] = cx; } // Now, let's traverse through all of the colors and // sort out the least used for (cx = 0; cx < nColors; cx++) { cy = 0; while ((!(bc[cx].bDontUse)) && cy < nReject) { if (bc[cx].dwColorCnt < bc[dwLeastUsed[cy]].dwColorCnt) { bc[dwLeastUsed[cy]].bDontUse = FALSE; dwLeastUsed[cy] = cx; bc[cx].bDontUse = TRUE; } cy++; } } // We want only 236 colors, so that the 20 system colors // are left untouched pLP->palNumEntries = 236; cx = 0; for (int i = 0; i < nColors; i++) { // Should we use this color? if (!((bc[i].bDontUse))) { pLP->palPalEntry[cx].peRed = bmInfo.bmiColors[i].rgbRed; pLP->palPalEntry[cx].peGreen = bmInfo.bmiColors[i].rgbGreen; pLP->palPalEntry[cx].peBlue = bmInfo.bmiColors[i].rgbBlue; pLP->palPalEntry[cx].peFlags = PC_RESERVED; cx++; } } } else if (nColors) { // We have enough room for all the colors pLP->palNumEntries = nColors; // Copy the colors for (int i = 0; i < nColors; i++) { pLP->palPalEntry[i].peRed = bmInfo.bmiColors[i].rgbRed; pLP->palPalEntry[i].peGreen = bmInfo.bmiColors[i].rgbGreen; pLP->palPalEntry[i].peBlue = bmInfo.bmiColors[i].rgbBlue; pLP->palPalEntry[i].peFlags = PC_RESERVED; } } hPal = CreatePalette(pLP); delete[] pLP; // return handle to DIB's palette return hPal; } // FadeColorToGrayScale - Draws a bitmap in color slowly turns it to grayscale // pDC - Pointer to target device context // hDIB - Handle of device-independent bitmap // xDest - x-coordinate of upper-left corner of dest. rect. // yDest - y-coordinate of upper-left corner of dest. rect. // nLoops - How many loops to fade the image into color // nDelay - Delay in milli-seconds between each loop // void CEnBitmap::FadeColorToGrayScale(CDC *pDC, int xDest, int yDest, int nLoops, int nDelay) { CPalette pal; CPalette *pOldPalette; PALETTEENTRY peAnimate[256]; PALETTEENTRY peGray[256]; PALETTEENTRY peOriginal[256]; HBITMAP hBmp = (HBITMAP)this->GetSafeHandle(); // get image properties //BITMAP bmp = { 0 }; //::GetObject( hBmp, sizeof(BITMAP), &bmp ); // allocate memory for extended image information BITMAPINFO &bmInfo = *(LPBITMAPINFO) new BYTE[sizeof(BITMAPINFO) + 8]; memset(&bmInfo, 0, sizeof(BITMAPINFO) + 8); bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // get extended information about image (length, compression, length of color table if exist, ...) DWORD res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, GetHeight(), 0, &bmInfo, DIB_RGB_COLORS); // allocate memory for image data (colors) LPBYTE pBits = new BYTE[bmInfo.bmiHeader.biSizeImage + 4]; res = GetDIBits(pDC->GetSafeHdc(), hBmp, 0, bmInfo.bmiHeader.biHeight, pBits, &bmInfo, DIB_RGB_COLORS); int nColors = bmInfo.bmiHeader.biClrUsed ? bmInfo.bmiHeader.biClrUsed : 1 << bmInfo.bmiHeader.biBitCount; int nWidth = bmInfo.bmiHeader.biWidth; int nHeight = bmInfo.bmiHeader.biHeight; // Compute the address of the bitmap bits LPVOID lpDIBBits; if (bmInfo.bmiHeader.biBitCount > 8) lpDIBBits = (LPVOID)((LPDWORD)(pBits + bmInfo.bmiHeader.biClrUsed) + ((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0)); else lpDIBBits = (LPVOID)(pBits + nColors); int nReservedColors = nColors > 236 ? 236 : nColors; // Create the palette if needed if (pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && nColors <= 256) { // The device supports a palette and bitmap has color table HPALETTE hPal = CreateReservedPalette(pDC); pal.Attach(hPal); // Now save the original colors and get the grayscale colors int i = 0; pal.GetPaletteEntries(0, nReservedColors, (LPPALETTEENTRY)&peOriginal); for (i = 0; i < nReservedColors; i++) { int nGray = Grey(peOriginal[i].peRed, peOriginal[i].peGreen, peOriginal[i].peBlue); peGray[i].peRed = nGray; peGray[i].peGreen = nGray; peGray[i].peBlue = nGray; } // Select the palette pOldPalette = pDC->SelectPalette(&pal, FALSE); pDC->RealizePalette(); ::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0, 0, 0, nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS); // Now animate palette to set the image to grayscale for (i = 1; i <= nLoops; i++) { for (int j = 0; j < nColors; j++) { peAnimate[j].peRed = peOriginal[j].peRed - ((peOriginal[j].peRed - peGray[j].peRed)*i) / nLoops; peAnimate[j].peGreen = peOriginal[j].peGreen - ((peOriginal[j].peGreen - peGray[j].peGreen)*i) / nLoops; peAnimate[j].peBlue = peOriginal[j].peBlue - ((peOriginal[j].peBlue - peGray[j].peBlue)*i) / nLoops; peAnimate[j].peFlags = peOriginal[j].peFlags; } pal.AnimatePalette(0, nColors, (LPPALETTEENTRY)&peAnimate); // Delay... Sleep(nDelay); } // Select the old palette back pDC->SelectPalette(pOldPalette, FALSE); } else if ((pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE) == 0 && nColors <= 256) { // Now change the image to grayscale for (int i = 1; i <= nLoops; i++) { BYTE *dst = (BYTE*)lpDIBBits; int Size = nWidth*nHeight; while (Size--) { int nGrey = Grey(dst[2], dst[1], dst[0]); dst[2] = (BYTE)dst[2] - ((dst[2] - nGrey)*i) / nLoops; dst[1] = (BYTE)dst[1] - ((dst[1] - nGrey)*i) / nLoops; dst[0] = (BYTE)dst[0] - ((dst[0] - nGrey)*i) / nLoops; dst += 4; } // Draw the image again ::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0, 0, 0, nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS); // Delay... Sleep(nDelay); } } else { ::SetDIBitsToDevice(pDC->m_hDC, xDest, yDest, nWidth, nHeight, 0, 0, 0, nHeight, lpDIBBits, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS); } } void CEnBitmap::AlphaDisplay(CDC *pDC, BYTE bAlpha) { CDC dc; dc.CreateCompatibleDC(pDC); CBitmap * bmp = dc.SelectObject(this); BLENDFUNCTION rBlendProps; rBlendProps.BlendOp = AC_SRC_OVER; rBlendProps.BlendFlags = 0; rBlendProps.AlphaFormat = 0; rBlendProps.SourceConstantAlpha = bAlpha; BITMAP bmInfo; ::GetObject(m_hObject, sizeof(BITMAP), &bmInfo); INT nWidth, nHeigh; nWidth = bmInfo.bmWidth; nHeigh = bmInfo.bmHeight; AlphaBlend(pDC->m_hDC, 0, 0, nWidth, nHeigh, dc.m_hDC, 0, 0, nWidth, nHeigh, rBlendProps); dc.SelectObject(bmp); } /* ExtCreateRegion replacement */ HRGN CEnBitmap::CreateRegionExt(DWORD nCount, CONST RGNDATA *pRgnData) { HRGN hRgn = CreateRectRgn(0, 0, 0, 0); const DWORD RDHDR = sizeof(RGNDATAHEADER); ASSERT(hRgn != NULL); LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR); for (int i = 0; i < (int)nCount; i++) { HRGN hr = CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right, pRects[i].bottom); VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR) != ERROR); if (hr) ::DeleteObject(hr); } ASSERT(hRgn != NULL); return hRgn; } /////////////////////////////////////////////////////////////////// // InflateRegion - Inflates a region by the x and y values // specified in nXInflate and nYInflate // Creates a new region that represents the inflated region // (retains the contents of the old region) // Returns NULL if unsuccessfull HRGN CEnBitmap::InflateRegion(HRGN hRgn, int nXInflate, int nYInflate) { // Local Variables LPRGNDATA lpData; // The RGNDATA structure LPRECT lpRect; // Pointer to the array of RECT structures DWORD BufSize; // The amount of memory required DWORD i; // General index variable HRGN hRgnNew; // The newly created region // Get the number of rectangles in the region BufSize = GetRegionData(hRgn, 0, NULL); if (BufSize == 0) return NULL; // Allocate memory for the RGNDATA structure lpData = (LPRGNDATA)malloc(BufSize); // Set the location of the RECT structures lpRect = (LPRECT)(lpData->Buffer); // Get the region data if (!GetRegionData(hRgn, BufSize, lpData)) { free(lpData); return NULL; } // Expand (or contract) all the rectangles in the data for (i = 0; i < lpData->rdh.nCount; i++) InflateRect(&lpRect[i], nXInflate, nYInflate); // Create the new region hRgnNew = CreateRegionExt(lpData->rdh.nCount, lpData); free((void*)lpData); return hRgnNew; } BOOL CEnBitmap::StretchDraw(CDC *pDC, LPRECT r, LPRECT sr) { if (!r) return FALSE; CDC dc; dc.CreateCompatibleDC(pDC); CBitmap * bmp = dc.SelectObject(this); //pDC->SetStretchBltMode(COLORONCOLOR); pDC->SetStretchBltMode(STRETCH_HALFTONE); // 使界面拉伸后不模糊; if (!sr) pDC->StretchBlt(r->left, r->top, r->right, r->bottom, &dc, 0, 0, GetWidth(), GetHeight(), SRCCOPY); else pDC->StretchBlt(r->left, r->top, r->right - r->left, r->bottom - r->top, &dc, sr->left, sr->top, sr->right - sr->left, sr->bottom - sr->top, SRCCOPY); dc.SelectObject(bmp); return TRUE; } BOOL CEnBitmap::DrawImage(CEnBitmap &bmp, int nX, int nY, int nCol, int nRow) { nX -= 1; nY -= 1; //单个图片的长和宽; int w = GetWidth() / nCol; int h = GetHeight() / nRow; CBitmap *OldBmp; CDC memDC; CClientDC dc(0); memDC.CreateCompatibleDC(&dc); bmp.CreateCompatibleBitmap(&dc, w, h); OldBmp = memDC.SelectObject(&bmp); StretchDraw(&memDC, CRect(0, 0, w, h), CRect(GetWidth()*nX / nCol, GetHeight()*nY / nRow, GetWidth()*nX / nCol + w, GetHeight()*nY / nRow + h)); memDC.SelectObject(OldBmp); return TRUE; } //BOLL GetBmp() CRect CEnBitmap::GetRect() { return CRect(0, 0, GetWidth(), GetHeight()); } HBITMAP CEnBitmap::SetBitmap(HBITMAP hBitmap) { CEnBitmap *pBmp = (CEnBitmap *)CEnBitmap::FromHandle(hBitmap); HBITMAP hBmp = (HBITMAP)this->Detach(); this->DeleteObject(); pBmp->DrawImage(*this, 1, 1, 1, 1); return hBmp; } /************************************************************************/ /* 函数:[8/23/2016 IT]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ BOOL CEnBitmap::ExtendDraw(IN CDC *pDC, IN CRect rc, IN int nX, IN int nY, IN BOOL bTran, IN UINT colorTransparent) { CEnBitmap bmp; if (ExtendDrawImage(bmp, rc, nX, nY)) { if (bTran) bmp.TransparentBlt(*pDC, &rc, colorTransparent); else bmp.Draw(pDC, &rc); // return TRUE; } return FALSE; } /************************************************************************/ /* 函数:ExtendDrawImage[8/23/2016 IT]; /* 描述:; /* 参数:; /* [OUT] bmp:返回图片对象; /* [IN] rc:画图的目标区域; /* [IN] nX:分割点x坐标(原图坐标); /* [IN] nY:分割点y坐标(原图坐标); /* 返回:BOOL; /* 注意:; /* 示例:; /* (0,0)-------|----------| /* | | | /* | 左上 | 右上 | /* | | | /* ----------(x,y)-------|----x,y分割点坐标; /* | | | /* | 左下 | 右下 | /* | | | /* -----------|---------(r,b)- /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ BOOL CEnBitmap::ExtendDrawImage(OUT CEnBitmap &bmp, IN CRect rc, IN int nX, IN int nY) { CBitmap *OldBmp; CDC memDC; CClientDC cdc(0); memDC.CreateCompatibleDC(&cdc); bmp.CreateCompatibleBitmap(&cdc, rc.Width(), rc.Height()); OldBmp = memDC.SelectObject(&bmp); if (nX == 0 && nY == 0) { StretchDraw(&memDC, &rc, GetRect()); return TRUE; } CDC dc; dc.CreateCompatibleDC(&memDC); CBitmap * Bmp = dc.SelectObject(this); //dc.SetStretchBltMode(COLORONCOLOR); if (nX > 0 && nY == 0) {// 左右对半; // 左边; memDC.BitBlt(0, 0, nX, rc.Height(), &dc, 0, 0, SRCCOPY); memDC.StretchBlt(nX, 0, rc.Width() - GetWidth(), rc.Height(), &dc, nX, 0, 1, GetHeight(), SRCCOPY); // 右边; memDC.BitBlt(rc.right - (GetWidth() - nX), 0, GetWidth() - nX, rc.Height(), &dc, nX, 0, SRCCOPY); } else if (nX == 0 && nY > 0) {// 上下对半; // 上边; memDC.BitBlt(0, 0, rc.Width(), nY, &dc, 0, 0, SRCCOPY); memDC.StretchBlt(0, nY, GetWidth(), rc.Height() - GetHeight(), &dc, 0, nY, GetWidth(), 1, SRCCOPY); // 下边; memDC.BitBlt(0, rc.bottom - (GetHeight() - nY), GetWidth(), GetHeight() - nY, &dc, 0, nY, SRCCOPY); } else if (nX > 0 && nY > 0) { //左上角; memDC.StretchBlt(0, 0, nX, nY, &dc, 0, 0, nX, nY, SRCCOPY); //上中; memDC.StretchBlt(nX, 0, rc.Width() - GetWidth(), nY, &dc, nX, 0, 1, nY, SRCCOPY); //右上角; memDC.StretchBlt(rc.Width() - (GetWidth() - nX), 0, GetWidth() - nX, nY, &dc, nX, 0, GetWidth() - nX, nY, SRCCOPY); //左中; memDC.StretchBlt(0, nY, nX, rc.Height() - GetHeight(), &dc, 0, nY, nX, 1, SRCCOPY); //正中; memDC.StretchBlt(nX, nY, rc.Width() - GetWidth(), rc.Height() - GetHeight(), &dc, nX, nY, 1, 1, SRCCOPY); //右中; memDC.StretchBlt(rc.Width() - (GetWidth() - nX), nY, GetWidth() - nX, rc.Height() - GetHeight(), &dc, nX, nY, GetWidth() - nX, 1, SRCCOPY); //左下角; memDC.StretchBlt(0, rc.Height() - (GetHeight() - nY), nX, GetHeight() - nY, &dc, 0, nY, nX, GetHeight() - nY, SRCCOPY); //下中; memDC.StretchBlt(nX, rc.Height() - (GetHeight() - nY), rc.Width() - GetWidth(), GetHeight() - nY, &dc, nX, nY, 1, GetHeight() - nY, SRCCOPY); //右下角; memDC.StretchBlt(rc.Width() - (GetWidth() - nX), rc.Height() - (GetHeight() - nY), GetWidth() - nX, GetHeight() - nY, &dc, nX, nY, GetWidth() - nX, GetHeight() - nY, SRCCOPY); } dc.SelectObject(Bmp); memDC.SelectObject(OldBmp); return TRUE; }