#include "StdAfx.h" #include "..\include\skinbitmap.h" const int HIMETRIC_INCH = 2540; void RGBtoHLS(COLORREF color,double *H, double *L, double *S) { double r = (double)GetRValue(color)/ 255.0 ; double g = (double)GetGValue(color) / 255.0 ; double b = (double)GetBValue(color) / 255.0 ; double cmax = max (r, max (g, b)) ; double cmin = min (r, min (g, b)) ; *L = (cmax+cmin) / 2.0 ; if (cmax == cmin) { *S = 0 ; *H = 0 ; } else { if (*L < 0.5) *S = (cmax-cmin) / (cmax+cmin) ; else *S = (cmax-cmin) / (2.0-cmax-cmin) ; double delta = cmax - cmin ; if (delta == 0.0) delta = 1.0 ; if (r == cmax) *H = (g-b) / delta ; else if (g == cmax) *H = 2.0 + (b-r) / delta ; else *H = 4.0 + (r-g) / delta ; *H /= 6.0 ; if (*H < 0.0) *H += 1 ; } } double __F_HLS_Value (const double &m1, double const &m2, double h) { if (h < 0) h += 1.0 ; if (h > 1) h -= 1.0 ; if (6.0*h < 1) return (m1+(m2-m1)*h*6.0) ; if (2.0*h < 1) return m2 ; if (3.0*h < 2.0) return (m1+(m2-m1)*((2.0/3.0)-h)*6.0) ; return m1 ; } COLORREF HLStoRGB(const double& H, const double& L, const double& S) { double r, g, b ; if (S == 0) { r = g = b = L ; } else { double m1, m2 ; if (L <= 0.5) m2 = L * (1.0+S) ; else m2 = L + S - L*S ; m1 = 2.0*L - m2 ; r = __F_HLS_Value (m1, m2, H+1.0/3.0) ; g = __F_HLS_Value (m1, m2, H) ; b = __F_HLS_Value (m1, m2, H-1.0/3.0) ; } BYTE red,green,blue ; red = max (min ((int)(r*255), 0xFF), 0) ; green = max (min ((int)(g*255), 0xFF), 0) ; blue = max (min ((int)(b*255), 0xFF), 0) ; return RGB(red,green,blue) ; } /****************************************** * 函数名 : CSkinBitmap * 功能 : 构造函数 *******************************************/ CSkinBitmap::CSkinBitmap(void) :m_lpBuffer(NULL) ,m_nSize(0) ,m_strName(_T("")) { } /****************************************** * 函数名 : ~CSkinBitmap * 功能 : 析构函数 *******************************************/ CSkinBitmap::~CSkinBitmap(void) { if(m_lpBuffer) delete []m_lpBuffer; m_lpBuffer = NULL; } COLORREF CSkinBitmap::GetTransparentColor() const { CBitmap* pBitmap = (CBitmap*)this; if (pBitmap != NULL) { CCompatibleDC dc(NULL, pBitmap); return dc.GetPixel(0,0); } return (COLORREF)-1; } /****************************************** * 函数名 : LoadImage * 功能 : 从资源文件中载入位图 *******************************************/ BOOL CSkinBitmap::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; if(m_lpBuffer) delete []m_lpBuffer; BOOL bResult = FALSE; // first call is to get buffer size if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, 0, m_nSize)) { if (m_nSize > 0) { m_lpBuffer = new BYTE[m_nSize]; // this loads it if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, m_lpBuffer, m_nSize)) { IPicture* pPicture = LoadFromBuffer(m_lpBuffer, m_nSize); if (pPicture) { bResult = Attach(pPicture, crBack); pPicture->Release(); } } } } return bResult; } /****************************************** * 函数名 : LoadImage * 功能 : 从文件中载入位图 *******************************************/ BOOL CSkinBitmap::LoadImage(LPCTSTR szImagePath, COLORREF crBack) { ASSERT(m_hObject == NULL); // only attach once, detach on destroy if (m_hObject != NULL) return FALSE; if(m_lpBuffer) delete []m_lpBuffer; BOOL bResult = FALSE; CFile cFile; CFileException e; if (cFile.Open(szImagePath, CFile::modeRead | CFile::typeBinary, &e)) { m_nSize= cFile.GetLength(); m_lpBuffer = new BYTE[m_nSize]; if (cFile.Read(m_lpBuffer, m_nSize) > 0) { IPicture* pPicture = LoadFromBuffer(m_lpBuffer, m_nSize); if (pPicture) { bResult = Attach(pPicture, crBack); pPicture->Release(); } } } return bResult; } /****************************************** * 函数名 : LoadImage * 功能 : 从内存BUUFER中加载位图 *******************************************/ BOOL CSkinBitmap::LoadImage(LPBYTE lpBuffer,int nSize, COLORREF crBack) { ASSERT(m_hObject == NULL); // only attach once, detach on destroy if (m_hObject != NULL) return FALSE; BOOL bResult = FALSE; if (lpBuffer) { IPicture* pPicture = LoadFromBuffer(lpBuffer, nSize); if (pPicture) { bResult = Attach(pPicture, crBack); pPicture->Release(); } } return bResult; } /****************************************** * 函数名 : LoadFromBuffer * 功能 : 从内存重载入位图 *******************************************/ IPicture* CSkinBitmap::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 CSkinBitmap::Save(CFile &file) { char name[256]; strcpy(name,m_strName); file.Write(name,256); file.Write(&m_nSize,sizeof(m_nSize)); file.Write(m_lpBuffer,m_nSize); return TRUE; } BOOL CSkinBitmap::Load(CFile &file) { char name[256]; file.Read(name,256); m_strName = name; file.Read(&m_nSize,sizeof(m_nSize)); if(m_nSize) { m_lpBuffer = new BYTE[m_nSize]; file.Read(m_lpBuffer,m_nSize); if(m_lpBuffer) LoadImage(m_lpBuffer,m_nSize); } return TRUE; } void CSkinBitmap::Serialize(CArchive& ar) { if(ar.IsStoring()) { char name[256]; strcpy(name,m_strName); ar.Write(name,256); ar.Write(&m_nSize,sizeof(m_nSize)); ar.Write(m_lpBuffer,m_nSize); } else { char name[256]; // strcpy(name,m_strName); ar.Read(name,256); m_strName = name; ar.Read(&m_nSize,sizeof(m_nSize)); if(m_nSize) { m_lpBuffer = new BYTE[m_nSize]; ar.Read(m_lpBuffer,m_nSize); if(m_lpBuffer) LoadImage(m_lpBuffer,m_nSize); } } } /****************************************** * 函数名 : GetResource * 功能 : 从资源中获取位图buffer *******************************************/ BOOL CSkinBitmap::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; } /****************************************** * 函数名 : Attach * 功能 : 关联位图 *******************************************/ BOOL CSkinBitmap::Attach(IPicture* pPicture, COLORREF crBack) { ASSERT(m_hObject == NULL); // only attach once, detach on destroy if (m_hObject != NULL) return FALSE; ASSERT(pPicture); if (!pPicture) return FALSE; BOOL bResult = FALSE; 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); CBitmap bmMem; 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); if (hr == S_OK) bResult = CBitmap::Attach(bmMem.Detach()); } } CWnd::GetDesktopWindow()->ReleaseDC(pDC); return bResult; } /****************************************** * 函数名 : TransparentDraw * 功能 : 透明绘制位图 *******************************************/ BOOL CSkinBitmap::TransparentDraw( CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc, int mode) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if (lpRectDst) rectDst = *lpRectDst; else rectDst.SetRect(0,0,GetWidth(),GetHeight()); if (lpRectSrc) rectSrc = *lpRectSrc; else rectSrc.SetRect(0,0,GetWidth(),GetHeight()); COLORREF crOldBack; COLORREF crOldText; if (mode==0) { // 去除指定的颜色 crOldBack = pDC->SetBkColor(RGB(255,255,255)); crOldText = pDC->SetTextColor(RGB(0,0,0)); } else { // 保留指定的颜色 crOldBack = pDC->SetBkColor(RGB(0,0,0)); crOldText = pDC->SetTextColor(RGB(255,255,255)); } CDC dcImage, dcTrans; // 创建内存设备描述表 dcImage.CreateCompatibleDC(pDC); dcTrans.CreateCompatibleDC(pDC); // 选择原始图像到DC中 CBitmap* pOldBitmapImage = dcImage.SelectObject(this); // 创建掩码位图 CBitmap bitmapTrans; int nWidth = rectDst.Width(); int nHeight = rectDst.Height(); bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL); // 选择掩码位图到DC中 CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans); // 创建掩码图像(基于指定的颜色) dcImage.SetBkColor(crColour); dcTrans.StretchBlt(0,0, nWidth, nHeight, &dcImage, rectSrc.left, rectSrc.top,rectSrc.Width(),rectSrc.Height(), SRCCOPY); /* 设置目标DC的拉伸模式为STRETCH_DELETESCANS,也就是不显示拉伸掉的图像 */ int srlold = pDC->SetStretchBltMode(STRETCH_DELETESCANS); // 显示位图 pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(), &dcImage,rectSrc.left,rectSrc.top,rectSrc.Width(),rectSrc.Height(),SRCINVERT); pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(), &dcTrans,0,0,nWidth,nHeight,SRCAND); pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(), &dcImage,rectSrc.left,rectSrc.top,rectSrc.Width(),rectSrc.Height(),SRCINVERT); // 恢复设备描述表原来的设置 pDC->SetStretchBltMode(srlold); // 恢复设置 dcImage.SelectObject(pOldBitmapImage); dcTrans.SelectObject(pOldBitmapTrans); pDC->SetBkColor(crOldBack); pDC->SetTextColor(crOldText); return TRUE; } /****************************************** * 函数名 : Draw * 功能 : 设备描述表之间绘制 *******************************************/ BOOL CSkinBitmap::Draw(CDC *pDstDC,CDC *pSrcDC,LPRECT lpRectDst,LPRECT lpRectSrc ) { if(pDstDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if (lpRectDst) rectDst = *lpRectDst; if (lpRectSrc) rectSrc = *lpRectSrc; if(lpRectSrc) { /* 设置目标DC的拉伸模式为STRETCH_DELETESCANS,也就是不显示拉伸掉的图像 */ int srlold = pDstDC->SetStretchBltMode(STRETCH_DELETESCANS); pDstDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(), pSrcDC, rectSrc.left, rectSrc.top ,rectSrc.Width(),rectSrc.Height(),SRCCOPY ); pDstDC->SetStretchBltMode(srlold); } else { pDstDC->BitBlt( rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(), pSrcDC, 0, 0 ,SRCCOPY ); } return TRUE; } /****************************************** * 函数名 : Draw * 功能 : 位图绘制函数 *******************************************/ BOOL CSkinBitmap::Draw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); Draw(pDC,&dc,lpRectDst,lpRectSrc); dc.SelectObject( bmp ); return TRUE; } /****************************************** * 函数名 : TitleDraw * 功能 : 填充位图绘制函数 *******************************************/ BOOL CSkinBitmap::TitleDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc ) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); //矩形坐标规范画 rectDst.NormalizeRect(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight) { for(int x = rectDst.left ; x < rectDst.right ; x += nWidth) { rectTemp.SetRect(x,y,x+nWidth,y+nHeight); Draw(pDC,&dc,&rectTemp,lpRectSrc); } } dc.SelectObject(bmp); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : CenterDraw * 功能 : 中央位图绘制函数 *******************************************/ BOOL CSkinBitmap::CenterDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); //计算源区域的宽度和高度 int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } // 取指定矩形的中点坐标 CPoint ptCeneter = rectDst.CenterPoint(); CRect rectTemp(ptCeneter.x - nWidth/2, ptCeneter.y - nHeight/2, ptCeneter.x - nWidth/2, ptCeneter.y + nHeight/2); CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); Draw(pDC,&dc,&rectTemp,lpRectSrc); dc.SelectObject(bmp); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : WidthStretchDraw * 功能 : 宽度伸展函数 *******************************************/ BOOL CSkinBitmap::WidthStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc ) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight) { rectTemp.SetRect(rectDst.left, y,rectDst.right, y + nHeight); Draw(pDC,&dc,&rectTemp,lpRectSrc); } dc.SelectObject(bmp); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : HeightStretchDraw * 功能 : 高度伸展绘制函数 *******************************************/ BOOL CSkinBitmap::HeightStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); for(int x = rectDst.left ; x < rectDst.right ; x += nWidth) { rectTemp.SetRect(x, rectDst.top,x + nWidth, rectDst.bottom); Draw(pDC,&dc,&rectTemp,lpRectSrc); } dc.SelectObject(bmp); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : HeightStretchDraw * 功能 : 伸展绘制函数 *******************************************/ BOOL CSkinBitmap::AllStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; else rectSrc.SetRect(0, 0, GetWidth(), GetHeight()); //矩形坐标规范化 rectDst.NormalizeRect(); CDC dc; dc.CreateCompatibleDC( pDC ); CBitmap * bmp = dc.SelectObject( this ); Draw(pDC,&dc,&rectDst,&rectSrc); dc.SelectObject(bmp); return TRUE; } /****************************************** * 函数名 : TitleTransDraw * 功能 : 透明填充绘制函数 *******************************************/ BOOL CSkinBitmap::TitleTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); //矩形坐标规范画 rectDst.NormalizeRect(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight) { for(int x = rectDst.left ; x < rectDst.right ; x += nWidth) { rectTemp.SetRect(x,y,x+nWidth,y+nHeight); TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc); } } pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : CenterTransDraw * 功能 : 透明中央绘制函数 *******************************************/ BOOL CSkinBitmap::CenterTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); //计算源区域的宽度和高度 int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } // 取指定矩形的中点坐标 CPoint ptCeneter = rectDst.CenterPoint(); CRect rectTemp(ptCeneter.x - nWidth/2, ptCeneter.y - nHeight/2, ptCeneter.x - nWidth/2, ptCeneter.y + nHeight/2); TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : WidthStretchTransDraw * 功能 : 透明宽度伸展绘制函数 *******************************************/ BOOL CSkinBitmap::WidthStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight) { rectTemp.SetRect(rectDst.left, y,rectDst.right, y + nHeight); TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc); } pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : HeightStretchTransDraw * 功能 : 透明高度伸展绘制函数 *******************************************/ BOOL CSkinBitmap::HeightStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc ) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; //矩形坐标规范化 rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); CRect rectTemp; int nWidth = 0; int nHeight = 0; if(lpRectSrc) { nWidth = rectSrc.Width(); nHeight = rectSrc.Height(); } else { nWidth = GetWidth(); nHeight = GetHeight(); } for(int x = rectDst.left ; x < rectDst.right ; x += nWidth) { rectTemp.SetRect(x, rectDst.top,x + nWidth, rectDst.bottom); TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc); } pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : AllStretchTransDraw * 功能 : 透明伸展绘制函数 *******************************************/ BOOL CSkinBitmap::AllStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, LPRECT lpRectSrc) { if(pDC == NULL || lpRectDst == NULL) return FALSE; CRect rectDst; // 目标位置数据 CRect rectSrc; // 源位置数据 if(lpRectDst) rectDst = *lpRectDst; if(lpRectSrc) rectSrc = *lpRectSrc; else rectSrc.SetRect(0, 0, GetWidth(), GetHeight()); rectDst.NormalizeRect(); //保存当前设备描述表,因下面对其剪贴区域进行更改 int savedc = pDC->SaveDC(); CRgn newrgn; //设置需要显示的区域 newrgn.CreateRectRgnIndirect(&rectDst); pDC->SelectClipRgn(&newrgn, RGN_AND); TransparentDraw(pDC,crColour,rectDst,rectSrc); pDC->RestoreDC(savedc); newrgn.CGdiObject::DeleteObject(); return TRUE; } /****************************************** * 函数名 : CreateRgnFromFile * 功能 : 根据位图创建区域 *******************************************/ HRGN CSkinBitmap::CreateRgnFromFile( COLORREF color ) { HBITMAP hBmp = (HBITMAP)this->GetSafeHandle(); // get image properties BITMAP bmp = { 0 }; ::GetObject( hBmp, sizeof(BITMAP), &bmp ); // allocate memory for extended image information LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 8 ]; memset( bi, 0, sizeof(BITMAPINFO) + 8 ); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // set window size int m_dwWidth = bmp.bmWidth; // bitmap width int m_dwHeight = bmp.bmHeight; // bitmap height // create temporary dc HDC dc = CreateIC( _TEXT("DISPLAY"),NULL,NULL,NULL ); // get extended information about image (length, compression, length of color table if exist, ...) DWORD res = GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS ); // allocate memory for image data (colors) LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 4 ]; // allocate memory for color table if ( bi->bmiHeader.biBitCount == 8 ) { // actually color table should be appended to this header(BITMAPINFO), // so we have to reallocate and copy it LPBITMAPINFO old_bi = bi; // 255 - because there is one in BITMAPINFOHEADER bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ]; memcpy( bi, old_bi, sizeof(BITMAPINFO) ); // release old header delete old_bi; } // get bitmap info header BITMAPINFOHEADER& bih = bi->bmiHeader; // get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD)) LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors; // fill bits buffer res = GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS ); DeleteDC( dc ); BITMAP bm; ::GetObject( hBmp, sizeof(BITMAP), &bm ); // shift bits and byte per pixel (for comparing colors) LPBYTE pClr = (LPBYTE)&color; // swap red and blue components BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp; // convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5) if ( bih.biBitCount == 16 ) { // for 16 bit color = ((DWORD)(pClr[0] & 0xf8) >> 3) | ((DWORD)(pClr[1] & 0xfc) << 3) | ((DWORD)(pClr[2] & 0xf8) << 8); // for 15 bit // color = ((DWORD)(pClr[0] & 0xf8) >> 3) | // ((DWORD)(pClr[1] & 0xf8) << 2) | // ((DWORD)(pClr[2] & 0xf8) << 7); } const DWORD RGNDATAHEADER_SIZE = sizeof(RGNDATAHEADER); const DWORD ADD_RECTS_COUNT = 40; // number of rects to be appended // to region data buffer // BitPerPixel BYTE Bpp = bih.biBitCount >> 3; // bytes per pixel // bytes per line in pBits is DWORD aligned and bmp.bmWidthBytes is WORD aligned // so, both of them not DWORD m_dwAlignedWidthBytes = (bmp.bmWidthBytes & ~0x3) + (!!(bmp.bmWidthBytes & 0x3) << 2); // DIB image is flipped that's why we scan it from the last line LPBYTE pColor = pBits + (bih.biHeight - 1) * m_dwAlignedWidthBytes; DWORD dwLineBackLen = m_dwAlignedWidthBytes + bih.biWidth * Bpp; // offset of previous scan line // (after processing of current) DWORD dwRectsCount = bih.biHeight; // number of rects in allocated buffer INT i, j; // current position in mask image INT first = 0; // left position of current scan line // where mask was found bool wasfirst = false; // set when mask has been found in current scan line bool ismask; // set when current color is mask color // allocate memory for region data // region data here is set of regions that are rectangles with height 1 pixel (scan line) // that's why first allocation is RECTs - number of scan lines in image RGNDATAHEADER* pRgnData = (RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ]; // get pointer to RECT table LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE); // zero region data header memory (header part only) memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ); // fill it by default pRgnData->dwSize = RGNDATAHEADER_SIZE; pRgnData->iType = RDH_RECTANGLES; for ( i = 0; i < bih.biHeight; i++ ) { for ( j = 0; j < bih.biWidth; j++ ) { // get color switch ( bih.biBitCount ) { case 8: ismask = (clr_tbl[ *pColor ] != color); break; case 16: ismask = (*(LPWORD)pColor != (WORD)color); break; case 24: ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color); break; case 32: ismask = (*(LPDWORD)pColor != color); } // shift pointer to next color pColor += Bpp; // place part of scan line as RECT region if transparent color found after mask color or // mask color found at the end of mask image if ( wasfirst ) { if ( !ismask ) { // save current RECT pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 ); // if buffer full reallocate it with more room if ( pRgnData->nCount >= dwRectsCount ) { dwRectsCount += ADD_RECTS_COUNT; // allocate new buffer LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ]; // copy current region data to it memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) ); // delte old region data buffer delete pRgnData; // set pointer to new regiondata buffer to current pRgnData = (RGNDATAHEADER*)pRgnDataNew; // correct pointer to RECT table pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE); } wasfirst = false; } } else if ( ismask ) // set wasfirst when mask is found { first = j; wasfirst = true; } } if ( wasfirst && ismask ) { // save current RECT pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 ); // if buffer full reallocate it with more room if ( pRgnData->nCount >= dwRectsCount ) { dwRectsCount += ADD_RECTS_COUNT; // allocate new buffer LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ]; // copy current region data to it memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) ); // delte old region data buffer delete pRgnData; // set pointer to new regiondata buffer to current pRgnData = (RGNDATAHEADER*)pRgnDataNew; // correct pointer to RECT table pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE); } wasfirst = false; } pColor -= dwLineBackLen; } // release image data delete pBits; delete bi; // create region HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData ); // release region data delete pRgnData; return hRgn; } void CSkinBitmap::ModifyHue(CDC *pDC,int nWidth,int nHeight,int nPercent) { double H, L, S ; COLORREF color ; for(int i = 0 ; i < nWidth ; i++) for(int j = 0 ; j < nHeight ; j++) { color = pDC->GetPixel(i,j); RGBtoHLS(color,&H,&L,&S); if (nPercent != 100) H = H * nPercent / 100 ; color = HLStoRGB(H,L,S); pDC->SetPixel(i,j,color); } } void CSkinBitmap::ModifyHue(int nPercent) { DeleteObject(); LoadImage(m_lpBuffer,m_nSize); HDC dc = CreateIC( _TEXT("DISPLAY"),NULL,NULL,NULL ); CDC *pDC = CDC::FromHandle(dc); CCompatibleDC memDC(pDC,this); int nWidth = GetWidth(); int nHeight = GetHeight(); ModifyHue(&memDC,nWidth,nHeight, nPercent); DeleteDC(dc); } BOOL CSkinBitmap::Copy(CSkinBitmap *pSrc) { if(pSrc == NULL) return FALSE; if(m_lpBuffer) delete []m_lpBuffer; m_strName = pSrc->m_strName; m_nSize = pSrc->m_nSize; m_lpBuffer = new BYTE[m_nSize]; if(!m_lpBuffer) return FALSE; ::CopyMemory(m_lpBuffer,pSrc->m_lpBuffer,m_nSize); LoadImage(m_lpBuffer,m_nSize); return TRUE; }