|
@@ -0,0 +1,1183 @@
|
|
|
+//////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+#include "pch.h"
|
|
|
+#include "EnBitmap.h"
|
|
|
+#include <AFXPRIV.H>
|
|
|
+
|
|
|
+#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
|
|
|
+};
|
|
|
+
|
|
|
+//////////////////////////////////////////////////////////////////////
|
|
|
+// Construction/Destruction
|
|
|
+//////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+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(T2OLE(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(".BMP") > 0)
|
|
|
+ return FT_BMP;
|
|
|
+
|
|
|
+ else if (sPath.Find(".ICO") > 0)
|
|
|
+ return FT_ICO;
|
|
|
+
|
|
|
+ else if (sPath.Find(".JPG") > 0 || sPath.Find(".JPEG") > 0)
|
|
|
+ return FT_JPG;
|
|
|
+
|
|
|
+ else if (sPath.Find(".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
|
|
|
+
|
|
|
+void CEnBitmap::TransparentBlt(CDC& dc, CRect rc, 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);
|
|
|
+
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL CEnBitmap::ExtendDraw(CDC* pDC, CRect rc, int nX, int nY, BOOL bTran, 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;
|
|
|
+}
|
|
|
+
|
|
|
+BOOL CEnBitmap::ExtendDrawImage(CEnBitmap& bmp, CRect rc, int nX, 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
|
|
|
+ {
|
|
|
+ //左上角
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|