CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 1 of 1
  1. #1
    Join Date
    Feb 2000
    Location
    Indore, India
    Posts
    1,046

    Windows SDK GDI: How do I display a bitmap rotated?

    Q: How do I display a bitmap rotated?

    A: Mirroring or inverting a bitmap about its center point is not difficult to achieve since they do not change its rectangular shape with horizontal and vertical sides. Rotating the bitmap in multiples of 90 degrees also is easy. But displaying a bitmap rotated by an arbitrary angle is difficult since the shape is changed and screen resolutions come into picture. Here I have attempted to achieve this, using simple graphic transformation.

    I am presenting a function 'MBRotate()', which takes, as inputs, the handle to a display device context, X and Y positions of the top left corner where the bitmap is to be displayed, handle to the bitmap object and angle of rotation in radians. Rotation direction is positive in anti-clockwise direction and point about which the rotation is performed is the insertion point of the bitmap, which is the top left corner of the bitmap. Since I am using trigonometric functions like 'sin()' and 'cos()' functions for coordinate transformations, I have included '' header file. I have written two simple functions to return rotated coordinates of a point and an array of points, latter using the former function. Steps to display the bitmap rotated involves two main steps:
    • Get the bitmap dimensions and compute the span when it is rotated. Get minimum and maximum of X and Y coordinates.
    • Scans all the points from between the minimum and maximum values of X and Y. Checks whether the point corresponds to a point within the bitmap dimensions. If it is, pick up the corresponding pixel of the bitmap and display.

    The code is amply commented.

    Code:
    #include <math.h>
    
    POINT Rotate(POINT pt, double theta)
    {
      // Gets horizontal and vertical resolution of display
      HDC hDC = GetDC(NULL);
      int XScale = GetDeviceCaps(hDC, LOGPIXELSX);
      int YScale = GetDeviceCaps(hDC, LOGPIXELSY);
      ReleaseDC(NULL, hDC);
    
      // Transforms coordinates
      int X = (int) (pt.x * cos(theta) - XScale * pt.y * sin(theta) / YScale);
      int Y = (int) (pt.y * cos(theta) + YScale * pt.x * sin(theta) / XScale);
    
      // Returns transformed point
      POINT P = {X, Y};
      return P;
    }
    
    LPPOINT Rotate(LPPOINT lppt, int size, double theta)
    {
      // Replaces the array with transformed points
      for (int i = 0; i < size; i++)
        lppt[i] = Rotate(lppt[i], theta);
    
      // Returns the transformed array
      return lppt;
    }
    
    BOOL BMRotate(HDC hdc, int x, int y, HBITMAP hbm, double theta = 0)
    {
      // Return value; TRUE if funtion successfully completed
      BOOL Done = FALSE;
    
      // Does nothing if bitmap handle is not valid
      if (hbm == NULL)
        return Done;
    
      // Set mapping mode to MM_TEXT
      int MapMode = SetMapMode(hdc, MM_TEXT);
    
      // Creates a compatible memory DC handle to load bitmap
      HDC hDC = CreateCompatibleDC(hdc);
      if (hDC)    // Device contect handle is not NULL
      {
        // Selects bitmap to device context
        HBITMAP hBM = (HBITMAP) SelectObject(hDC, hbm);
    
        // Gets bitmap dimensions
        BITMAP BM;
        GetObject(hbm, sizeof(BITMAP), &BM);
        int W = BM.bmWidth, H = BM.bmHeight;
    
        // Gets vertical & horizontal screen resolutions
        int XScale = GetDeviceCaps(hdc, LOGPIXELSX);
        int YScale = GetDeviceCaps(hdc, LOGPIXELSY);
    
        // Evaluate corner points
        POINT P[4];
        P[0].x = 0, P[0].y = 0;
        P[1].x = W, P[1].y = 0;
        P[2].x = W, P[2].y = H;
        P[3].x = 0, P[3].y = H;
    
        // Rotates the rectangle
        Rotate(P, 4, -theta);
    
        // Computes span of rotated rectangle
        for (int i = 1, MinX = P[0].x, MinY = P[0].y, MaxX = P[0].x, MaxY = P[0].y; i < 4; i++)
        {
          MinX = MinX < P[i].x ? MinX : P[i].x;
          MaxX = MaxX > P[i].x ? MaxX : P[i].x;
          MinY = MinY < P[i].y ? MinY : P[i].y;
          MaxY = MaxY > P[i].y ? MaxY : P[i].y;
        }
    
        // Computes original rectangle
        RECT R = {0, 0, W, H};
    
        // Spans all points of rotated rectangle
        for (int iX = MinX; iX < MaxX; iX++)
          for (int iY = MinY; iY < MaxY; iY++)
          {
            POINT P = {iX, iY};
    
            // Rotates back and checks whether in bitmap rectangle
            P = Rotate(P, theta);
            if (PtInRect(&R, P))  // Valid point
            {
              // Displays the bit in display device context
              SetPixel(hdc, x + iX, y + iY, GetPixel(hDC, P.x, P.y));
            }
          }
    
          // Deselects bitmap and deletes device context
          SelectObject(hDC, hBM);
          DeleteDC(hDC);
    
          // Returns TRUE since operation is successful
          Done = TRUE;
        }
      }
    
      // Resets mapping mode to its original value
      SetMapMode(hdc, MapMode);
    
      // Returns FALSE since operation is failed
      return Done;
    }
    Here is what I got when I rotated the bitmap by 30 degrees. Point about which rotation is performed is marked for illustration.

    For bigger bitmaps, 'GetPixel()'/'SetPixel()' calls will be time consuming. This can be changed by getting the pixel information of the bitmap in an array and reconstructing the rotated pixels from this information. That is beyond the scope of this post since this attempts to illustrate the method to display rotated bitmaps.



    Attached Images Attached Images  
    Last edited by Andreas Masur; November 4th, 2006 at 12:54 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured