Rotate a Bitmap Image in 90-Degree Increments
Bitmap rotation is a graphic effect that Delphi 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.
procedure RotateBitmap(var hBitmapDC : Longint; var lWidth : Longint;
var lHeight : Longint; lRadians : real);
var
I : Longint; // loop counter
J : Longint; // loop counter
hNewBitmapDC : Longint; // DC of the new bitmap
hNewBitmap : Longint; // handle to the new bitmap
lSine : extended; // sine used in rotation
lCosine : extended; // cosine used in rotation
X1 : Longint; // used in calculating new
// bitmap dimensions
X2 : Longint; // used in calculating new
// bitmap dimensions
X3 : Longint; // used in calculating new
// bitmap dimensions
Y1 : Longint; // used in calculating new
// bitmap dimensions
Y2 : Longint; // used in calculating new
// bitmap dimensions
Y3 : Longint; // used in calculating new
// bitmap dimensions
lMinX : Longint; // used in calculating new
// bitmap dimensions
lMaxX : Longint; // used in calculating new
// bitmap dimensions
lMinY : Longint; // used in calculating new
// bitmap dimensions
lMaxY : Longint; // used in calculating new
// bitmap dimensions
lNewWidth : Longint; // width of new bitmap
lNewHeight : Longint; // height of new bitmap
lSourceX : Longint; // x pixel coord we are blitting
// from the source image
lSourceY : Longint; // y pixel coord we are blitting
// from the source image
begin
// 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 := Round(-lHeight * lSine);
Y1 := Round(lHeight * lCosine);
X2 := Round(lWidth * lCosine - lHeight * lSine);
Y2 := Round(lHeight * lCosine + lWidth * lSine);
X3 := Round(lWidth * lCosine);
Y3 := Round(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
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 do begin
For J := 0 To lNewWidth do begin
lSourceX := Round((J + lMinX) * lCosine + (I + lMinY) * lSine);
lSourceY := Round((I + lMinY) * lCosine - (J + lMinX) * lSine);
If (lSourceX >= 0) And (lSourceX <= lWidth) And
(lSourceY >= 0) And (lSourceY <= lHeight) Then
BitBlt(hNewBitmapDC, J, I, 1, 1, hBitmapDC,
lSourceX, lSourceY, SRCCOPY);
end;
end;
// reset the new bitmap width and height
lWidth := lNewWidth;
lHeight := lNewHeight;
// return the DC to the new bitmap
hBitmapDC := hNewBitmapDC;
// destroy the bitmap created
DeleteObject(hNewBitmap);
End;
The following is an example of how the RotateBitmap function might be called:
procedure TForm1.RotateTest(Sender: TObject);
var
lRadians : real;
DC : longint;
H, W : integer;
Degrees : integer;
begin
Degrees := 45;
lRadians := PI * Degrees / 180;
DC := Image1.Picture.Bitmap.Canvas.Handle;
H := Image1.Picture.Bitmap.Height;
W := Image1.Picture.Bitmap.Width;
RotateBitmap(DC, W, H, lRadians);
Image1.Width := W;
Image1.Height := H;
Image1.Picture.Bitmap.Width := W;
Image1.Picture.Bitmap.Height := H;
BitBlt(Image1.Picture.Bitmap.Canvas.Handle, 0, 0, W, H, DC, 0, 0, SRCCopy);
Image1.Refresh;
end;