新建 文本文档.txt
Upload User: hongxinly
Upload Date: 2022-06-13
Package Size: 2588k
Code Size: 15k
Category:

Special Effects

Development Platform:

Visual C++

  1. HBITMAP RotateBitmapNT(HBITMAP hBitmap, double fDegrees, COLORREF clrBack)
  2. {
  3. // Create a memory DC compatible with the display
  4. CDC sourceDC, destDC;
  5. sourceDC.CreateCompatibleDC( NULL );
  6. destDC.CreateCompatibleDC( NULL );
  7. // Get logical coordinates
  8. BITMAP bm;
  9. ::GetObject( hBitmap, sizeof( bm ), &bm );
  10. // Convert angle degree to radians 
  11. #define PI 3.1415926
  12. double radians = (fDegrees/90.0)*(PI/2);
  13. // Compute the cosine and sine only once
  14. float cosine = (float)cos(radians);
  15. float sine = (float)sin(radians);
  16. // Compute dimensions of the resulting bitmap
  17. // First get the coordinates of the 3 corners other than origin
  18. int x1 = (int)(bm.bmHeight * sine);
  19. int y1 = (int)(bm.bmHeight * cosine);
  20. int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight * sine);
  21. int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth * sine);
  22. int x3 = (int)(bm.bmWidth * cosine);
  23. int y3 = (int)(-bm.bmWidth * sine);
  24. int minx = min(0,min(x1, min(x2,x3)));
  25. int miny = min(0,min(y1, min(y2,y3)));
  26. int maxx = max(0,max(x1, max(x2,x3)));
  27. int maxy = max(0,max(y1, max(y2,y3)));
  28. int w = maxx - minx;
  29. int h = maxy - miny;
  30. // Create a bitmap to hold the result
  31. HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
  32. HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
  33. HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
  34. // Draw the background color before we change mapping mode
  35. HBRUSH hbrBack = CreateSolidBrush( clrBack );
  36. HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
  37. destDC.PatBlt( 0, 0, w, h, PATCOPY );
  38. ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
  39. // We will use world transform to rotate the bitmap
  40. SetGraphicsMode(destDC.m_hDC, GM_ADVANCED);
  41. XFORM xform;
  42. xform.eM11 = cosine;
  43. xform.eM12 = -sine;
  44. xform.eM21 = sine;
  45. xform.eM22 = cosine;
  46. xform.eDx = (float)-minx;
  47. xform.eDy = (float)-miny;
  48. SetWorldTransform( destDC.m_hDC, &xform );
  49. // Now do the actual rotating - a pixel at a time
  50. destDC.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &sourceDC, 0, 0, SRCCOPY );
  51. // Restore DCs
  52. ::SelectObject( sourceDC.m_hDC, hbmOldSource );
  53. ::SelectObject( destDC.m_hDC, hbmOldDest );
  54. return hbmResult;
  55. }
  56. // RotateBitmap - Create a new bitmap with rotated image
  57. // Returns - Returns new bitmap with rotated image
  58. // hBitmap - Bitmap to rotate
  59. // fDegrees - Angle of rotation in degree
  60. // clrBack - Color of pixels in the resulting bitmap that do
  61. //   not get covered by source pixels
  62. // Note - If the bitmap uses colors not in the system palette 
  63. //   then the result is unexpected. You can fix this by
  64. //   adding an argument for the logical palette.
  65. HBITMAP RotateBitmap(HBITMAP hBitmap, double fDegrees, COLORREF clrBack)
  66. {
  67. // Create a memory DC compatible with the display
  68. CDC sourceDC, destDC;
  69. sourceDC.CreateCompatibleDC( NULL );
  70. destDC.CreateCompatibleDC( NULL );
  71. // Get logical coordinates
  72. BITMAP bm;
  73. ::GetObject( hBitmap, sizeof( bm ), &bm );
  74. // Convert angle degree to radians 
  75. #define PI 3.1415926
  76. double radians = (fDegrees/90.0)*(PI/2);
  77. // Compute the cosine and sine only once
  78. float cosine = (float)cos(radians);
  79. float sine = (float)sin(radians);
  80. // Compute dimensions of the resulting bitmap
  81. // First get the coordinates of the 3 corners other than origin
  82. int x1 = (int)(-bm.bmHeight * sine);
  83. int y1 = (int)(bm.bmHeight * cosine);
  84. int x2 = (int)(bm.bmWidth * cosine - bm.bmHeight * sine);
  85. int y2 = (int)(bm.bmHeight * cosine + bm.bmWidth * sine);
  86. int x3 = (int)(bm.bmWidth * cosine);
  87. int y3 = (int)(bm.bmWidth * sine);
  88. int minx = min(0,min(x1, min(x2,x3)));
  89. int miny = min(0,min(y1, min(y2,y3)));
  90. int maxx = max(x1, max(x2,x3));
  91. int maxy = max(y1, max(y2,y3));
  92. int w = maxx - minx;
  93. int h = maxy - miny;
  94. // Create a bitmap to hold the result
  95. HBITMAP hbmResult = ::CreateCompatibleBitmap(CClientDC(NULL), w, h);
  96. HBITMAP hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );
  97. HBITMAP hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );
  98. // Draw the background color before we change mapping mode
  99. HBRUSH hbrBack = CreateSolidBrush( clrBack );
  100. HBRUSH hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );
  101. destDC.PatBlt( 0, 0, w, h, PATCOPY );
  102. ::DeleteObject( ::SelectObject( destDC.m_hDC, hbrOld ) );
  103. // Set mapping mode so that +ve y axis is upwords
  104. sourceDC.SetMapMode(MM_ISOTROPIC);
  105. sourceDC.SetWindowExt(1,1);
  106. sourceDC.SetViewportExt(1,-1);
  107. sourceDC.SetViewportOrg(0, bm.bmHeight-1);
  108. destDC.SetMapMode(MM_ISOTROPIC);
  109. destDC.SetWindowExt(1,1);
  110. destDC.SetViewportExt(1,-1);
  111. destDC.SetWindowOrg(minx, maxy);
  112. // Now do the actual rotating - a pixel at a time
  113. // Computing the destination point for each source point
  114. // will leave a few pixels that do not get covered
  115. // So we use a reverse transform - e.i. compute the source point
  116. // for each destination point
  117. for( int y = miny; y < maxy; y++ )
  118. {
  119. for( int x = minx; x < maxx; x++ )
  120. {
  121. int sourcex = (int)(x*cosine + y*sine);
  122. int sourcey = (int)(y*cosine - x*sine);
  123. if( sourcex >= 0 && sourcex < bm.bmWidth && sourcey >= 0 
  124. && sourcey < bm.bmHeight )
  125. destDC.SetPixel(x,y,sourceDC.GetPixel(sourcex,sourcey));
  126. }
  127. }
  128. // Restore DCs
  129. ::SelectObject( sourceDC.m_hDC, hbmOldSource );
  130. ::SelectObject( destDC.m_hDC, hbmOldDest );
  131. return hbmResult;
  132. }
  133. // RotateDIB - Create a new bitmap with rotated image
  134. // Returns - Returns new bitmap with rotated image
  135. // hDIB - Device-independent bitmap to rotate
  136. // fDegrees - Angle of rotation in degree
  137. // clrBack - Color of pixels in the resulting bitmap that do
  138. //   not get covered by source pixels
  139. HDIB RotateDIB(HDIB hDIB, double fDegrees, COLORREF clrBack)
  140. {
  141. WaitCursorBegin();
  142. // Get source bitmap info
  143. LPBITMAPINFO lpBmInfo = (LPBITMAPINFO)GlobalLock(hDIB);
  144. int bpp = lpBmInfo->bmiHeader.biBitCount; // Bits per pixel
  145. int nColors = lpBmInfo->bmiHeader.biClrUsed ? lpBmInfo->bmiHeader.biClrUsed : 
  146. 1 << bpp;
  147. int nWidth = lpBmInfo->bmiHeader.biWidth;
  148. int nHeight = lpBmInfo->bmiHeader.biHeight;
  149. int nRowBytes = ((((nWidth * bpp) + 31) & ~31) / 8);
  150. // Make sure height is positive and biCompression is BI_RGB or BI_BITFIELDS
  151. DWORD compression = lpBmInfo->bmiHeader.biCompression;
  152. if( nHeight < 0 || (compression!=BI_RGB))
  153. {
  154. GlobalUnlock(hDIB);
  155. WaitCursorEnd();
  156. return NULL;
  157. }
  158. LPBYTE lpDIBBits = FindDIBBits((LPBYTE)lpBmInfo);
  159.     
  160. // Convert angle degree to radians 
  161. #define PI 3.1415926
  162. double radians = (fDegrees/90.0)*(PI/2);
  163. // Compute the cosine and sine only once
  164. float cosine = (float)cos(radians);
  165. float sine = (float)sin(radians);
  166. // Compute dimensions of the resulting bitmap
  167. // First get the coordinates of the 3 corners other than origin
  168. int x1 = (int)(-nHeight * sine);
  169. int y1 = (int)(nHeight * cosine);
  170. int x2 = (int)(nWidth * cosine - nHeight * sine);
  171. int y2 = (int)(nHeight * cosine + nWidth * sine);
  172. int x3 = (int)(nWidth * cosine);
  173. int y3 = (int)(nWidth * sine);
  174. int minx = min(0,min(x1, min(x2,x3)));
  175. int miny = min(0,min(y1, min(y2,y3)));
  176. int maxx = max(x1, max(x2,x3));
  177. int maxy = max(y1, max(y2,y3));
  178. int w = maxx - minx;
  179. int h = maxy - miny;
  180. // Create a DIB to hold the result
  181. int nResultRowBytes = ((((w * bpp) + 31) & ~31) / 8);
  182. long len = nResultRowBytes * h;
  183. int nHeaderSize = ((LPBYTE)lpDIBBits-(LPBYTE)lpBmInfo) ;
  184. HANDLE hDIBResult = GlobalAlloc(GHND,len+nHeaderSize);
  185. // Initialize the header information
  186. LPBITMAPINFO lpBmInfoResult = (LPBITMAPINFO)GlobalLock(hDIBResult);
  187. memcpy( (void*)lpBmInfoResult, (void*)lpBmInfo, nHeaderSize);
  188. lpBmInfoResult->bmiHeader.biWidth = w;
  189. lpBmInfoResult->bmiHeader.biHeight = h;
  190. lpBmInfoResult->bmiHeader.biSizeImage = len;
  191. LPBYTE lpDIBBitsResult = FindDIBBits((LPBYTE)lpBmInfoResult);
  192. // Get the back color value (index)
  193. ZeroMemory( lpDIBBitsResult, len );
  194. DWORD dwBackColor;
  195. switch(bpp)
  196. {
  197. case 1: //Monochrome
  198. if( clrBack == RGB(255,255,255) )
  199. memset( lpDIBBitsResult, 0xff, len );
  200. break;
  201. case 4:
  202. case 8: //Search the color table
  203. int i;
  204. for(i = 0; i < nColors; i++ )
  205. {
  206. if( lpBmInfo->bmiColors[i].rgbBlue ==  GetBValue(clrBack)
  207. && lpBmInfo->bmiColors[i].rgbGreen ==  GetGValue(clrBack)
  208. && lpBmInfo->bmiColors[i].rgbRed ==  GetRValue(clrBack) )
  209. {
  210. if(bpp==4) i = i | i<<4;
  211. memset( lpDIBBitsResult, i, len );
  212. break;
  213. }
  214. }
  215. // If not match found the color remains black
  216. break;
  217. case 16:
  218. // Windows95 supports 5 bits each for all colors or 5 bits for red & blue
  219. // and 6 bits for green - Check the color mask for RGB555 or RGB565
  220. if( *((DWORD*)lpBmInfo->bmiColors) == 0x7c00 )
  221. {
  222. // Bitmap is RGB555
  223. dwBackColor = ((GetRValue(clrBack)>>3) << 10) + 
  224. ((GetRValue(clrBack)>>3) << 5) +
  225. (GetBValue(clrBack)>>3) ;
  226. }
  227. else
  228. {
  229. // Bitmap is RGB565
  230. dwBackColor = ((GetRValue(clrBack)>>3) << 11) + 
  231. ((GetRValue(clrBack)>>2) << 5) +
  232. (GetBValue(clrBack)>>3) ;
  233. }
  234. break;
  235. case 24:
  236. case 32:
  237. dwBackColor = (((DWORD)GetRValue(clrBack)) << 16) | 
  238. (((DWORD)GetGValue(clrBack)) << 8) |
  239. (((DWORD)GetBValue(clrBack)));
  240. break;
  241. }
  242. // Now do the actual rotating - a pixel at a time
  243. // Computing the destination point for each source point
  244. // will leave a few pixels that do not get covered
  245. // So we use a reverse transform - e.i. compute the source point
  246. // for each destination point
  247. for( int y = 0; y < h; y++ )
  248. {
  249. for( int x = 0; x < w; x++ )
  250. {
  251. int sourcex = (int)((x+minx)*cosine + (y+miny)*sine);
  252. int sourcey = (int)((y+miny)*cosine - (x+minx)*sine);
  253. if( sourcex >= 0 && sourcex < nWidth && sourcey >= 0 
  254. && sourcey < nHeight )
  255. {
  256. // Set the destination pixel
  257. switch(bpp)
  258. {
  259. BYTE mask;
  260. case 1: //Monochrome
  261. mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey + 
  262. sourcex/8) & (0x80 >> sourcex%8);
  263. //Adjust mask for destination bitmap
  264. mask = mask ? (0x80 >> x%8) : 0;
  265. *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) + 
  266. (x/8)) &= ~(0x80 >> x%8);
  267. *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) + 
  268. (x/8)) |= mask;
  269. break;
  270. case 4:
  271. mask = *((LPBYTE)lpDIBBits + nRowBytes*sourcey + 
  272. sourcex/2) & ((sourcex&1) ? 0x0f : 0xf0);
  273. //Adjust mask for destination bitmap
  274. if( (sourcex&1) != (x&1) )
  275. mask = (mask&0xf0) ? (mask>>4) : (mask<<4);
  276. *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) + 
  277. (x/2)) &= ~((x&1) ? 0x0f : 0xf0);
  278. *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) + 
  279. (x/2)) |= mask;
  280. break;
  281. case 8:
  282. BYTE pixel ;
  283. pixel = *((LPBYTE)lpDIBBits + nRowBytes*sourcey + 
  284. sourcex);
  285. *((LPBYTE)lpDIBBitsResult + nResultRowBytes*(y) + 
  286. (x)) = pixel;
  287. break;
  288. case 16:
  289. DWORD dwPixel;
  290. dwPixel = *((LPWORD)((LPBYTE)lpDIBBits + 
  291. nRowBytes*sourcey + sourcex*2));
  292. *((LPWORD)((LPBYTE)lpDIBBitsResult + 
  293. nResultRowBytes*y + x*2)) = (WORD)dwPixel;
  294. break;
  295. case 24:
  296. dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits + 
  297. nRowBytes*sourcey + sourcex*3)) & 0xffffff;
  298. *((LPDWORD)((LPBYTE)lpDIBBitsResult + 
  299. nResultRowBytes*y + x*3)) |= dwPixel;
  300. break;
  301. case 32:
  302. dwPixel = *((LPDWORD)((LPBYTE)lpDIBBits + 
  303. nRowBytes*sourcey + sourcex*4));
  304. *((LPDWORD)((LPBYTE)lpDIBBitsResult + 
  305. nResultRowBytes*y + x*4)) = dwPixel;
  306. }
  307. }
  308. else 
  309. {
  310. // Draw the background color. The background color
  311. // has already been drawn for 8 bits per pixel and less
  312. switch(bpp)
  313. {
  314. case 16:
  315. *((LPWORD)((LPBYTE)lpDIBBitsResult + 
  316. nResultRowBytes*y + x*2)) = 
  317. (WORD)dwBackColor;
  318. break;
  319. case 24:
  320. *((LPDWORD)((LPBYTE)lpDIBBitsResult + 
  321. nResultRowBytes*y + x*3)) |= dwBackColor;
  322. break;
  323. case 32:
  324. *((LPDWORD)((LPBYTE)lpDIBBitsResult + 
  325. nResultRowBytes*y + x*4)) = dwBackColor;
  326. break;
  327. }
  328. }
  329. }
  330. }
  331. GlobalUnlock(hDIB);
  332. GlobalUnlock(hDIBResult);
  333. WaitCursorEnd();
  334. return hDIBResult;
  335. }
  336. /************************************************************************* 
  337.  * 
  338.  * RotateDIB() 
  339.  * 
  340.  * Parameters: 
  341.  * 
  342.  * HDIB hDIB  - handle of DIB to rotate
  343.  * 
  344.  * Return Value: 
  345.  * 
  346.  * HDIB             - Handle to new DIB 
  347.  * 
  348.  * Description: 
  349.  * 
  350.  * This function rotate DIB 90 degree counter clockwise, and return
  351.  * the rotated DIB in a new DIB handle, let the source DIB unchanged
  352.  * 
  353.  ************************************************************************/ 
  354. HDIB RotateDIB(HDIB hDib)
  355. {
  356. WaitCursorBegin();
  357. // old DIB
  358. LPBYTE lpDIBSrc = (LPBYTE)GlobalLock(hDib);
  359. DWORD lSrcWidth = DIBWidth(lpDIBSrc);
  360. DWORD lSrcHeight = DIBHeight(lpDIBSrc);
  361. WORD wBitCount = ((LPBITMAPINFOHEADER)lpDIBSrc)->biBitCount;
  362. // bits position
  363.     LPBYTE lpOldBits = FindDIBBits(lpDIBSrc);
  364. // get bytes/pixel, bytes/row of new DIB
  365. double fColorBytes = (double)((double)wBitCount/8.0);
  366. DWORD lSrcRowBytes = WIDTHBYTES(lSrcWidth*((DWORD)wBitCount));
  367. DWORD lDestRowBytes = WIDTHBYTES(lSrcHeight*((DWORD)wBitCount));
  368. // adjust new DIB size
  369. DWORD dwDataLength = GlobalSize(hDib);
  370. dwDataLength += lDestRowBytes*(lSrcWidth-1)+(DWORD)((lSrcHeight-1)*fColorBytes) - 
  371.   lSrcRowBytes*(lSrcHeight-1)+(DWORD)((lSrcWidth-1)*fColorBytes);
  372. HDIB hNewDib = GlobalAlloc(GHND, dwDataLength);
  373. if (! hNewDib)
  374. {
  375. WaitCursorEnd();
  376. return NULL;
  377. }
  378. // new DIB buffer
  379. LPBYTE lpDIB = (LPBYTE)GlobalLock(hNewDib);
  380. // copy LPBITMAPINFO from old to new
  381. memcpy(lpDIB, lpDIBSrc, sizeof(BITMAPINFOHEADER)+PaletteSize(lpDIBSrc));
  382. // swap width and height
  383. ((LPBITMAPINFOHEADER)lpDIB)->biHeight = lSrcWidth;
  384. ((LPBITMAPINFOHEADER)lpDIB)->biWidth = lSrcHeight;
  385. // new bits position
  386. LPBYTE lpData = FindDIBBits(lpDIB);
  387. // trandform bits
  388. DWORD i, j;
  389. switch (wBitCount)
  390. {
  391. case 1:
  392. for (i=0; i<lSrcHeight; ++i)
  393. {
  394. for (j=0; j<lSrcWidth; ++j)
  395. {
  396. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)/8)) &= ~(1<<(7-((lSrcHeight-i-1)%8)));
  397. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)/8)) |= 
  398. ((*(lpOldBits+(lSrcRowBytes*i+j/8))<<(j%8))>>7)<<(7-((lSrcHeight-i-1)%8));
  399. }
  400. }
  401. break;
  402. case 4:
  403. for (i=0; i<lSrcHeight; ++i)
  404. {
  405. for (j=0; j<lSrcWidth; ++j)
  406. {
  407. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)/2)) &= ((lSrcHeight-i-1)%2) ? 0xf0 : 0x0f;
  408. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)/2)) |= 
  409. ((*(lpOldBits+(lSrcRowBytes*i+j/2))<<(j%2 ? 4 : 0))>>4)<<(((lSrcHeight-i-1)%2) ? 0 : 4);
  410. }
  411. }
  412. break;
  413. case 8:
  414. for (i=0; i<lSrcHeight; ++i)
  415. {
  416. for (j=0; j<lSrcWidth; ++j)
  417. {
  418. *(lpData+(lDestRowBytes*j+lSrcHeight-i-1))
  419. = *(lpOldBits+(lSrcRowBytes*i+j));
  420. }
  421. }
  422. break;
  423. case 24:
  424. for (i=0; i<lSrcHeight; ++i)
  425. {
  426. for (j=0; j<lSrcWidth; j++)
  427. {
  428. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)*3))
  429. = *(lpOldBits+(lSrcRowBytes*i+j*3));
  430. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)*3)+1)
  431. = *(lpOldBits+(lSrcRowBytes*i+j*3)+1);
  432. *(lpData+(lDestRowBytes*j+(lSrcHeight-i-1)*3)+2)
  433. = *(lpOldBits+(lSrcRowBytes*i+j*3)+2);
  434. }
  435. }
  436. break;
  437. }
  438. // cleanup
  439. GlobalUnlock(hDib);
  440. GlobalUnlock(hNewDib);
  441. WaitCursorEnd();
  442. return hNewDib;
  443. }