El corazón del sistema está en la API GdipRotateWorldTransform y para conseguir el punto del centro de rotación, la API GdipTranslateWorldTransform.
La función que presento, rota una imagen sobre un punto de rotación elegido y un determinado número de grados. Recibe como parámetro la imagen en un HDC (Canvas.Handle) y devuelve un HBITMAP.
Como de costumbre daré las versiones delphi y C/C++ del mismo código:
// GDI+ Flat API... function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): Cardinal; stdcall external 'gdiplus'; procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus'; function GdipCreateBitmapFromHBITMAP(hbm: HBITMAP; hpal: HPALETTE; var GBitmap: THANDLE): Cardinal; stdcall external 'gdiplus'; function GdipDisposeImage(image: THANDLE): Cardinal; stdcall external 'gdiplus'; function GdipCreateFromHDC(DC: HDC; var Graphics: Pointer): Cardinal; stdcall external 'gdiplus'; function GdipRotateWorldTransform(graphics: Pointer; angle: Single; order: Cardinal): Cardinal; stdcall external 'gdiplus'; function GdipTranslateWorldTransform(graphics: Pointer; sx, sy: Single; order: Cardinal): Cardinal; stdcall external 'gdiplus'; function GdipDrawImage(graphics: Pointer; image: THANDLE; sx, sy: Single): Cardinal; stdcall external 'gdiplus'; function GdipDeleteGraphics(graphics: Pointer): Cardinal; stdcall external 'gdiplus'; function RotateDC(DC: HDC; x, y, Angle: Single): HBITMAP; var Bitmap: HBITMAP; GBitmap: THANDLE; Graphics: Pointer; BitmapData: TagBITMAP; Rect: TRect; begin Bitmap:= GetCurrentObject(DC, OBJ_BITMAP); GetObject(Bitmap, sizeof(TagBITMAP), @BitmapData); Rect.Left:= 0; Rect.Right:= BitmapData.bmWidth; Rect.Top:= 0; Rect.Bottom:= BitmapData.bmHeight; GdipCreateBitmapFromHBITMAP(Bitmap, 0, GBitmap); FillRect(DC, Rect, 0); GdipCreateFromHDC(DC, Graphics); GdipTranslateWorldTransform(Graphics, -x, -y, 0); GdipRotateWorldTransform(Graphics, Angle, 1); GdipTranslateWorldTransform(Graphics, x, y, 1); GdipDrawImage(Graphics, GBitmap, 0, 0); GdipDisposeImage(GBitmap); GdipDeleteGraphics(Graphics); Result:= GetCurrentObject(DC, OBJ_BITMAP); end;
Un ejemplo de uso:
var gdiplusToken: DWORD; GdiPlusStartupInput: array[0..1] of int64; begin // Inicializamos GDI+. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0; if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) <> 0 then exit; RotateDC(Image1.Picture.Bitmap.Canvas.Handle, Image1.Picture.Width/2, Image1.Picture.Height/2, 45); Image1.Invalidate; // Shutdown GDI+ GdiplusShutdown(gdiplusToken); end;
Espero que sea de utilidad.
Saludos.