DOCUMENT:Q186260 08-MAR-2002 [vbwin] TITLE :HOWTO: Rotate a Bitmap Image in 90-Degree Increments PRODUCT :Microsoft Visual Basic for Windows PROD/VER::5.0,6.0 OPER/SYS: KEYWORDS:kbBitmap kbVBp kbVBp500 kbVBp600 kbGrpDSVB kbDSupport ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - Microsoft Visual Basic Learning Edition for Windows, versions 5.0, 6.0 - Microsoft Visual Basic Professional Edition for Windows, versions 5.0, 6.0 - Microsoft Visual Basic Enterprise Edition for Windows, versions 5.0, 6.0 ------------------------------------------------------------------------------- SUMMARY ======= Bitmap rotation is a graphic effect that Visual Basic does not natively offer. This article shows how to rotate a given image in 90-degree increments. It allows you to rotate any image 0, 90, 180 or 270 degrees. With a little work, the code can be modified to rotate to any angle, but that is beyond the scope of this article. MORE INFORMATION ================ The following sample uses a function called RotateBitmap. Here is some information about this function: RotateBitmap(hBitmapDC As Long, _ lWidth As Long, _ lHeight As Long, _ lRadians As Long) hBitmapDC: Handle to a device context of the image to be rotated. Upon return, this variable will contain the device context of the rotated image. lWidth: Width of the incoming image. Upon return contains the width of the rotated image. lHeight: Height of the incoming image. Upon return, contains the height of the rotated image. lRadians: Angle to rotate the image (in Radians). The sample shows how to convert degrees into radians on the fly. Step-by-Step Example -------------------- 1. Create a new Standard EXE project in Visual Basic. Form1 is created by default. 2. Add a Standard Module (Module1) to the project. 3. Add the following controls to Form1: - Two PictureBox controls - One Timer control 4. For the two PictureBox controls, set their AutoRedraw properties to True. 5. Copy and paste the following code in the Form's code Window: Option Explicit Dim sFileName As String ' filename of the image being used Dim hBitmap As Long ' handle to the loaded bitmap Dim lBMDC As Long ' device context of the bitmap Dim sBitmapInfo As BITMAP ' information on the loaded image Dim Degrees As Long ' current rotation degree Private Sub Form_Load() ' set staring degrees Degrees = 0 ' set the bitmap that will be used in the sample sFileName = "filename.bmp" ' where filename.bmp is the bitmap ' being used ' load the bitmap into memory hBitmap = LoadImage(0, sFileName, IMAGE_BITMAP, 0, 0, _ LR_LOADFROMFILE Or LR_CREATEDIBSECTION) ' make sure the call succeeded If (hBitmap = 0) Then MsgBox "Error, Unable To Load Bitmap", vbOKOnly, _ "Bitmap Load Error" End End If ' create a device context to use when blitting the loaded bitmap lBMDC = CreateCompatibleDC(0) ' make sure our call succeeded If (lBMDC = 0) Then MsgBox "Error, Unable To Create Device Context", _ vbOKOnly, "Device Context Error" Exit Sub End If ' attach the bitmap to the device context just created Call SelectObject(lBMDC, hBitmap) ' get the information about this image Call GetObject(hBitmap, Len(sBitmapInfo), sBitmapInfo) ' blit the bitmap image onto the picturebox control ' on the form to show what is being worked with Call BitBlt(Picture1.hdc, 0, 0, sBitmapInfo.bmWidth, _ sBitmapInfo.bmHeight, lBMDC, 0, 0, SRCCOPY) Picture1.Refresh ' set the timer and turn it on Timer1.Interval = 500 Timer1.Enabled = True End Sub Private Sub Timer1_Timer() Dim hRotatedBitmapDC As Long ' returned DC to the new bitmap Dim lWidth As Long ' current/new width of the bitmaps Dim lHeight As Long ' current/new width of the bitmaps Dim lRadians As Long ' the degrees will be converted to ' - radians ' get the width/height of the original bitmap image lWidth = sBitmapInfo.bmWidth lHeight = sBitmapInfo.bmHeight ' convert the rotation degrees into radians for the ' rotate function lRadians = PI * Degrees / 180 ' set the input var to the current bitmaps DC hRotatedBitmapDC = Picture1.hdc ' rotate the bitmap to its new degree RotateBitmap hRotatedBitmapDC, lWidth, lHeight, lRadians ' clear the second picturebox to show the rotated image Set Picture2.Picture = LoadPicture ' blit the rotated image Call BitBlt(Picture2.hdc, 0, 0, lWidth, lHeight, _ hRotatedBitmapDC, 0, 0, SRCCOPY) Picture2.Refresh ' destroy the DC created for the rotated bitmap Call DeleteDC(hRotatedBitmapDC) ' increase the degree count, or reset if we have come full circle Degrees = Degrees + 90 If Degrees = 360 Then Degrees = 0 End If End Sub 6. In the Form_Load event in the above code, be sure to set the sFileName variable to a bitmap file on your system. 7. Add the following code to the Standard Module (Module1): Option Explicit ' refer to the MSDN for more detailed information regarding the ' constants used in this sample. Public Const IMAGE_BITMAP = &O0 ' used with LoadImage to load ' a bitmap Public Const LR_LOADFROMFILE = 16 ' used with LoadImage Public Const LR_CREATEDIBSECTION = 8192 ' used with LoadImage Public Const SRCCOPY = &HCC0020 ' (DWORD) dest = source Public Const PI = 3.14159 ' Refer to the MSDN for more detailed information regarding the ' structures used in this sample. Type BITMAP '14 bytes bmType As Long bmWidth As Long bmHeight As Long bmWidthBytes As Long bmPlanes As Integer bmBitsPixel As Integer bmBits As Long End Type ' Refer to the MSDN for more detailed information regarding the API's ' used in this sample. Declare Function LoadImage Lib "user32" Alias "LoadImageA" _ (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, _ ByVal n1 As Long,ByVal n2 As Long, ByVal un2 As Long) As Long Declare Function CreateCompatibleDC Lib "gdi32" _ (ByVal hdc As Long) As Long Declare Function SelectObject Lib "gdi32" _ (ByVal hdc As Long, ByVal hObject As Long) As Long Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _ ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, _ ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, _ ByVal ySrc As Long, ByVal dwRop As Long) As Long Declare Function GetObject Lib "gdi32" Alias "GetObjectA" _ (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long Declare Function CreateCompatibleBitmap Lib "gdi32" _ (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long Declare Function DeleteObject Lib "gdi32" _ (ByVal hObject As Long) As Long Public Sub RotateBitmap(hBitmapDC As Long, lWidth As Long, _ lHeight As Long, lRadians As Long) Dim hNewBitmapDC As Long ' DC of the new bitmap Dim hNewBitmap As Long ' handle to the new bitmap Dim lSine As Long ' sine used in rotation Dim lCosine As Long ' cosine used in rotation Dim X1 As Long ' used in calculating new ' bitmap dimensions Dim X2 As Long ' used in calculating new ' bitmap dimensions Dim X3 As Long ' used in calculating new ' bitmap dimensions Dim Y1 As Long ' used in calculating new ' bitmap dimensions Dim Y2 As Long ' used in calculating new ' bitmap dimensions Dim Y3 As Long ' used in calculating new ' bitmap dimensions Dim lMinX As Long ' used in calculating new ' bitmap dimensions Dim lMaxX As Long ' used in calculating new ' bitmap dimensions Dim lMinY As Long ' used in calculating new ' bitmap dimensions Dim lMaxY As Long ' used in calculating new ' bitmap dimensions Dim lNewWidth As Long ' width of new bitmap Dim lNewHeight As Long ' height of new bitmap Dim I As Long ' loop counter Dim J As Long ' loop counter Dim lSourceX As Long ' x pixel coord we are blitting ' from the source image Dim lSourceY As Long ' y pixel coord we are blitting ' from the source image ' create a compatible DC from the one just brought ' into this function hNewBitmapDC = CreateCompatibleDC(hBitmapDC) ' compute the sine/cosinse of the radians used to ' rotate this image lSine = Sin(lRadians) lCosine = Cos(lRadians) ' compute the size of the new bitmap being created X1 = -lHeight * lSine Y1 = lHeight * lCosine X2 = lWidth * lCosine - lHeight * lSine Y2 = lHeight * lCosine + lWidth * lSine X3 = lWidth * lCosine Y3 = lWidth * lSine ' figure out the max/min size of the new bitmap lMinX = Min(0, Min(X1, Min(X2, X3))) lMinY = Min(0, Min(Y1, Min(Y2, Y3))) lMaxX = Max(X1, Max(X2, X3)) lMaxY = Max(Y1, Max(Y2, Y3)) ' set the new bitmap width/height lNewWidth = lMaxX - lMinX lNewHeight = lMaxY - lMinY ' create a new bitmap based upon the new width/height of the ' rotated bitmap hNewBitmap = CreateCompatibleBitmap _ (hBitmapDC, lNewWidth, lNewHeight) ' attach the new bitmap to the new device context created ' above before constructing the rotated bitmap Call SelectObject(hNewBitmapDC, hNewBitmap) ' loop through and translate each pixel to its new location. ' this is using a standard rotation algorithm For I = 0 To lNewHeight For J = 0 To lNewWidth lSourceX = (J + lMinX) * lCosine + (I + lMinY) * lSine lSourceY = (I + lMinY) * lCosine - (J + lMinX) * lSine If (lSourceX >= 0) And (lSourceX <= lWidth) And _ (lSourceY >= 0) And (lSourceY <= lHeight) Then Call BitBlt(hNewBitmapDC, J, I, 1, 1, hBitmapDC, _ lSourceX, lSourceY, SRCCOPY) End If Next J Next I ' reset the new bitmap width and height lWidth = lNewWidth lHeight = lNewHeight ' return the DC to the new bitmap hBitmapDC = hNewBitmapDC ' destroy the bitmap created Call DeleteObject(hNewBitmap) End Sub Private Function Min(X1 As Long, Y1 As Long) As Long If X1 >= Y1 Then Min = Y1 Else Min = X1 End If End Function Private Function Max(X1 As Long, Y1 As Long) As Long If X1 >= Y1 Then Max = X1 Else Max = Y1 End If End Function 8. Press the F5 key to run the project. Note that the application will load and attempt to read in the bitmap image specified in sFileName. If successful, the image will be blitted to the first PictureBox on the Form. Every half second, the image will then be rotated 90-degrees and blitted into the second PictureBox. Additional query words: sprites animation ====================================================================== Keywords : kbBitmap kbVBp kbVBp500 kbVBp600 kbGrpDSVB kbDSupport Technology : kbVBSearch kbAudDeveloper kbZNotKeyword6 kbZNotKeyword2 kbVB500Search kbVB600Search kbVB500 kbVB600 Version : :5.0,6.0 Issue type : kbhowto ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2002.