Rotate a Graphics Bitmap at Its Center

Rotate a Graphics bitmap at its center

To draw a rotated Bitmap you need to do a few steps to prepare the Graphics object:

  • first you move its origin onto the midpoint of the rotation
  • then you rotate by the desired angle
  • next you move it back
  • now you can draw the Bitmap
  • finally you reset the Graphics

This needs to be done for each bitmap.

Here are the steps in code to draw a Bitmap bmp at position (xPos, yPos):

float moveX = bmp.Width / 2f + xPos;   
float moveY = bmp.Height / 2f+ xPosf;
e.Graphics.TranslateTransform(moveX , moveY );
e.Graphics.RotateTransform(angle);
e.Graphics.TranslateTransform(-moveX , -moveY );
e.Graphics.DrawImage(bmp, xPos, yPos);
e.Graphics.ResetTransform();

There is one possible complication: If your Bitmap has different dpi resolution than the screen i.e. than the Graphics you must first adapt the Bitmap's dpi setting!

To adapt the Bitmapto the usual 96dpi you can simply do a

bmp.SetResolution(96,96);

To be prepared for future retina-like displays you can create a class variable you set at startup:

int ScreenDpi = 96;
private void Form1_Load(object sender, EventArgs e)
{
using (Graphics G = this.CreateGraphics()) ScreenDpi = (int)G.DpiX;
}

and use it after loading the Bitmap:

bmp.SetResolution(ScreenDpi , ScreenDpi );

As usual the DrawImage method uses the top left corner of the Bitmap. You may need to use different Points for the rotation point and possibly also for the virtual position of your car, maybe in the middle of its front..

How can I rotate a bitmap, keeping its scale

Answered on MSDN:

static void RotateBitmap2( string srcFilename, string destFilename, double degrees )
{
using( var srcBitmap = Bitmap.FromFile( srcFilename ) )
{
using( var g1 = Graphics.FromImage( srcBitmap ) )
{
var w = srcBitmap.Width;
var h = srcBitmap.Height;
g1.TranslateTransform( w / 2, h / 2 );
g1.RotateTransform( checked((float)degrees) );
g1.TranslateTransform( -w / 2, -h / 2 );
var a = new[] { new Point( 0, 0 ), new Point( w, 0 ), new Point( w, h ), new Point( 0, h ) };
g1.TransformPoints( CoordinateSpace.Device, CoordinateSpace.World, a );

int new_w = a.Max( p => p.X ) - a.Min( p => p.X );
int new_h = a.Max( p => p.Y ) - a.Min( p => p.Y );

using( var rotatedImage = new Bitmap( new_w, new_h, g1 ) )
{
using(var g2 = Graphics.FromImage(rotatedImage))
{
g2.TranslateTransform( new_w / 2, new_h / 2 );
g2.RotateTransform( checked((float)degrees) );

g2.DrawImageUnscaled( srcBitmap, -w / 2, -h / 2 );
}

rotatedImage.Save( destFilename, ImageFormat.Png );
}
}
}
}

Android rotate bitmap around center without resizing

This worked for me!

I created a method that returns a matrix. The matrix can be used in the following drawing method:

public void drawBitmap (Bitmap bitmap, Matrix matrix, Paint paint)

Here you go! (The parameter shape can be replaced with ease, if you would like that, just leave a comment):

public static Matrix rotateMatrix(Bitmap bitmap, Shape shape, int rotation) {

float scaleWidth = ((float) shape.getWidth()) / bitmap.getWidth();
float scaleHeight = ((float) shape.getHeight()) / bitmap.getHeight();

Matrix rotateMatrix = new Matrix();
rotateMatrix.postScale(scaleWidth, scaleHeight);
rotateMatrix.postRotate(rotation, shape.getWidth()/2, shape.getHeight()/2);
rotateMatrix.postTranslate(shape.getX(), shape.getY());

return rotateMatrix;

}

NB: If you want an animated rotation, the rotation parameter will have to be updated with new values every frame eg. 1 then 2 then 3 ...

Properly rotate an image

The issue occurs in the rotating is related to the bounding box. It is clipping the edge because of the image you provided does not fit into the area that you have given.

I also faced this issue. So I tried a solution from here.

Adding the code that works for me.

public static Bitmap RotateImageN(Bitmap bitmap, float angle)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;

Rectangle rectangle = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rectangle.Width, rectangle.Height);

using (Graphics gDest = Graphics.FromImage(resultBitmap))
{
Matrix mDest = new Matrix();
mDest.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
gDest.Transform = mDest;
gDest.DrawImage(bitmap, points);
return resultBitmap;
}
}
}

private static Rectangle boundingBox(Image image, Matrix matrix)
{
GraphicsUnit graphicsUnit = new GraphicsUnit();
Rectangle boundingRectangle = Rectangle.Round(image.GetBounds(ref graphicsUnit));
Point topLeft = new Point(boundingRectangle.Left, boundingRectangle.Top);
Point topRight = new Point(boundingRectangle.Right, boundingRectangle.Top);
Point bottomRight = new Point(boundingRectangle.Right, boundingRectangle.Bottom);
Point bottomLeft = new Point(boundingRectangle.Left, boundingRectangle.Bottom);
Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
GraphicsPath graphicsPath = new GraphicsPath(points, new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
graphicsPath.Transform(matrix);
return Rectangle.Round(graphicsPath.GetBounds());
}

VB.NET Rotate graphics object around center

I started a new VB.NET Windows Forms project. I added a Panel of 200px x 200px and a Button to pause the animation as desired. I gave Panel1 a background image:

Sample Image

Made an image a little like yours:

Sample Image

and used the following code:

Public Class Form1

Dim wiggle As Bitmap
Dim tim As Timer

Sub MoveWiggle(sender As Object, e As EventArgs)
Static rot As Integer = 0
Panel1.Refresh()

Using g = Panel1.CreateGraphics()
Using fnt As New Font("Consolas", 12), brsh As New SolidBrush(Color.Red)
' the text will not be rotated or translated
g.DrawString($"{rot}°", fnt, brsh, New Point(10, 10))
End Using
' the image will be rotated and translated
g.TranslateTransform(100, 100)
g.RotateTransform(CSng(rot))
g.DrawImage(wiggle, -80, 0)
End Using

rot = (rot + 10) Mod 360

End Sub

Private Sub bnPause_Click(sender As Object, e As EventArgs) Handles bnPause.Click
Static isPaused As Boolean = False
If isPaused Then
tim.Start()
bnPause.Text = "Pause"
Else
tim.Stop()
bnPause.Text = "Start"
End If

isPaused = Not isPaused

End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
wiggle = New Bitmap("C:\temp\path3494.png")
wiggle.SetResolution(96, 96) ' my image had a strange resolution
tim = New Timer With {.Interval = 50}
AddHandler tim.Tick, AddressOf MoveWiggle
tim.Start()

End Sub

Private Sub Form1_Closing(sender As Object, e As EventArgs) Handles MyBase.Closing
RemoveHandler tim.Tick, AddressOf MoveWiggle
tim.Dispose()
wiggle.Dispose()

End Sub

End Class

and achieved this:

Sample Image

Note 1: It is important to set the transformations in the correct order.

Note 2: I called .Dispose() on the disposable resources in the MyBase.Closing event. This makes sure that memory is left clean and nothing leaks.

There are undoubtedly better ways to create animations, but at your desired one frame per second this achieves the effect you're after.



Related Topics



Leave a reply



Submit