MyBitmap.cpp
上传用户:vipseo
上传日期:2010-02-15
资源大小:137k
文件大小:13k
源码类别:

组合框控件

开发平台:

Visual C++

  1. // MyBitmap.cpp: implementation of the CMyBitmap class.
  2. //
  3. // History:
  4. // 2002.11.23
  5. // copy from kdphoto projects
  6. //
  7. //
  8. //
  9. //
  10. //////////////////////////////////////////////////////////////////////
  11. #include "stdafx.h"
  12. #include "MyBitmap.h"
  13. #ifdef _DEBUG
  14. #undef THIS_FILE
  15. static char THIS_FILE[]=__FILE__;
  16. #define new DEBUG_NEW
  17. #endif
  18. // TransparentBlt - Copies a bitmap transparently onto the destination DC
  19. // hdcDest - Handle to destination device context 
  20. // nXDest - x-coordinate of destination rectangle's upper-left corner 
  21. // nYDest - y-coordinate of destination rectangle's upper-left corner 
  22. // nWidth - Width of destination rectangle 
  23. // nHeight - height of destination rectangle 
  24. // hBitmap - Handle of the source bitmap
  25. // nXSrc - x-coordinate of source rectangle's upper-left corner 
  26. // nYSrc - y-coordinate of source rectangle's upper-left corner 
  27. // colorTransparent - The transparent color
  28. // hPal - Logical palette to be used with bitmap. Can be NULL
  29. void MyTransparentBlt( HDC hdcDest, int nXDest, int nYDest, int nWidth, 
  30. int nHeight, HBITMAP hBitmap, int nXSrc, int nYSrc,
  31. COLORREF colorTransparent, HPALETTE hPal )
  32. {
  33. CDC dc, memDC, maskDC, tempDC;
  34. dc.Attach( hdcDest );
  35. maskDC.CreateCompatibleDC(&dc);
  36. CBitmap maskBitmap;
  37. //add these to store return of SelectObject() calls
  38. CBitmap* pOldMemBmp = NULL;
  39. CBitmap* pOldMaskBmp = NULL;
  40. HBITMAP hOldTempBmp = NULL;
  41. memDC.CreateCompatibleDC(&dc);
  42. tempDC.CreateCompatibleDC(&dc);
  43. CBitmap bmpImage;
  44. bmpImage.CreateCompatibleBitmap( &dc, nWidth, nHeight );
  45. pOldMemBmp = memDC.SelectObject( &bmpImage );
  46. // Select and realize the palette
  47. if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && hPal )
  48. {
  49. ::SelectPalette( dc, hPal, FALSE );
  50. dc.RealizePalette();
  51. ::SelectPalette( memDC, hPal, FALSE );
  52. }
  53. hOldTempBmp = (HBITMAP) ::SelectObject( tempDC.m_hDC, hBitmap );
  54. memDC.BitBlt( 0,0,nWidth, nHeight, &tempDC, nXSrc, nYSrc, SRCCOPY );
  55. // Create monochrome bitmap for the mask
  56. maskBitmap.CreateBitmap( nWidth, nHeight, 1, 1, NULL );
  57. pOldMaskBmp = maskDC.SelectObject( &maskBitmap );
  58. memDC.SetBkColor( colorTransparent );
  59. // Create the mask from the memory DC
  60. maskDC.BitBlt( 0, 0, nWidth, nHeight, &memDC, 
  61. 0, 0, SRCCOPY );
  62. // Set the background in memDC to black. Using SRCPAINT with black 
  63. // and any other color results in the other color, thus making 
  64. // black the transparent color
  65. memDC.SetBkColor(RGB(0,0,0));
  66. memDC.SetTextColor(RGB(255,255,255));
  67. memDC.BitBlt(0, 0, nWidth, nHeight, &maskDC, 0, 0, SRCAND);
  68. // Set the foreground to black. See comment above.
  69. dc.SetBkColor(RGB(255,255,255));
  70. dc.SetTextColor(RGB(0,0,0));
  71. dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &maskDC, 0, 0, SRCAND);
  72. // Combine the foreground with the background
  73. dc.BitBlt(nXDest, nYDest, nWidth, nHeight, &memDC, 
  74. 0, 0, SRCPAINT);
  75. if (hOldTempBmp)
  76. ::SelectObject( tempDC.m_hDC, hOldTempBmp);
  77. if (pOldMaskBmp)
  78. maskDC.SelectObject( pOldMaskBmp );
  79. if (pOldMemBmp)
  80. memDC.SelectObject( pOldMemBmp );
  81. dc.Detach();
  82. }
  83. //////////////////////////////////////////////////////////////////////
  84. // Construction/Destruction
  85. //////////////////////////////////////////////////////////////////////
  86. CMyBitmap::CMyBitmap()
  87. {
  88. }
  89. CMyBitmap::~CMyBitmap()
  90. {
  91. }
  92. BOOL CMyBitmap::StretchDraw(CDC *pDC, LPRECT r, LPRECT sr )
  93. {
  94. if ( !r ) return FALSE;
  95. CDC dc;
  96. dc.CreateCompatibleDC( pDC );
  97. CBitmap * bmp = dc.SelectObject( this );
  98. pDC->SetStretchBltMode(COLORONCOLOR);
  99. if ( !sr )
  100. pDC->StretchBlt( r->left, r->top, r->right, r->bottom, &dc, 0, 0, GetWidth(), GetHeight() ,
  101. SRCCOPY );
  102. else
  103. pDC->StretchBlt( r->left, r->top, r->right - r->left, r->bottom - r->top, &dc, sr->left, sr->top, 
  104. sr->right - sr->left, sr->bottom - sr->top,
  105. SRCCOPY );
  106. dc.SelectObject( bmp );
  107. return TRUE;
  108. }
  109. BOOL CMyBitmap::StretchDraw(CDC *pDC, LPRECT r)
  110. {
  111. CDC dc;
  112. dc.CreateCompatibleDC( pDC );
  113. CBitmap * bmp = dc.SelectObject( this );
  114. pDC->StretchBlt( r->left, r->top, r->right, r->bottom, &dc, 0, 0, GetWidth(), GetHeight() ,
  115. SRCCOPY );
  116. dc.SelectObject( bmp );
  117. return TRUE;
  118. }
  119. BOOL CMyBitmap::Draw( CDC *pDC, int x, int y, LPRECT sr, COLORREF colTrans, BOOL bTrans )
  120. {
  121. if ( !bTrans )
  122. Draw( pDC ,x, y, sr );
  123. else
  124. {
  125. MyTransparentBlt( pDC->GetSafeHdc(), x, y, sr->right - sr->left, sr->bottom - sr->top, 
  126. (HBITMAP)this->GetSafeHandle(), sr->left, sr->top, colTrans, NULL );
  127. }
  128. return TRUE;
  129. }
  130. //draw sub bmp to special point
  131. BOOL CMyBitmap::Draw( CDC *pDC, int x, int y, LPRECT sr )
  132. {
  133. CDC dc;
  134. dc.CreateCompatibleDC( pDC );
  135. CBitmap * bmp = dc.SelectObject( this );
  136. if ( sr != NULL)
  137. pDC->BitBlt( x, y, sr->right - sr->left, sr->bottom - sr->top, &dc, 
  138. sr->left, sr->top,  SRCCOPY );
  139. else
  140. pDC->BitBlt( x, y, Width(), Height(), &dc, 
  141. 0, 0,  SRCCOPY );
  142. dc.SelectObject( bmp );
  143. return TRUE;
  144. }
  145. BOOL CMyBitmap::Draw(CDC *pDC, LPRECT r)
  146. {
  147. CDC dc;
  148. dc.CreateCompatibleDC( pDC );
  149. CBitmap * bmp = dc.SelectObject( this );
  150. pDC->BitBlt( r->left, r->top, r->right - r->left, r->bottom - r->top, &dc, 0, 0 ,
  151.   SRCCOPY );
  152. dc.SelectObject( bmp );
  153. return TRUE;
  154. }
  155. ///HOWTO: Drawing Transparent Bitmaps
  156. //see: Microsoft Knowledge Base Article - Q79212
  157. BOOL CMyBitmap::DrawTransparent(CDC * pDC, int x, int y, COLORREF crColour)
  158. {
  159. MyTransparentBlt( pDC->GetSafeHdc(), x, y, GetWidth(), GetHeight(), (HBITMAP)this->GetSafeHandle(), 0, 0, crColour, NULL );
  160. /*
  161. COLORREF crOldBack = pDC->SetBkColor(0);
  162. COLORREF crOldText = pDC->SetTextColor(RGB(255,255,255));
  163. CDC dcImage, dcTrans;
  164. // Create two memory dcs for the image and the mask
  165. dcImage.CreateCompatibleDC(pDC);
  166. dcTrans.CreateCompatibleDC(pDC);
  167. // Select the image into the appropriate dc
  168. CBitmap* pOldBitmapImage = dcImage.SelectObject(this);
  169. // Create the mask bitmap
  170. CBitmap bitmapTrans;
  171. int nWidth = GetWidth();
  172. int nHeight = GetHeight();
  173. bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
  174. // Select the mask bitmap into the appropriate dc
  175. CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);
  176. // Build mask based on transparent colour
  177. dcImage.SetBkColor(crColour);
  178. dcTrans.BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCCOPY);
  179. // Do the work - True Mask method - cool if not actual display
  180. pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
  181. pDC->BitBlt(x, y, nWidth, nHeight, &dcTrans, 0, 0, SRCAND);
  182. pDC->BitBlt(x, y, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
  183. // Restore settings
  184. dcImage.SelectObject(pOldBitmapImage);
  185. dcTrans.SelectObject(pOldBitmapTrans);
  186. pDC->SetBkColor(crOldBack);
  187. pDC->SetTextColor(crOldText);
  188. */
  189. return TRUE;
  190. }
  191. HRGN CMyBitmap::CreateRgnFromFile( COLORREF color )
  192. {
  193. HBITMAP hBmp = (HBITMAP)this->GetSafeHandle();
  194. // get image properties
  195. BITMAP bmp = { 0 };
  196. ::GetObject( hBmp, sizeof(BITMAP), &bmp );
  197. // allocate memory for extended image information
  198. LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 8 ];
  199. memset( bi, 0, sizeof(BITMAPINFO) + 8 );
  200. bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  201. // set window size
  202. int m_dwWidth = bmp.bmWidth; // bitmap width
  203. int m_dwHeight = bmp.bmHeight; // bitmap height
  204. // create temporary dc
  205. HDC dc = CreateIC( "DISPLAY",NULL,NULL,NULL );
  206. // get extended information about image (length, compression, length of color table if exist, ...)
  207. DWORD res = GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS );
  208. // allocate memory for image data (colors)
  209. LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 4 ];
  210. // allocate memory for color table
  211. if ( bi->bmiHeader.biBitCount == 8 )
  212. {
  213. // actually color table should be appended to this header(BITMAPINFO),
  214. // so we have to reallocate and copy it
  215. LPBITMAPINFO old_bi = bi;
  216. // 255 - because there is one in BITMAPINFOHEADER
  217. bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ];
  218. memcpy( bi, old_bi, sizeof(BITMAPINFO) );
  219. // release old header
  220. delete old_bi;
  221. }
  222. // get bitmap info header
  223. BITMAPINFOHEADER& bih = bi->bmiHeader;
  224. // get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD))
  225. LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors;
  226. // fill bits buffer
  227. res = GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS );
  228. DeleteDC( dc );
  229. BITMAP bm;
  230. ::GetObject( hBmp, sizeof(BITMAP), &bm );
  231. // shift bits and byte per pixel (for comparing colors)
  232. LPBYTE pClr = (LPBYTE)&color;
  233. // swap red and blue components
  234. BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;
  235. // convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5)
  236. if ( bih.biBitCount == 16 )
  237. {
  238. // for 16 bit
  239. color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
  240. ((DWORD)(pClr[1] & 0xfc) << 3) |
  241. ((DWORD)(pClr[2] & 0xf8) << 8);
  242. // for 15 bit
  243. // color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
  244. // ((DWORD)(pClr[1] & 0xf8) << 2) |
  245. // ((DWORD)(pClr[2] & 0xf8) << 7);
  246. }
  247. const DWORD RGNDATAHEADER_SIZE = sizeof(RGNDATAHEADER);
  248. const DWORD ADD_RECTS_COUNT = 40; // number of rects to be appended
  249. // to region data buffer
  250. // BitPerPixel
  251. BYTE Bpp = bih.biBitCount >> 3; // bytes per pixel
  252. // bytes per line in pBits is DWORD aligned and bmp.bmWidthBytes is WORD aligned
  253. // so, both of them not
  254. DWORD m_dwAlignedWidthBytes = (bmp.bmWidthBytes & ~0x3) + (!!(bmp.bmWidthBytes & 0x3) << 2);
  255. // DIB image is flipped that's why we scan it from the last line
  256. LPBYTE pColor = pBits + (bih.biHeight - 1) * m_dwAlignedWidthBytes;
  257. DWORD dwLineBackLen = m_dwAlignedWidthBytes + bih.biWidth * Bpp; // offset of previous scan line
  258. // (after processing of current)
  259. DWORD dwRectsCount = bih.biHeight; // number of rects in allocated buffer
  260. INT i, j; // current position in mask image
  261. INT first = 0; // left position of current scan line
  262. // where mask was found
  263. bool wasfirst = false; // set when mask has been found in current scan line
  264. bool ismask; // set when current color is mask color
  265. // allocate memory for region data
  266. // region data here is set of regions that are rectangles with height 1 pixel (scan line)
  267. // that's why first allocation is <bm.biHeight> RECTs - number of scan lines in image
  268. RGNDATAHEADER* pRgnData = 
  269. (RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
  270. // get pointer to RECT table
  271. LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
  272. // zero region data header memory (header  part only)
  273. memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );
  274. // fill it by default
  275. pRgnData->dwSize = RGNDATAHEADER_SIZE;
  276. pRgnData->iType = RDH_RECTANGLES;
  277. for ( i = 0; i < bih.biHeight; i++ )
  278. {
  279. for ( j = 0; j < bih.biWidth; j++ )
  280. {
  281. // get color
  282. switch ( bih.biBitCount )
  283. {
  284. case 8:
  285. ismask = (clr_tbl[ *pColor ] != color);
  286. break;
  287. case 16:
  288. ismask = (*(LPWORD)pColor != (WORD)color);
  289. break;
  290. case 24:
  291. ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color);
  292. break;
  293. case 32:
  294. ismask = (*(LPDWORD)pColor != color);
  295. }
  296. // shift pointer to next color
  297. pColor += Bpp;
  298. // place part of scan line as RECT region if transparent color found after mask color or
  299. // mask color found at the end of mask image
  300. if ( wasfirst )
  301. {
  302. if ( !ismask )
  303. {
  304. // save current RECT
  305. pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 );
  306. // if buffer full reallocate it with more room
  307. if ( pRgnData->nCount >= dwRectsCount )
  308. {
  309. dwRectsCount += ADD_RECTS_COUNT;
  310. // allocate new buffer
  311. LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
  312. // copy current region data to it
  313. memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
  314. // delte old region data buffer
  315. delete pRgnData;
  316. // set pointer to new regiondata buffer to current
  317. pRgnData = (RGNDATAHEADER*)pRgnDataNew;
  318. // correct pointer to RECT table
  319. pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
  320. }
  321. wasfirst = false;
  322. }
  323. }
  324. else if ( ismask ) // set wasfirst when mask is found
  325. {
  326. first = j;
  327. wasfirst = true;
  328. }
  329. }
  330. if ( wasfirst && ismask )
  331. {
  332. // save current RECT
  333. pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 );
  334. // if buffer full reallocate it with more room
  335. if ( pRgnData->nCount >= dwRectsCount )
  336. {
  337. dwRectsCount += ADD_RECTS_COUNT;
  338. // allocate new buffer
  339. LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
  340. // copy current region data to it
  341. memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
  342. // delte old region data buffer
  343. delete pRgnData;
  344. // set pointer to new regiondata buffer to current
  345. pRgnData = (RGNDATAHEADER*)pRgnDataNew;
  346. // correct pointer to RECT table
  347. pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
  348. }
  349. wasfirst = false;
  350. }
  351. pColor -= dwLineBackLen;
  352. }
  353. // release image data
  354. delete pBits;
  355. delete bi;
  356. // create region
  357. HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
  358. // release region data
  359. delete pRgnData;
  360. return hRgn;
  361. }