To follow up on the earlier image editing tutorial, I will be going over an easy technique to rotate an image just like it is done in Adobe Photoshop.
To learn some more about the inner workings on the topic you can look up image transformation matrices. Let's create a method that takes a Bitmap object and a rotation angle and returns the new, rotated image.
private Bitmap rotateImage(Bitmap b, float angle)
We pass in the image to rotate (System.Drawing.Bitmap) and the the angle to rotate it by in degrees. The image will be rotated clockwise.
The next step is to create the bitmap we are going to return and also the graphics object (System.Drawing.Graphics) we use to rotate and draw the image. First we create a blank Bitmap which is the same size at the incoming one. Since we'll be drawing on this new Bitmap, the next thing to do is to create a Graphics object from this Bitmap.
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);
}
The next part is the important part which does the actual rotation. First we move the image to the middle because the image rotates from the upper left corner. Next we tell the graphics object to rotate the picture by the requested degrees. And finally we move the image back to the correct position.
The way the graphics object rotates the image is by using a transformation matrix, which you can do a lot more with than just rotate the image. If you know more about transformation matrices, you can set g.Transform to a System.Drawing.Drawing2D.Matrix to perform any number of translations. We didn't use a transformation matrix in this tutorial because this technique is easier to understand.
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);
//move rotation point to center of image
g.TranslateTransform((float)b.Width/2,(float)b.Height / 2);
//rotate
g.RotateTransform(angle);
//move image back
g.TranslateTransform(-(float)b.Width/2,-(float)b.Height / 2);
}
The last thing to do is draw the return image and return it.
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);
//move rotation point to center of image
g.TranslateTransform((float)b.Width/2, (float)b.Height / 2);
//rotate
g.RotateTransform(angle);
//move image back
g.TranslateTransform(-(float)b.Width/2,-(float)b.Height / 2);
//draw passed in image onto graphics object
g.DrawImage(b, new Point(0, 0));
return returnBitmap;
}
Just like before, here is the source code and a C# VS2005 Express Edition solution with the needed methods and some test code.
09/18/2007 - 14:24
Good example. Clear source codes :)
09/26/2007 - 09:46
Great example to get me started - could sort the clipping out though?
09/26/2007 - 10:13
Since the image is rotated inside its original bounds, the corners are most likely to be clipped. This can be fixed by increasing the size of
returnBitmapto account for this. You'll also have to adjust the transformation matrix to keep the image centered in the new, larger image.09/27/2007 - 11:12
Thanks, I've had a go and it seems to work.
Any idea why RotateTransform seems to recolour the image? How do I stop it doing that?
09/27/2007 - 11:28
Actually, have just found something that helps fix it:
System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
This doesnt recolour the image so my palette now stays the same when i rotate apart from one extra colour - the black it fills the background with.
09/27/2007 - 17:30
If you want the background to be a different color, you can clear the Graphics object after it's been created from the Bitmap.
g.Clear(Color.White);
02/13/2009 - 08:34
I thought of increasing the size of the resulting bitmap by a factor of theta but it does nt seem to work. The image still gets clipped. Can u help me avoid the clipping?
Regards,
Vikas
11/02/2007 - 12:29
I am using this rotateImage to rotate an image during acquire event during scanning. However, the image is saved very very small and hugs the right side of the page. Any ideas?
03/13/2009 - 10:13
This occurs because you're rotating the bitmap result from a previous rotation. Each rotation induces anomalies into the result image.
You can avoid this by not re-rotating the bitmap result of a previous rotation. Instead, keep a copy of the original bitmap, and rotate it by theta. This way, you don't increasingly distort the source image with each successive rotation.
03/13/2009 - 10:14
My reply was for the guy that said his image gets fuzzy with repeated rotations.
11/20/2007 - 13:34
This fades the whole image and if you keep rotating, the image gets messed up.
Any one noticed?
11/30/2007 - 11:32
Thank you
02/28/2008 - 04:11
Thank for your sample code :)
04/03/2008 - 06:14
Thanks for the good sample code.
04/03/2008 - 10:05
Your code has saved me. If I weren't a Christian, I would ask you to me my Savior.
04/10/2008 - 12:22
This is most excellent. Thanks so much.
04/16/2008 - 00:24
nice comment
04/26/2008 - 01:04
Very helpful and nicely commented and explained :)
05/13/2008 - 11:18
Good example with clear codes..Thanks to the author
07/23/2008 - 08:25
God bless you man!
;-) thanks very much.
07/23/2008 - 15:11
If you just need to rotate (and flip) by a multiple of 90 use
08/19/2008 - 17:19
The graphics I get at the end are the wrong dimensions and the contents are pushed out to the side and mostly cut off.
Any suggestions?
09/24/2008 - 11:18
hey help me to identify a circle in a image. it can be of any diameter.but i will have one of the pixel of that circle.
09/30/2008 - 13:32
This code works well but there seem to be certain issues that i am facing.
1.one that a few people have mentioned about the rotated image being clipped as the bounding rectangle stays the same
2. Rotating the image a lot, makes it blurry and unclear.
My approach would be to build a rotation matrix and apply the to the corners of the rectangle. Is there an easier way to do this.
11/19/2008 - 05:40
Hello,
could use some help plz
//move image back
g.TranslateTransform(-(float)b.Width/2,-(float)b.Height / 2);
i dont understand why cant I just write g.TranslateTransform(b.Width * 2, b.Height * 2);
thanks in advance
02/26/2009 - 13:14
thanx bgt broo..makin cakep deh kamu..
03/23/2009 - 22:23
/// Rotates the input image by theta degrees around center.
/// </summary>
public static Bitmap rotateCenter(Bitmap bmpSrc, float theta)
{
Matrix mRotate = new Matrix();
mRotate.Translate(bmpSrc.Width / -2, bmpSrc.Height / -2, MatrixOrder.Append);
mRotate.RotateAt(theta, new Point(0, 0), MatrixOrder.Append);
using (GraphicsPath gp = new GraphicsPath())
{ // transform image points by rotation matrix
gp.AddPolygon(new Point[] { new Point(0, 0), new Point(bmpSrc.Width, 0), new Point(0, bmpSrc.Height) });
gp.Transform(mRotate);
PointF[] pts = gp.PathPoints;
// create destination bitmap sized to contain rotated source image
Rectangle bbox = boundingBox(bmpSrc, mRotate);
Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height);
using (Graphics gDest = Graphics.FromImage(bmpDest))
{ // draw source into dest
Matrix mDest = new Matrix();
mDest.Translate(bmpDest.Width / 2, bmpDest.Height / 2, MatrixOrder.Append);
gDest.Transform = mDest;
gDest.DrawImage(bmpSrc, pts);
gDest.DrawRectangle(Pens.Red, bbox);
//drawAxes(gDest, Color.Red, 0, 0, 1, 100, "");
return bmpDest;
}
}
}
private static Rectangle boundingBox(Image img, Matrix matrix)
{
GraphicsUnit gu = new GraphicsUnit();
Rectangle rImg = Rectangle.Round(img.GetBounds(ref gu));
// Transform the four points of the image, to get the resized bounding box.
Point topLeft = new Point(rImg.Left, rImg.Top);
Point topRight = new Point(rImg.Right, rImg.Top);
Point bottomRight = new Point(rImg.Right, rImg.Bottom);
Point bottomLeft = new Point(rImg.Left, rImg.Bottom);
Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
GraphicsPath gp = new GraphicsPath(points,
new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
gp.Transform(matrix);
return Rectangle.Round(gp.GetBounds());
}
03/23/2009 - 22:26
Crap! Accidently submitted before I cleaned it up.
This hack will rotate an input bitmap about its center.
It returns a new bitmap, sized to bound the rotated input bitmap.
As usual with my code, my style is "thick". I'm sure more than one person will shred this and show a very simple way to accomplish the same result. But this gave me fits until I worked it out. Your mileage may vary.
- JMS
- gojumpinthelake@comcast.net
07/04/2009 - 06:10
Im trying to rotate an image using this method but im using a back buffer and just want to rotate an image on it. When i try to use this it is rotating all my images. Can anyone help please.
12/26/2009 - 07:10
very nice
thanks
01/17/2010 - 08:46
hey that really helped a lot.Thanks a lot...but how can this code be used for multiple images can u please tell...
01/31/2010 - 12:59
hello
i have 2 image i use surf descriptor to specify each picture
i want for example i have two similar images, the second image is turned at x degrees in relation with first
i would like to countdown the x degrees
how can i do this with surf discriptor or can i use anything else ???
thanks
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.