Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1577 lines
48 KiB

  1. /*************************************************************************/
  2. /* Copyright (C) 1999 Microsoft Corporation */
  3. /* File: dibapi.cpp */
  4. /* Description: Modified for transparent blitting. */
  5. /*************************************************************************/
  6. // Source file for Device-Independent Bitmap (DIB) API. Provides
  7. // the following functions:
  8. //
  9. // PaintDIB() - Painting routine for a DIB
  10. // PaintDIBTransparent() - Transparent painting routine for a DIB
  11. // CreateDIBPalette() - Creates a palette from a DIB
  12. // FindDIBBits() - Returns a pointer to the DIB bits
  13. // DIBWidth() - Gets the width of the DIB
  14. // DIBHeight() - Gets the height of the DIB
  15. // PaletteSize() - Gets the size required to store the DIB's palette
  16. // DIBNumColors() - Calculates the number of colors
  17. // in the DIB's color table
  18. // CopyHandle() - Makes a copy of the given global memory block
  19. //
  20. // This is a part of the Microsoft Foundation Classes C++ library.
  21. // Copyright (C) 1992-1998 Microsoft Corporation
  22. // All rights reserved.
  23. //
  24. // This source code is only intended as a supplement to the
  25. // Microsoft Foundation Classes Reference and related
  26. // electronic documentation provided with the library.
  27. // See these sources for detailed information regarding the
  28. // Microsoft Foundation Classes product.
  29. #include "stdafx.h"
  30. //#include "bbtn.h"
  31. #include "CBitmap.h"
  32. #include <io.h>
  33. #include <errno.h>
  34. #include <math.h>
  35. #include <direct.h>
  36. /*
  37. * Dib Header Marker - used in writing DIBs to files
  38. */
  39. #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
  40. /*************************************************************************/
  41. /* Function: Init */
  42. /*************************************************************************/
  43. void CBitmap::Init(){
  44. m_hDIB = NULL;
  45. m_hPal = NULL;
  46. m_hMemDC = NULL;
  47. m_hMemBMP = NULL;
  48. m_hTransDC = NULL;
  49. m_hTransBMP = NULL;
  50. m_hRgn = NULL;
  51. m_fLoadPalette = false;
  52. ::ZeroMemory(&m_rc, sizeof(RECT));
  53. }/* end of function Init */
  54. /*************************************************************************/
  55. /* Function: CleanUp */
  56. /* Description: Destroys the objects. */
  57. /*************************************************************************/
  58. void CBitmap::CleanUp() {
  59. try {
  60. // cleanup the background image resources
  61. if (m_hDIB){
  62. ::GlobalFree(m_hDIB);
  63. }/* end of if statement */
  64. }
  65. catch(...){
  66. ATLASSERT(FALSE);
  67. }
  68. try {
  69. // cleanup the palette if applicable
  70. if (m_hPal){
  71. ::DeleteObject(m_hPal);
  72. }/* end of if statement */
  73. }
  74. catch(...){
  75. ATLASSERT(FALSE);
  76. }
  77. try {
  78. if(NULL != m_hRgn){
  79. ::DeleteObject(m_hRgn);
  80. }/* end of if statement */
  81. DeleteMemDC();
  82. DeleteTransDC();
  83. }
  84. catch(...){
  85. ATLASSERT(FALSE);
  86. }
  87. bool fLoadPalette = m_fLoadPalette;
  88. Init();
  89. m_fLoadPalette = fLoadPalette;
  90. }/* end of function Cleanup */
  91. /*************************************************************************
  92. Function: ReadDIBFile (CFile&)
  93. Purpose: Reads in the specified DIB file into a global chunk of
  94. memory.
  95. Returns: A handle to a dib (hDIB) if successful.
  96. NULL if an error occurs.
  97. Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything
  98. from the end of the BITMAPFILEHEADER structure on is
  99. returned in the global memory handle.
  100. TODO: Convert to HRESULTs clean up.
  101. *************************************************************************/
  102. HDIB WINAPI CBitmap::ReadDIBFile(LPCTSTR pszFileName, HINSTANCE hRes )
  103. {
  104. BITMAPFILEHEADER bmfHeader;
  105. DWORD dwBitsSize;
  106. LPSTR pDIB;
  107. HANDLE hFile = NULL;
  108. DWORD nBytesRead;
  109. HGLOBAL hMemory = NULL;
  110. if(NULL == hRes){
  111. /*
  112. * get length of DIB in bytes for use when reading
  113. */
  114. hFile = ::CreateFile(
  115. pszFileName, // pointer to name of the file
  116. GENERIC_READ, // access (read-write) mode
  117. FILE_SHARE_READ, // share mode
  118. NULL, // pointer to security descriptor
  119. OPEN_EXISTING, // how to create
  120. FILE_ATTRIBUTE_NORMAL, // file attributes
  121. NULL // handle to file with attributes to copy
  122. );
  123. if(hFile == INVALID_HANDLE_VALUE){
  124. #if _DEBUG
  125. TCHAR strBuffer[MAX_PATH + 25];
  126. wsprintf(strBuffer, TEXT("Failed to download %s"), pszFileName);
  127. ::MessageBox(::GetFocus(), strBuffer, TEXT("Error"), MB_OK);
  128. #endif
  129. return NULL;
  130. }/* end of if statement */
  131. dwBitsSize = GetFileSize(hFile,NULL);
  132. }
  133. else {
  134. TCHAR* strType = TEXT("DIB_FILE"); // this is a custom resource type, so we load the whole file
  135. // see script resource type in this project for an example
  136. HRSRC hrscScript = ::FindResource(hRes, pszFileName, strType);
  137. if(NULL == hrscScript){
  138. // convert the function to HRES evntually hr = HRESULT_FROM_WIN32(::GetLastError());
  139. #if _DEBUG
  140. TCHAR strBuffer[MAX_PATH + 25];
  141. wsprintf(strBuffer, TEXT("Failed to find resource %s"), pszFileName);
  142. ::MessageBox(::GetFocus(), strBuffer, TEXT("Error"), MB_OK);
  143. #endif
  144. return(NULL);
  145. }/* end of if statement */
  146. hMemory = ::LoadResource(hRes, hrscScript);
  147. if(NULL == hMemory){
  148. //hr = HRESULT_FROM_WIN32(::GetLastError());
  149. return(NULL);
  150. }/* end of if statement */
  151. dwBitsSize = SizeofResource((HMODULE)hRes, hrscScript);
  152. // hMemory contains the raw data
  153. // modify the algorithm to one read, so we can use the resources
  154. }/* end of if statement */
  155. if(0 == dwBitsSize){
  156. return(NULL); // the file size should be definetly more then 0
  157. }/* end of if statement */
  158. /*
  159. * Go read the DIB file header and check if it's valid.
  160. */
  161. if(NULL == hRes && hFile){
  162. // attempt an asynchronous read operation
  163. if(! ReadFile(hFile, (LPSTR)&bmfHeader, sizeof(bmfHeader), &nBytesRead, NULL))
  164. return NULL;
  165. }
  166. else if (hMemory){
  167. CopyMemory(&bmfHeader, hMemory, sizeof(bmfHeader));
  168. }
  169. if (bmfHeader.bfType != DIB_HEADER_MARKER)
  170. return NULL;
  171. /*
  172. * Allocate memory for DIB
  173. */
  174. m_hDIB = (HDIB) ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwBitsSize);
  175. if (m_hDIB == 0)
  176. {
  177. return NULL;
  178. }
  179. pDIB = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
  180. /*
  181. * Go read the bits.
  182. */
  183. if (NULL == hRes) {
  184. if(!ReadFile(hFile, (LPSTR)pDIB, dwBitsSize - sizeof(BITMAPFILEHEADER), &nBytesRead, NULL))
  185. {
  186. ::GlobalUnlock((HGLOBAL) m_hDIB);
  187. ::GlobalFree((HGLOBAL) m_hDIB);
  188. return NULL;
  189. }
  190. ::CloseHandle(hFile);
  191. }
  192. else{
  193. CopyMemory(pDIB, (LPSTR)hMemory+sizeof(BITMAPFILEHEADER), dwBitsSize - sizeof(BITMAPFILEHEADER));
  194. }
  195. ::GlobalUnlock((HGLOBAL) m_hDIB);
  196. return m_hDIB;
  197. }/* end of function ReadDIBFile */
  198. /*************************************************************/
  199. /* Name: CreateMemDC */
  200. /* Description: Creates a memory DC. */
  201. /*************************************************************/
  202. BOOL CBitmap::CreateMemDC(HDC hDC, LPRECT lpDCRect){
  203. DeleteMemDC();
  204. m_hMemDC = ::CreateCompatibleDC(hDC); // handle to the device context
  205. if(m_hMemDC == NULL){
  206. return(FALSE);
  207. }/* end of if statement */
  208. m_iMemDCWidth = RECTWIDTH(lpDCRect);
  209. m_iMemDCHeight = RECTHEIGHT(lpDCRect);
  210. m_hMemBMP = ::CreateCompatibleBitmap(hDC, m_iMemDCWidth, m_iMemDCHeight);
  211. if(m_hMemBMP == NULL){
  212. ::DeleteDC(m_hMemDC);
  213. return(FALSE);
  214. }/* end of if statement */
  215. ::SelectObject(m_hMemDC, m_hMemBMP);
  216. return TRUE;
  217. }/* end of function CreateMemDC */
  218. /*************************************************************/
  219. /* Name: DeleteMemDC */
  220. /* Description: Deletes the memory DC. */
  221. /*************************************************************/
  222. BOOL CBitmap::DeleteMemDC(){
  223. if (m_hMemDC) {
  224. ::DeleteDC(m_hMemDC);
  225. m_hMemDC = NULL;
  226. }
  227. if (m_hMemBMP) {
  228. ::DeleteObject(m_hMemBMP);
  229. m_hMemBMP = NULL;
  230. }
  231. m_iMemDCWidth = 0;
  232. m_iMemDCHeight = 0;
  233. return TRUE;
  234. }/* end of function DeleteMemDC */
  235. /*************************************************************/
  236. /* Name: CreateTransDC
  237. /* Description: Create a DC
  238. /*************************************************************/
  239. BOOL CBitmap::CreateTransDC(HDC hDC, LPRECT lpDCRect)
  240. {
  241. DeleteTransDC();
  242. m_hTransDC = ::CreateCompatibleDC(hDC); // handle to the device context
  243. if(m_hTransDC == NULL){
  244. return(FALSE);
  245. }/* end of if statement */
  246. m_iTransDCWidth = RECTWIDTH(lpDCRect);
  247. m_iTransDCHeight = RECTHEIGHT(lpDCRect);
  248. m_hTransBMP = ::CreateCompatibleBitmap(hDC, m_iTransDCWidth, m_iTransDCHeight);
  249. if(m_hTransBMP == NULL){
  250. ::DeleteDC(m_hTransDC);
  251. return(FALSE);
  252. }/* end of if statement */
  253. ::SelectObject(m_hTransDC, m_hTransBMP);
  254. return TRUE;
  255. }
  256. /*************************************************************/
  257. /* Name: DeleteTransDC
  258. /* Description:
  259. /*************************************************************/
  260. BOOL CBitmap::DeleteTransDC(){
  261. if (m_hTransDC) {
  262. ::DeleteDC(m_hTransDC);
  263. m_hTransDC = NULL;
  264. }
  265. if (m_hTransBMP) {
  266. ::DeleteObject(m_hTransBMP);
  267. m_hTransBMP = NULL;
  268. }
  269. m_iTransDCWidth = 0;
  270. m_iTransDCHeight = 0;
  271. return TRUE;
  272. }/* end of function DeleteTransDC */
  273. /*************************************************************/
  274. /* Name: BlitMemDC */
  275. /*************************************************************/
  276. BOOL CBitmap::BlitMemDC(HDC hDC, RECT* lpDCRect, RECT* lpDIBRect){
  277. if(NULL == hDC){
  278. ATLASSERT(FALSE);
  279. return(FALSE);
  280. }/* end of if statement */
  281. if(FALSE == CreateMemDC(hDC, lpDCRect)){
  282. ATLASSERT(FALSE);
  283. return FALSE;
  284. }/* end of if statement */
  285. RECT DIBRect = *lpDIBRect;
  286. RECT DCRect = *lpDCRect;
  287. // Blit the upper left corner
  288. DIBRect.bottom = (DIBRect.top+DIBRect.bottom)/2;
  289. DIBRect.right = (DIBRect.left+DIBRect.right)/2;
  290. DCRect.bottom = DCRect.top + RECTHEIGHT(&DIBRect);
  291. DCRect.right = DCRect.left + RECTWIDTH(&DIBRect);
  292. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  293. // Blit the upper right corner
  294. ::OffsetRect(&DCRect, RECTWIDTH(lpDCRect)-RECTWIDTH(&DIBRect), 0);
  295. ::OffsetRect(&DIBRect, RECTWIDTH(&DIBRect), 0);
  296. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  297. // Blit the lower right corner
  298. ::OffsetRect(&DCRect, 0, RECTHEIGHT(lpDCRect)-RECTHEIGHT(&DIBRect));
  299. ::OffsetRect(&DIBRect, 0, RECTHEIGHT(&DIBRect));
  300. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  301. // Blit the lower left corner
  302. ::OffsetRect(&DCRect, -RECTWIDTH(lpDCRect)+RECTWIDTH(&DIBRect), 0);
  303. ::OffsetRect(&DIBRect, -RECTWIDTH(&DIBRect), 0);
  304. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  305. // Blit the the middle if window resized beyond the bitmap
  306. if (RECTWIDTH(&m_rc)<RECTWIDTH(lpDCRect)+20) {
  307. int neededWidth = RECTWIDTH(lpDCRect)+20-RECTWIDTH(&m_rc);
  308. RECT DIBRect = m_rc;
  309. RECT DCRect = *lpDCRect;
  310. DIBRect.bottom = (DIBRect.top+DIBRect.bottom)/2;
  311. DIBRect.left += (RECTWIDTH(&m_rc)-neededWidth)/2;
  312. DIBRect.right = DIBRect.left + neededWidth;
  313. DCRect.bottom = DCRect.top+RECTHEIGHT(&DIBRect);
  314. DCRect.left += RECTWIDTH(&m_rc)/2;
  315. DCRect.right = DCRect.left + neededWidth;
  316. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  317. ::OffsetRect(&DCRect, 0, RECTHEIGHT(lpDCRect)-RECTHEIGHT(&DIBRect));
  318. ::OffsetRect(&DIBRect, 0, RECTHEIGHT(&DIBRect));
  319. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  320. }
  321. if (RECTHEIGHT(&m_rc)<RECTHEIGHT(lpDCRect)+20) {
  322. int neededHeight = RECTHEIGHT(lpDCRect)+20-RECTHEIGHT(&m_rc);
  323. RECT DIBRect = m_rc;
  324. RECT DCRect = *lpDCRect;
  325. DIBRect.top += (RECTHEIGHT(&m_rc)-neededHeight)/2;
  326. DIBRect.bottom = DIBRect.top + neededHeight;
  327. DIBRect.right = (DIBRect.left+DIBRect.right)/2;
  328. DCRect.top += RECTHEIGHT(&m_rc)/2;
  329. DCRect.bottom = DCRect.top + neededHeight;
  330. DCRect.right = DCRect.left+RECTWIDTH(&DIBRect);
  331. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  332. ::OffsetRect(&DCRect, RECTWIDTH(lpDCRect)-RECTWIDTH(&DIBRect), 0);
  333. ::OffsetRect(&DIBRect, RECTWIDTH(&DIBRect), 0);
  334. PaintDIB(m_hMemDC, &DCRect, &DCRect, &DIBRect);
  335. }
  336. return TRUE;
  337. }/* end of function BlitMemDC */
  338. /*************************************************************************
  339. *
  340. * PaintDIB()
  341. *
  342. * Parameters:
  343. *
  344. * HDC hDC - DC to do output to
  345. *
  346. * LPRECT lpDCRect - rectangle on DC to do output to
  347. *
  348. * Return Value:
  349. *
  350. * BOOL - TRUE if DIB was drawn, FALSE otherwise
  351. *
  352. * Description:
  353. * Painting routine for a DIB. Calls StretchDIBits() or
  354. * SetDIBitsToDevice() to paint the DIB. The DIB is
  355. * output to the specified DC, at the coordinates given
  356. * in lpDCRect. The area of the DIB to be output is
  357. * given by lpDIBRect.
  358. *
  359. ************************************************************************/
  360. BOOL WINAPI CBitmap::PaintDIB(HDC hDC,
  361. LPRECT lpDCWRect,
  362. LPRECT lpDCRect,
  363. LPRECT lpDIBRect,
  364. bool complex)
  365. {
  366. LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER
  367. LPSTR lpDIBBits; // Pointer to DIB bits
  368. BOOL bSuccess=FALSE; // Success/fail flag
  369. HPALETTE hOldPal=NULL; // Previous palette
  370. /* Check for valid DIB handle */
  371. if (m_hDIB == NULL)
  372. return FALSE;
  373. /* Lock down the DIB, and get a pointer to the beginning of the bit
  374. * buffer
  375. */
  376. lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
  377. lpDIBBits = FindDIBBits(lpDIBHdr);
  378. // Get the DIB's palette, then select it into DC
  379. // Select as background since we have
  380. // already realized in forground if needed
  381. //if(NULL != m_hPal){
  382. //
  383. // hOldPal = ::SelectPalette(hDC, m_hPal, TRUE);
  384. //}/* end of if statement */
  385. /* Make sure to use the stretching mode best for color pictures */
  386. ::SetStretchBltMode(hDC, COLORONCOLOR);
  387. /* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
  388. if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) && (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
  389. {
  390. bSuccess = ::SetDIBitsToDevice(hDC, // hDC
  391. lpDCRect->left, // DestX
  392. lpDCRect->top, // DestY
  393. RECTWIDTH(lpDCRect), // nDestWidth
  394. RECTHEIGHT(lpDCRect), // nDestHeight
  395. lpDIBRect->left, // SrcX
  396. (int)DIBHeight(lpDIBHdr) -
  397. lpDIBRect->top -
  398. RECTHEIGHT(lpDIBRect), // SrcY
  399. 0, // nStartScan
  400. (WORD)DIBHeight(lpDIBHdr), // nNumScans
  401. lpDIBBits, // lpBits
  402. (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
  403. DIB_RGB_COLORS); // wUsage
  404. }
  405. else
  406. {
  407. // resize the bitmap first and blit it
  408. if (complex) {
  409. if (m_hMemDC == NULL)
  410. BlitMemDC(hDC, lpDCWRect, lpDIBRect);
  411. else if (m_iMemDCWidth!= RECTWIDTH(lpDCWRect) ||
  412. m_iMemDCHeight!= RECTHEIGHT(lpDCWRect)) {
  413. if (EqualRect(lpDCWRect, lpDCRect))
  414. BlitMemDC(hDC, lpDCWRect, lpDIBRect);
  415. }
  416. bSuccess = ::BitBlt(hDC,
  417. lpDCRect->left, lpDCRect->top,
  418. RECTWIDTH(lpDCRect), RECTHEIGHT(lpDCRect),
  419. m_hMemDC, lpDCRect->left, lpDCRect->top, SRCCOPY);
  420. ATLTRACE(TEXT("BitBlt %d %d %d %d\n"),
  421. lpDCRect->left, lpDCRect->top,
  422. RECTWIDTH(lpDCRect), RECTHEIGHT(lpDCRect));
  423. }
  424. else {
  425. bSuccess = ::StretchDIBits(hDC, // hDC
  426. lpDCRect->left, // DestX
  427. lpDCRect->top, // DestY
  428. RECTWIDTH(lpDCRect), // nDestWidth
  429. RECTHEIGHT(lpDCRect), // nDestHeight
  430. lpDIBRect->left, // SrcX
  431. lpDIBRect->top, // SrcY
  432. RECTWIDTH(lpDIBRect), // wSrcWidth
  433. RECTHEIGHT(lpDIBRect), // wSrcHeight
  434. lpDIBBits, // lpBits
  435. (LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
  436. DIB_RGB_COLORS, // wUsage
  437. SRCCOPY); // dwROP
  438. }
  439. }
  440. ::GlobalUnlock((HGLOBAL) m_hDIB);
  441. /* Reselect old palette */
  442. //if (hOldPal != NULL)
  443. //{
  444. // ::SelectPalette(hDC, hOldPal, TRUE);
  445. //}
  446. return bSuccess;
  447. }
  448. /*************************************************************************
  449. *
  450. * PaintTransparentDIB()
  451. *
  452. * Parameters:
  453. *
  454. * HDC hDC - DC to do output to
  455. *
  456. * LPRECT lpDCRect - rectangle on DC to do output to
  457. *
  458. * COLORREF clr - color to be used as a transparency
  459. *
  460. * Return Value:
  461. *
  462. * BOOL - TRUE if DIB was drawn, FALSE otherwise
  463. *
  464. *
  465. * Description:
  466. * Painting routine for a DIB. Calls StretchDIBits() or
  467. * SetDIBitsToDevice() to paint the DIB. The DIB is
  468. * output to the specified DC, at the coordinates given
  469. * in lpDCRect. The area of the DIB to be output is
  470. * given by lpDIBRect.
  471. *
  472. ************************************************************************/
  473. BOOL WINAPI CBitmap::PaintTransparentDIB(HDC hDC,
  474. LPRECT lpDCWRect,
  475. LPRECT lpDCRect,
  476. TransparentBlitType blitType,
  477. bool complex,
  478. HWND hWnd){
  479. BOOL bSuccess=FALSE; // Success/fail flag
  480. if(NULL == m_hDIB){
  481. return(bSuccess);
  482. }/* end of if statement */
  483. if(blitType != DISABLE){
  484. LONG lWidth = RECTWIDTH(lpDCRect);
  485. LONG lHeight = RECTHEIGHT(lpDCRect);
  486. RECT rc = {0, 0, lWidth, lHeight};
  487. ATLTRACE(TEXT("PaintTransparentDIB %d %d %d %d\n"), lWidth, lHeight,
  488. m_iTransDCWidth, m_iTransDCHeight);
  489. BOOL bNewRgn = FALSE;
  490. if (!m_hTransDC || lWidth != m_iTransDCWidth || lHeight != m_iTransDCHeight) {
  491. bNewRgn = TRUE;
  492. CreateTransDC(hDC, &rc);
  493. if(FALSE == PaintDIB(m_hTransDC, lpDCWRect, &rc, &m_rc)){
  494. return (FALSE);
  495. }/* end of if statement */
  496. }
  497. COLORREF clrTrans = RGB(255, 0, 255);
  498. LPSTR pDIB = (LPSTR)::GlobalLock(m_hDIB);
  499. LONG lBmpWidth = DIBWidth(pDIB);
  500. LONG lBmpHeight = DIBHeight(pDIB);
  501. ::GlobalUnlock(m_hDIB);
  502. if(0 != lBmpWidth && 0 != lBmpHeight){
  503. if(TRANSPARENT_TOP_LEFT == blitType ||
  504. TOP_LEFT_WITH_BACKCOLOR == blitType ||
  505. TOP_LEFT_WINDOW_REGION == blitType )
  506. clrTrans = ::GetPixel(m_hTransDC, 0, 0);
  507. else if(TRANSPARENT_BOTTOM_RIGHT == blitType ||
  508. BOTTOM_RIGHT_WITH_BACKCOLOR == blitType ||
  509. BOTTOM_RIGHT_WINDOW_REGION == blitType )
  510. clrTrans = ::GetPixel(m_hTransDC, lBmpWidth - 1, lBmpHeight -1);
  511. }/* end of if statement */
  512. if (TOP_LEFT_WINDOW_REGION == blitType ||
  513. BOTTOM_RIGHT_WINDOW_REGION == blitType ) {
  514. HRGN hOldRgn = NULL;
  515. if (::IsWindow(hWnd)) {
  516. ::GetWindowRgn(hWnd, hOldRgn);
  517. if (bNewRgn) {
  518. if (m_hRgn)
  519. ::DeleteObject(m_hRgn);
  520. GetRegion(m_hTransDC, &m_hRgn, &rc, clrTrans);
  521. }
  522. HRGN hNewRgn = ::CreateRectRgn(0, 0, 1, 1);
  523. ::CombineRgn(hNewRgn, m_hRgn, NULL, RGN_COPY);
  524. int nRet = ::SetWindowRgn(hWnd, hNewRgn, TRUE);
  525. ATLTRACE(TEXT("SetWindowRgn %d\n"), nRet);
  526. ::SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
  527. }
  528. bSuccess = ::StretchBlt(hDC,
  529. lpDCRect->left, // DestX
  530. lpDCRect->top, // DestY
  531. lWidth, // nDestWidth
  532. lHeight, // nDestHeight
  533. m_hTransDC,
  534. 0, // SrcX
  535. 0, // SrcY
  536. lWidth, // nSrcWidth
  537. lHeight, // nSrcHeight
  538. SRCCOPY
  539. );
  540. if (::IsWindow(hWnd) && hOldRgn)
  541. ::SetWindowRgn(hWnd, hOldRgn, FALSE);
  542. }
  543. else
  544. bSuccess = ::TransparentBlt(hDC,
  545. lpDCRect->left, // DestX
  546. lpDCRect->top, // DestY
  547. lWidth, // nDestWidth
  548. lHeight, // nDestHeight
  549. m_hTransDC,
  550. 0, // SrcX
  551. 0, // SrcY
  552. lWidth, // nSrcWidth
  553. lHeight, // nSrcHeight
  554. clrTrans // transparent color
  555. );
  556. }
  557. else {
  558. // no transparent blit
  559. bSuccess = PaintDIB(hDC, lpDCWRect, lpDCRect, &m_rc, complex);
  560. }/* end of if statement */
  561. return bSuccess;
  562. }/* end of function PaintTransparentDIB */
  563. /*************************************************************************
  564. *
  565. * CreateDIBPalette()
  566. *
  567. * Parameter:
  568. *
  569. * HDIB hDIB - specifies the DIB
  570. *
  571. * Return Value:
  572. *
  573. * HPALETTE - specifies the palette
  574. *
  575. * Description:
  576. *
  577. * This function creates a palette from a DIB by allocating memory for the
  578. * logical palette, reading and storing the colors from the DIB's color table
  579. * into the logical palette, creating a palette from this logical palette,
  580. * and then returning the palette's handle. This allows the DIB to be
  581. * displayed using the best possible colors (important for DIBs with 256 or
  582. * more colors).
  583. *
  584. ************************************************************************/
  585. BOOL WINAPI CBitmap::CreateDIBPalette()
  586. {
  587. LPLOGPALETTE lpPal; // pointer to a logical palette
  588. HANDLE hLogPal; // handle to a logical palette
  589. HPALETTE hPal = NULL; // handle to a palette
  590. int i; // loop index
  591. WORD wNumColors; // number of colors in color table
  592. LPSTR lpbi; // pointer to packed-DIB
  593. LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
  594. LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
  595. BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
  596. BOOL bResult = FALSE;
  597. /* if handle to DIB is invalid, return FALSE */
  598. if (m_hDIB == NULL)
  599. return FALSE;
  600. lpbi = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
  601. /* get pointer to BITMAPINFO (Win 3.0) */
  602. lpbmi = (LPBITMAPINFO)lpbi;
  603. /* get pointer to BITMAPCOREINFO (old 1.x) */
  604. lpbmc = (LPBITMAPCOREINFO)lpbi;
  605. /* get the number of colors in the DIB */
  606. wNumColors = DIBNumColors(lpbi);
  607. if (wNumColors != 0)
  608. {
  609. /* allocate memory block for logical palette */
  610. hLogPal = ::GlobalAlloc(GHND, sizeof(LOGPALETTE)
  611. + sizeof(PALETTEENTRY)
  612. * wNumColors);
  613. /* if not enough memory, clean up and return NULL */
  614. if (hLogPal == 0)
  615. {
  616. ::GlobalUnlock((HGLOBAL) m_hDIB);
  617. return FALSE;
  618. }
  619. lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
  620. /* set version and number of palette entries */
  621. lpPal->palVersion = PALVERSION;
  622. lpPal->palNumEntries = (WORD)wNumColors;
  623. /* is this a Win 3.0 DIB? */
  624. bWinStyleDIB = IS_WIN30_DIB(lpbi);
  625. for (i = 0; i < (int)wNumColors; i++)
  626. {
  627. if (bWinStyleDIB)
  628. {
  629. lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
  630. lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
  631. lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
  632. lpPal->palPalEntry[i].peFlags = 0;
  633. }
  634. else
  635. {
  636. lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
  637. lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
  638. lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
  639. lpPal->palPalEntry[i].peFlags = 0;
  640. }
  641. }
  642. /* create the palette and get handle to it */
  643. hPal = (HPALETTE)::CreatePalette((LPLOGPALETTE)lpPal);
  644. ::GlobalUnlock((HGLOBAL) hLogPal);
  645. ::GlobalFree((HGLOBAL) hLogPal);
  646. m_hPal = hPal;
  647. }
  648. ::GlobalUnlock((HGLOBAL) m_hDIB);
  649. return (NULL != m_hPal);
  650. }
  651. /*************************************************************************
  652. *
  653. * ConvertColorTableGray()
  654. *
  655. * Parameter:
  656. *
  657. * HDIB hDIB - specifies the DIB
  658. *
  659. * Return Value:
  660. *
  661. * HPALETTE - specifies the palette
  662. *
  663. * Description:
  664. *
  665. ************************************************************************/
  666. BOOL WINAPI CBitmap::ConvertColorTableGray()
  667. {
  668. int i; // loop index
  669. WORD wNumColors; // number of colors in color table
  670. LPSTR lpbi; // pointer to packed-DIB
  671. LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
  672. LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
  673. BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
  674. BOOL bResult = FALSE;
  675. /* if handle to DIB is invalid, return FALSE */
  676. if (m_hDIB == NULL)
  677. return FALSE;
  678. lpbi = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
  679. /* get pointer to BITMAPINFO (Win 3.0) */
  680. lpbmi = (LPBITMAPINFO)lpbi;
  681. /* get pointer to BITMAPCOREINFO (old 1.x) */
  682. lpbmc = (LPBITMAPCOREINFO)lpbi;
  683. /* get the number of colors in the DIB */
  684. wNumColors = DIBNumColors(lpbi);
  685. if (wNumColors != 0)
  686. {
  687. /* is this a Win 3.0 DIB? */
  688. bWinStyleDIB = IS_WIN30_DIB(lpbi);
  689. for (i = 0; i < (int)wNumColors; i++)
  690. {
  691. if (bWinStyleDIB)
  692. {
  693. BYTE L = RGBtoL(lpbmi->bmiColors[i].rgbRed,
  694. lpbmi->bmiColors[i].rgbGreen,
  695. lpbmi->bmiColors[i].rgbBlue);
  696. lpbmi->bmiColors[i].rgbRed = L;
  697. lpbmi->bmiColors[i].rgbGreen = L;
  698. lpbmi->bmiColors[i].rgbBlue = L;
  699. }
  700. else
  701. {
  702. BYTE L = RGBtoL(lpbmc->bmciColors[i].rgbtRed,
  703. lpbmc->bmciColors[i].rgbtGreen,
  704. lpbmc->bmciColors[i].rgbtBlue);
  705. lpbmc->bmciColors[i].rgbtRed = L;
  706. lpbmc->bmciColors[i].rgbtGreen = L;
  707. lpbmc->bmciColors[i].rgbtBlue = L;
  708. }
  709. }
  710. }
  711. ::GlobalUnlock((HGLOBAL) m_hDIB);
  712. return TRUE;
  713. }
  714. /*************************************************************************
  715. *
  716. * ConvertDIBGray()
  717. *
  718. * Parameter:
  719. *
  720. * HDIB hDIB - specifies the DIB
  721. *
  722. * Return Value:
  723. *
  724. * blitType - specifies the TransparentBlitType
  725. *
  726. * Description:
  727. *
  728. ************************************************************************/
  729. BOOL WINAPI CBitmap::ConvertDIBGray(TransparentBlitType blitType)
  730. {
  731. /* if handle to DIB is invalid, return FALSE */
  732. if (m_hDIB == NULL)
  733. return FALSE;
  734. WORD wNumColors; // number of colors in color table
  735. LPSTR lpbi; // pointer to packed-DIB
  736. LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
  737. LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (old)
  738. LPSTR lpDIBBits; // Pointer to DIB bits
  739. LPSTR lpKeyColor;
  740. lpbi = (LPSTR) ::GlobalLock((HGLOBAL) m_hDIB);
  741. /* get pointer to BITMAPINFO (Win 3.0) */
  742. lpbmi = (LPBITMAPINFO)lpbi;
  743. /* get pointer to BITMAPCOREINFO (old 1.x) */
  744. lpbmc = (LPBITMAPCOREINFO)lpbi;
  745. /* get the number of colors in the DIB */
  746. wNumColors = DIBNumColors(lpbi);
  747. if (wNumColors != 0)
  748. return FALSE;
  749. /* Lock down the DIB, and get a pointer to the beginning of the bit
  750. * buffer
  751. */
  752. lpDIBBits = FindDIBBits(lpbi);
  753. // 24 bit color case
  754. if (lpbmi->bmiHeader.biBitCount==24) {
  755. int rowLength = lpbmi->bmiHeader.biWidth*3;
  756. if (rowLength%4)
  757. rowLength = (rowLength/4+1)*4;
  758. if(TRANSPARENT_TOP_LEFT == blitType ||
  759. TOP_LEFT_WITH_BACKCOLOR == blitType ||
  760. TOP_LEFT_WINDOW_REGION == blitType )
  761. lpKeyColor = lpDIBBits;
  762. else if(TRANSPARENT_BOTTOM_RIGHT == blitType ||
  763. BOTTOM_RIGHT_WITH_BACKCOLOR == blitType ||
  764. BOTTOM_RIGHT_WINDOW_REGION == blitType )
  765. lpKeyColor = lpDIBBits+rowLength*lpbmi->bmiHeader.biHeight-1;
  766. // TODO: Handle magenta
  767. for (int i=0; i<lpbmi->bmiHeader.biHeight; i++) {
  768. for (int j=0; j<lpbmi->bmiHeader.biWidth; j++) {
  769. if (*(lpDIBBits+i*rowLength+j*3) != *(lpDIBBits) ||
  770. *(lpDIBBits+i*rowLength+j*3+1) != *(lpDIBBits+1) ||
  771. *(lpDIBBits+i*rowLength+j*3+2) != *(lpDIBBits+2)) {
  772. BYTE L = RGBtoL(*(lpDIBBits+i*rowLength+j*3),
  773. *(lpDIBBits+i*rowLength+j*3+1),
  774. *(lpDIBBits+i*rowLength+j*3+2));
  775. *(lpDIBBits+i*rowLength+j*3) = L;
  776. *(lpDIBBits+i*rowLength+j*3+1) = L;
  777. *(lpDIBBits+i*rowLength+j*3+2) = L;
  778. }
  779. }
  780. }
  781. }
  782. // 16 bit color case
  783. else if (lpbmi->bmiHeader.biBitCount==16) {
  784. int rowLength = lpbmi->bmiHeader.biWidth*2;
  785. if (rowLength%4)
  786. rowLength = (rowLength/4+1)*4;
  787. if (lpbmi->bmiHeader.biCompression==BI_RGB) {
  788. for (int i=0; i<lpbmi->bmiHeader.biHeight; i++) {
  789. for (int j=0; j<lpbmi->bmiHeader.biWidth; j++) {
  790. WORD color = *(WORD*)(lpDIBBits+i*rowLength+j*2);
  791. WORD green = (WORD)(color & 0x03E0);
  792. WORD red = (WORD)(green << 5);
  793. WORD blue = (WORD)(green >> 5);
  794. color = (WORD)(red | green | blue);
  795. *(WORD*)(lpDIBBits+i*rowLength+j*2) = color;
  796. }
  797. }
  798. }
  799. }
  800. ::GlobalUnlock((HGLOBAL) m_hDIB);
  801. return TRUE;
  802. }
  803. /*************************************************************************
  804. *
  805. * FindDIBBits()
  806. *
  807. * Parameter:
  808. *
  809. * LPSTR lpbi - pointer to packed-DIB memory block
  810. *
  811. * Return Value:
  812. *
  813. * LPSTR - pointer to the DIB bits
  814. *
  815. * Description:
  816. *
  817. * This function calculates the address of the DIB's bits and returns a
  818. * pointer to the DIB bits.
  819. *
  820. ************************************************************************/
  821. LPSTR WINAPI CBitmap::FindDIBBits(LPSTR lpbi)
  822. {
  823. return (lpbi + *(LPDWORD)lpbi + PaletteSize(lpbi));
  824. }
  825. /*************************************************************/
  826. /* Name: SetImage
  827. /* Description: load bitmap image
  828. /*************************************************************/
  829. HRESULT CBitmap::SetImage(TCHAR* strFilename, HINSTANCE hRes)
  830. {
  831. HRESULT hr = S_OK;
  832. CleanUp();
  833. m_hDIB = ReadDIBFile(strFilename, hRes);
  834. if (m_hDIB){
  835. // we succeded
  836. if(m_fLoadPalette){
  837. CreateDIBPalette();
  838. }/* end of if statement */
  839. LPSTR pDIB = (LPSTR)::GlobalLock(m_hDIB);
  840. m_rc.left = 0;
  841. m_rc.top = 0;
  842. m_rc.right = DIBWidth(pDIB);
  843. m_rc.bottom = DIBHeight(pDIB);
  844. ::GlobalUnlock((HGLOBAL)m_hDIB);
  845. }
  846. else {
  847. hr = E_FAIL; // failed to load this DIB
  848. }/* end of if statement */
  849. return hr;
  850. }
  851. /*************************************************************************
  852. *
  853. * DIBWidth()
  854. *
  855. * Parameter:
  856. *
  857. * LPSTR lpbi - pointer to packed-DIB memory block
  858. *
  859. * Return Value:
  860. *
  861. * DWORD - width of the DIB
  862. *
  863. * Description:
  864. *
  865. * This function gets the width of the DIB from the BITMAPINFOHEADER
  866. * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  867. * width field if it is an other-style DIB.
  868. *
  869. ************************************************************************/
  870. DWORD WINAPI DIBWidth(LPSTR lpDIB)
  871. {
  872. LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
  873. LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
  874. /* point to the header (whether Win 3.0 and old) */
  875. lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  876. lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  877. /* return the DIB width if it is a Win 3.0 DIB */
  878. if (IS_WIN30_DIB(lpDIB))
  879. return lpbmi->biWidth;
  880. else /* it is an other-style DIB, so return its width */
  881. return (DWORD)lpbmc->bcWidth;
  882. }
  883. /*************************************************************************
  884. *
  885. * DIBHeight()
  886. *
  887. * Parameter:
  888. *
  889. * LPSTR lpbi - pointer to packed-DIB memory block
  890. *
  891. * Return Value:
  892. *
  893. * DWORD - height of the DIB
  894. *
  895. * Description:
  896. *
  897. * This function gets the height of the DIB from the BITMAPINFOHEADER
  898. * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
  899. * height field if it is an other-style DIB.
  900. *
  901. ************************************************************************/
  902. DWORD WINAPI DIBHeight(LPSTR lpDIB)
  903. {
  904. LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
  905. LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
  906. /* point to the header (whether old or Win 3.0 */
  907. lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  908. lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  909. /* return the DIB height if it is a Win 3.0 DIB */
  910. if (IS_WIN30_DIB(lpDIB))
  911. return lpbmi->biHeight;
  912. else /* it is an other-style DIB, so return its height */
  913. return (DWORD)lpbmc->bcHeight;
  914. }
  915. DWORD WINAPI DIBSize(LPSTR lpDIB)
  916. {
  917. LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
  918. LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
  919. /* point to the header (whether Win 3.0 and old) */
  920. lpbmi = (LPBITMAPINFOHEADER)lpDIB;
  921. lpbmc = (LPBITMAPCOREHEADER)lpDIB;
  922. /* return the DIB width if it is a Win 3.0 DIB */
  923. if (IS_WIN30_DIB(lpDIB))
  924. return lpbmi->biBitCount*DIBWidth(lpDIB)*DIBHeight(lpDIB);
  925. else /* it is an other-style DIB, so return its width */
  926. return (DWORD)lpbmc->bcWidth*DIBWidth(lpDIB)*DIBHeight(lpDIB);
  927. }
  928. /*************************************************************************
  929. *
  930. * PaletteSize()
  931. *
  932. * Parameter:
  933. *
  934. * LPSTR lpbi - pointer to packed-DIB memory block
  935. *
  936. * Return Value:
  937. *
  938. * WORD - size of the color palette of the DIB
  939. *
  940. * Description:
  941. *
  942. * This function gets the size required to store the DIB's palette by
  943. * multiplying the number of colors by the size of an RGBQUAD (for a
  944. * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an other-
  945. * style DIB).
  946. *
  947. ************************************************************************/
  948. WORD WINAPI CBitmap::PaletteSize(LPSTR lpbi)
  949. {
  950. /* calculate the size required by the palette */
  951. if (IS_WIN30_DIB (lpbi))
  952. return (WORD)(DIBNumColors(lpbi) * sizeof(RGBQUAD));
  953. else
  954. return (WORD)(DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
  955. }
  956. /*************************************************************************
  957. *
  958. * DIBNumColors()
  959. *
  960. * Parameter:
  961. *
  962. * LPSTR lpbi - pointer to packed-DIB memory block
  963. *
  964. * Return Value:
  965. *
  966. * WORD - number of colors in the color table
  967. *
  968. * Description:
  969. *
  970. * This function calculates the number of colors in the DIB's color table
  971. * by finding the bits per pixel for the DIB (whether Win3.0 or other-style
  972. * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
  973. * if 24, no colors in color table.
  974. *
  975. ************************************************************************/
  976. WORD WINAPI CBitmap::DIBNumColors(LPSTR lpbi)
  977. {
  978. WORD wBitCount; // DIB bit count
  979. /* If this is a Windows-style DIB, the number of colors in the
  980. * color table can be less than the number of bits per pixel
  981. * allows for (i.e. lpbi->biClrUsed can be set to some value).
  982. * If this is the case, return the appropriate value.
  983. */
  984. if (IS_WIN30_DIB(lpbi))
  985. {
  986. DWORD dwClrUsed;
  987. dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
  988. if (dwClrUsed != 0)
  989. return (WORD)dwClrUsed;
  990. }
  991. /* Calculate the number of colors in the color table based on
  992. * the number of bits per pixel for the DIB.
  993. */
  994. if (IS_WIN30_DIB(lpbi))
  995. wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
  996. else
  997. wBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
  998. /* return number of colors based on bits per pixel */
  999. switch (wBitCount)
  1000. {
  1001. case 1:
  1002. return 2;
  1003. case 4:
  1004. return 16;
  1005. case 8:
  1006. return 256;
  1007. default:
  1008. return 0;
  1009. }
  1010. }
  1011. /*************************************************************************/
  1012. /* Function: PutImage */
  1013. /* Description: Reads the DIB file (from file or resource) into a DIB, */
  1014. /* updates palette and rects of the internal bitmap. */
  1015. /*************************************************************************/
  1016. HRESULT CBitmap::PutImage(BSTR strFilename, HINSTANCE hRes, IUnknown* pUnk, bool fGrayOut, TransparentBlitType blitType){
  1017. USES_CONVERSION;
  1018. HRESULT hr = S_OK;
  1019. TCHAR strBuffer[MAX_PATH] = TEXT("\0");
  1020. if(NULL == hRes){
  1021. // do not bother to resolve files if loading from resources
  1022. // use this API to resolve http:/ file:/ html:/
  1023. hr = ::URLDownloadToCacheFile(pUnk, OLE2T(strFilename), strBuffer, MAX_PATH, 0, NULL);
  1024. if(FAILED(hr)){
  1025. #if _DEBUG
  1026. TCHAR strTmpBuffer[MAX_PATH + 25];
  1027. wsprintf(strTmpBuffer, TEXT("Failed to download %s, if it is a local file it might not exist"), OLE2T(strFilename));
  1028. ::MessageBox(::GetFocus(), strTmpBuffer, TEXT("Error"), MB_OK);
  1029. #endif
  1030. return(hr);
  1031. }/* end of if statement */
  1032. ATLTRACE(TEXT("Loading new button image %s \n"), strBuffer);
  1033. }/* end of if statement */
  1034. if (lstrlen(strBuffer) == 0){
  1035. hr = SetImage(OLE2T(strFilename), hRes);
  1036. }
  1037. else {
  1038. hr = SetImage(strBuffer, hRes);
  1039. }/* end of if statement */
  1040. if(FAILED(hr)){
  1041. return(hr);
  1042. }/* end of if statement */
  1043. // we succeded
  1044. if(m_fLoadPalette){
  1045. CreateDIBPalette();
  1046. }/* end of if statement */
  1047. if (fGrayOut) {
  1048. ConvertDIBGray(blitType);
  1049. ConvertColorTableGray();
  1050. }/* end of if statement */
  1051. return(hr);
  1052. }/* end of function PutImage */
  1053. //----------------------------------------------------------------------------
  1054. // CWMPBitmap::GetRegion
  1055. //
  1056. // Purpose:
  1057. // This method will create a region based on each transparent color found
  1058. // within the bitmap.
  1059. // Parameters:
  1060. // phRgn - pointer to the return of a region created from the bitmap
  1061. // crTransparentColor - RGB based COLORREF of the color that is considered
  1062. // transparent
  1063. // fInvert - Set to TRUE, to invert the region created based on the transparent
  1064. // color
  1065. // Returns:
  1066. // HRESULT
  1067. //
  1068. //----------------------------------------------------------------------------
  1069. #pragma optimize( "t", on )
  1070. HRESULT CBitmap::GetRegion(HDC hDC, HRGN *phRgn, RECT* pRect, COLORREF crTransparentColor, bool fInvert/*=FALSE*/) const
  1071. {
  1072. //DASSERTMSG(NULL != m_hBMP, "CWMPBitmap::GetRegion(), no bitmap has been created yet. Call a create method first.");
  1073. //DASSERTMSG(OBJ_BITMAP == ::GetObjectType(m_hBMP), "CWMPBitmap::GetRegion(), m_hBMP is invalid");
  1074. //DASSERTMSG(NULL != phRgn, "CWMPBitmap::GetRegion(), parameter phRgn is invalid");
  1075. //DASSERTMSG(0 == (crTransparentColor&0xFF000000), "CWMPBitmap::GetRegion(), crTransparentColor must be RGB values");
  1076. *phRgn = NULL;
  1077. //if (NULL == m_hBMP) // no bitmap has been created yet
  1078. //return E_WMP_BMP_BITMAP_NOT_CREATED;
  1079. HRESULT hr = S_OK;
  1080. const COLORREF kcrTolerance = RGB(0,0,0);
  1081. // For better performances, we will use the ExtCreateRegion() function to create the
  1082. // region. This function take a RGNDATA structure on entry.
  1083. const int knMaxRect = 2000; // do not make bigger then 2000, see below
  1084. // alloc the rects on the stack 2000*sizeof(rect) = 32k
  1085. RGNDATA *pData = reinterpret_cast<RGNDATA*>(_alloca(sizeof(RGNDATAHEADER) + (sizeof(RECT) * knMaxRect)));
  1086. pData->rdh.dwSize = sizeof(RGNDATAHEADER);
  1087. pData->rdh.iType = RDH_RECTANGLES;
  1088. pData->rdh.nCount = 0;
  1089. pData->rdh.nRgnSize = 0;
  1090. SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  1091. // precompute highest and lowest values for the "transparent" pixels
  1092. BYTE ubLowRed = (BYTE)__max(0, GetRValue(crTransparentColor) - GetRValue(kcrTolerance));
  1093. BYTE ubLowGreen = (BYTE)__max(0, GetGValue(crTransparentColor) - GetGValue(kcrTolerance));
  1094. BYTE ubLowBlue = (BYTE)__max(0, GetBValue(crTransparentColor) - GetBValue(kcrTolerance));
  1095. BYTE ubHighRed = (BYTE)__min(0xFF, GetRValue(crTransparentColor) + GetRValue(kcrTolerance));
  1096. BYTE ubHighGreen = (BYTE)__min(0xFF, GetGValue(crTransparentColor) + GetGValue(kcrTolerance));
  1097. BYTE ubHighBlue = (BYTE)__min(0xFF, GetBValue(crTransparentColor) + GetBValue(kcrTolerance));
  1098. // scan the bitmap from top to bottom
  1099. for (int y = 0; y < RECTHEIGHT(pRect); y++)
  1100. {
  1101. // scan each bitmap pixel from left to right
  1102. for (int x = 0; x < RECTWIDTH(pRect); x++)
  1103. {
  1104. // search for a continuous range of "non transparent pixels"
  1105. int nStartX = x;
  1106. while (x < RECTWIDTH(pRect))
  1107. {
  1108. COLORREF crPixel = ::GetPixel(hDC, x, y);
  1109. BYTE ubRed = GetRValue(crPixel);
  1110. if (ubRed >= ubLowRed && ubRed <= ubHighRed)
  1111. {
  1112. BYTE ubGreen = GetGValue(crPixel);
  1113. if (ubGreen >= ubLowGreen && ubGreen <= ubHighGreen)
  1114. {
  1115. BYTE ubBlue = GetBValue(crPixel);
  1116. if (ubBlue >= ubLowBlue && ubBlue <= ubHighBlue)
  1117. break; // This pixel is "transparent"
  1118. }
  1119. }
  1120. x++; // next horz. pixel
  1121. }
  1122. if (x > nStartX)
  1123. {
  1124. // add the pixels (nStartX, y) to (x, y+1) as a new rectangle in the region
  1125. RECT *pr = reinterpret_cast<RECT*>(&pData->Buffer);
  1126. SetRect(&pr[pData->rdh.nCount], nStartX, y, x, y+1);
  1127. if (nStartX < pData->rdh.rcBound.left)
  1128. pData->rdh.rcBound.left = nStartX;
  1129. if (y < pData->rdh.rcBound.top)
  1130. pData->rdh.rcBound.top = y;
  1131. if (x > pData->rdh.rcBound.right)
  1132. pData->rdh.rcBound.right = x;
  1133. if (y+1 > pData->rdh.rcBound.bottom)
  1134. pData->rdh.rcBound.bottom = y+1;
  1135. // ericwol: warning to optimization people. NT4.0 is very buggy creating regions out of rects!!!
  1136. // test any changes you make here!!!
  1137. pData->rdh.nCount++;
  1138. // on Windows98, ExtCreateRegion() may fail if the number of rectangles is too
  1139. // large (ie: > 4000). Therefore, we have to create the region by multiple steps.
  1140. if (pData->rdh.nCount == knMaxRect)
  1141. {
  1142. HRGN hrgnNew = ::ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  1143. //HRWIN32(hr, NULL == hrgnNew, "ExtCreateRegion");
  1144. if (NULL != hrgnNew)
  1145. {
  1146. // if we already have a region from a previous pass,
  1147. // combine the new region with the old region
  1148. if (*phRgn)
  1149. {
  1150. ::CombineRgn(*phRgn, *phRgn, hrgnNew, RGN_OR);
  1151. ::DeleteObject(hrgnNew);
  1152. }
  1153. else
  1154. {
  1155. *phRgn = hrgnNew;
  1156. }
  1157. }
  1158. // reset the rect count for another pass
  1159. pData->rdh.nCount = 0;
  1160. SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  1161. }
  1162. }
  1163. } // x loop
  1164. } // y loop
  1165. // create or extend the region with the remaining rectangles from the final pass
  1166. HRGN hrgnNew = ::ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  1167. //HRWIN32(hr, NULL == hrgnNew, "ExtCreateRegion");
  1168. if (NULL != hrgnNew)
  1169. {
  1170. // if we already have a region from a previous pass,
  1171. // combine the new region with the old region
  1172. if (*phRgn)
  1173. {
  1174. ::CombineRgn(*phRgn, *phRgn, hrgnNew, RGN_OR);
  1175. ::DeleteObject(hrgnNew);
  1176. }
  1177. else
  1178. {
  1179. *phRgn = hrgnNew;
  1180. }
  1181. }
  1182. // does the user want the a region inverted based on the transparent color
  1183. if (SUCCEEDED(hr) && true == fInvert)
  1184. {
  1185. HRGN hRgnInverted = NULL;
  1186. RECT rc = { 0, 0, RECTWIDTH(pRect), RECTHEIGHT(pRect) };
  1187. hr = XORRegion( &hRgnInverted, *phRgn, rc);
  1188. //DPF_HR( A, hr, "XORRegion" );
  1189. if (SUCCEEDED(hr))
  1190. {
  1191. ::DeleteObject(*phRgn);
  1192. *phRgn = hRgnInverted;
  1193. }
  1194. }
  1195. return hr;
  1196. }
  1197. #pragma optimize( "", on )
  1198. //----------------------------------------------------------------------------
  1199. // CWMPBitmap::XORRegion
  1200. //
  1201. // Purpose:
  1202. // This parivate method will invert a given region.
  1203. // Parameters:
  1204. // phRgn - pointer to the return of the inverted region
  1205. // hRgn - the region to invert
  1206. // rc - max outside dimensions of the inverted region
  1207. // Returns:
  1208. // HRESULT
  1209. //
  1210. //----------------------------------------------------------------------------
  1211. HRESULT CBitmap::XORRegion(HRGN *phRgn, HRGN hRgn, const RECT &rc) const
  1212. {
  1213. //DASSERTMSG(NULL != phRgn, "CWMPBitmap::XORRegion(), 'phRgn' parameteris invalid");
  1214. //DASSERTMSG(NULL != hRgn, "CWMPBitmap::XORRegion(), 'hRgn' parameter is inavlid");
  1215. //DASSERTMSG(OBJ_REGION == ::GetObjectType(hRgn), "CWMPBitmap::XORRegion(), 'hRgn' parameter is inavlid");
  1216. HRESULT hr = S_OK;
  1217. // create the region based on the destination rect
  1218. HRGN hRgnTemp = ::CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);
  1219. //HRWIN32ERR(hr, NULL == hRgnTemp, "CreateRectRgn");
  1220. if (SUCCEEDED(hr))
  1221. {
  1222. // create a region to invert into
  1223. HRGN hRgnResult = ::CreateRectRgn(0, 0, 0, 0);
  1224. //HRWIN32ERR(hr, NULL == hRgnResult, "CreateRectRgn");
  1225. if (SUCCEEDED(hr))
  1226. {
  1227. // invert the passed region into hRgnResult
  1228. int nResult = ::CombineRgn(hRgnResult, hRgn, hRgnTemp, RGN_XOR);
  1229. //HRWIN32ERR(hr, ERROR == nResult, "CreateRectRgn");
  1230. if (SUCCEEDED(hr))
  1231. {
  1232. *phRgn = hRgnResult; // success, return the inverted region
  1233. }
  1234. else
  1235. {
  1236. ::DeleteObject(hRgnResult);
  1237. }
  1238. }
  1239. ::DeleteObject(hRgnTemp);
  1240. }
  1241. return hr;
  1242. }
  1243. //////////////////////////////////////////////////////////////////////////
  1244. //// Clipboard support
  1245. //---------------------------------------------------------------------
  1246. //
  1247. // Function: CopyHandle (from SDK DibView sample clipbrd.c)
  1248. //
  1249. // Purpose: Makes a copy of the given global memory block. Returns
  1250. // a handle to the new memory block (NULL on error).
  1251. //
  1252. // Routine stolen verbatim out of ShowDIB.
  1253. //
  1254. // Parms: h == Handle to global memory to duplicate.
  1255. //
  1256. // Returns: Handle to new global memory block.
  1257. //
  1258. //---------------------------------------------------------------------
  1259. HGLOBAL WINAPI CopyHandle (HGLOBAL h)
  1260. {
  1261. if (h == NULL)
  1262. return NULL;
  1263. DWORD dwLen = ::GlobalSize((HGLOBAL) h);
  1264. HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);
  1265. if (hCopy != NULL)
  1266. {
  1267. void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
  1268. void* lp = ::GlobalLock((HGLOBAL) h);
  1269. memcpy(lpCopy, lp, dwLen);
  1270. ::GlobalUnlock(hCopy);
  1271. ::GlobalUnlock(h);
  1272. }
  1273. return hCopy;
  1274. }
  1275. BYTE RGBtoL(BYTE R, BYTE G, BYTE B) {
  1276. /* calculate lightness */
  1277. BYTE cMax = max( max(R,G), B);
  1278. BYTE cMin = min( min(R,G), B);
  1279. BYTE L = (BYTE) (( cMax + cMin + 1 )/2);
  1280. return L;
  1281. }