现在的位置: 首页 > 综合 > 正文

【转载】Rotate a bitmap image

2012年11月23日 ⁄ 综合 ⁄ 共 4602字 ⁄ 字号 评论关闭

If you are targeting multiple platforms, then your task becomes tougher.
You could either rotate each pixel in the source bitmap one at a time or
directly manipulate the DIB bits to get the rotated bitmap. The first method is
very slow to the point of being useless and the second is more complex but is
fast enough. We cover both these methods below. Note that all the functions
shown below create a new bitmap ( in one case it creates a DIB ). If instead of
a new bitmap you want the rotated image to be drawn directly, you will need to
modify the functions. Function 1: GetRotatedBitmapNT() This function is
specific to NT and will not work on Windows95. It's the simplest and probably
the fastest of the three functions listed in this topic. The other two
functions share some of the same initial code.

All the three functions expect the angle of rotation to be in radians. If
you have degrees to begin with you can convert from degrees to radians by using
the formula

radian = (2*pi *degree)/360

Here are the steps that we take to rotate the bitmap.

1.   
Create a couple of device contexts
compatible with the display. One of them will be used to hold the source bitmap
and the other will hold the destination bitmap (for the rotated image).

2.   
Precompute the cosine and the sine of the
angle. This will help save a few microseconds in subsequent computations.

3.   
Compute the bounding rectangle of the
rotated image. We use the formula
 
newx = x.cos(angle) + y.sin(angle)
 

newy = y.cos(angle) - x.sin(angle)
 

We assume one of the corners (0,0) to be the center of rotation and therefore
need to calculate the new co-ordinates of the other three corners. Based on
this we can determine the widht and height of the new bitmap.

4.   
Since the rotated image will not occupy
the entire area of the new bitmap, we fill the destination bitmap with the
background color specified through the function argument.

5.   
Since we will use NTs support for linear
transformation we set the graphic mode of the destination DC to support this.

6.   
We set up the XFORM struction and call
SetWorldTransform() to activate the transformation. The SetWorldTransform()
function sets up the stage for BitBlt(), which is when the transformation takes
place. The algorithm used for the linear transformation is
 
newx = x * eM11 + y * eM21 + eDx
 

newy = x * eM12 + y * eM22 + eDy
 

For rotation eM11 and eM22 should be the cosine of the rotation angle, eM12
should be the sine of the rotation angle and eM21 should be -eM12. In the DC we
are using, since the +ve y direction is downwards, we reverse the signs of eM12
and eM21. We also set the translation components (eDx & eDy) so that
rotated image fits inside the new bitmap without part of it getting clipped.

7.   
We finally call BitBlt() to do the actual
rotation. This call in itself looks like it will simply copy the image.
However, the previous call to SetWorldTransform() causes the image to be
rotated.

// GetRotatedBitmapNT     - Create a new bitmap with rotated image

// Returns                - Returns new bitmap with rotated image

// hBitmap                - Bitmap to rotate

// radians                - Angle of rotation in radians

// clrBack                - Color of pixels in the resulting bitmap that do

//                          not get covered by source pixels

HBITMAP GetRotatedBitmapNT( HBITMAP
hBitmap,
float
radians, COLORREF clrBack )

{

         //
Create a memory DC compatible with the display

         CDC
sourceDC, destDC;

         sourceDC.CreateCompatibleDC(
NULL );

         destDC.CreateCompatibleDC(
NULL );

 

         //
Get logical coordinates

         BITMAP
bm;

         ::GetObject(
hBitmap,
sizeof( bm
), &bm );

 

         float cosine = (float)cos(radians);

         float sine = (float)sin(radians);

 

         //
Compute dimensions of the resulting bitmap

         //
First get the coordinates of the 3 corners other than origin

         int x1 = (int)(bm.bmHeight * sine);

         int y1 = (int)(bm.bmHeight * cosine);

         int x2 = (int)(bm.bmWidth * cosine + bm.bmHeight *
sine);

         int y2 = (int)(bm.bmHeight * cosine - bm.bmWidth *
sine);

         int x3 = (int)(bm.bmWidth * cosine);

         int y3 = (int)(-bm.bmWidth * sine);

 

         int minx = min(0,min(x1, min(x2,x3)));

         int miny = min(0,min(y1, min(y2,y3)));

         int maxx = max(0,max(x1, max(x2,x3)));

         int maxy = max(0,max(y1, max(y2,y3)));

 

         int w = maxx - minx;

         int h = maxy - miny;

 

         //
Create a bitmap to hold the result

         HBITMAP
hbmResult = ::CreateCompatibleBitmap(CClientDC(
NULL), w, h);

 

         HBITMAP
hbmOldSource = (HBITMAP)::SelectObject( sourceDC.m_hDC, hBitmap );

         HBITMAP
hbmOldDest = (HBITMAP)::SelectObject( destDC.m_hDC, hbmResult );

 

         //
Draw the background color before we change mapping mode

         HBRUSH
hbrBack = CreateSolidBrush( clrBack );

         HBRUSH
hbrOld = (HBRUSH)::SelectObject( destDC.m_hDC, hbrBack );

         destDC.PatBlt(
0, 0, w, h, PATCOPY );

         ::DeleteObject(
::SelectObject( destDC.m_hDC, hbrOld ) );

 

         //
We will use world transform to rotate the bitmap

         SetGraphicsMode(destDC.m_hDC,
GM_ADVANCED);

         XFORM
xform;

         xform.eM11
= cosine;

         xform.eM12
= -sine;

         xform.eM21
= sine;

         xform.eM22
= cosine;

         xform.eDx
= (
float)-minx;

         xform.eDy
= (
float)-miny;

 

         SetWorldTransform(
destDC.m_hDC, &xform );

 

抱歉!评论已关闭.