C# Tutorial - Image Editing: Rotate

Skill

C# Tutorial - Image Editing: Rotate

Posted in:

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.

private Bitmap rotateImage(Bitmap b, float angle)
{
  //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.

private Bitmap rotateImage(Bitmap b, float angle)
{
  //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.

private Bitmap rotateImage(Bitmap b, float angle)
{
  //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.

Mike
09/18/2007 - 14:24

Good example. Clear source codes :)

reply

Claire
09/26/2007 - 09:46

Great example to get me started - could sort the clipping out though?

reply

The Reddest
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 returnBitmap to account for this. You'll also have to adjust the transformation matrix to keep the image centered in the new, larger image.

reply

Claire
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?

reply

Claire
09/27/2007 - 11:28

Actually, have just found something that helps fix it:

g.InterpolationMode =
  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.

reply

The Reddest
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.

Graphics g = Graphics.FromImage(returnBitmap);
g.Clear(Color.White);

reply

joinvikas_24
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

reply

Janet
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?

reply

Anonymous
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.

reply

Anonymous
03/13/2009 - 10:14

My reply was for the guy that said his image gets fuzzy with repeated rotations.

reply

Mustansar
11/20/2007 - 13:34

This fades the whole image and if you keep rotating, the image gets messed up.

Any one noticed?

reply

Anonymous
11/30/2007 - 11:32

Thank you

reply

Chan nyein thar
02/28/2008 - 04:11

Thank for your sample code :)

reply

Sai Gudigundla
04/03/2008 - 06:14

Thanks for the good sample code.

reply

GeekThug
04/03/2008 - 10:05

Your code has saved me. If I weren't a Christian, I would ask you to me my Savior.

reply

Rich Bateman
04/10/2008 - 12:22

This is most excellent. Thanks so much.

reply

Anonymous
04/16/2008 - 00:24

nice comment

reply

Sobia Saeed Magray
04/26/2008 - 01:04

Very helpful and nicely commented and explained :)

reply

Vicky
05/13/2008 - 11:18

Good example with clear codes..Thanks to the author

reply

Ampelio
07/23/2008 - 08:25

God bless you man!
;-) thanks very much.

reply

Paul
07/23/2008 - 15:11

If you just need to rotate (and flip) by a multiple of 90 use

image.RotateFlip(RotateFlipType);

reply

Bret
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?

reply

Maninder
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.

reply

Neehar
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.

reply

Im cant understand
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

reply

orang tampan
02/26/2009 - 13:14

thanx bgt broo..makin cakep deh kamu..

reply

Anonymous
03/23/2009 - 22:23

/// <summary>
/// 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());
        }

reply

Anonymous
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

reply

Anonymous
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.

reply

mousa
12/26/2009 - 07:10

very nice
thanks

reply

djsproject10
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...

reply

ntouros
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

reply

Add Comment

Put code snippets inside language tags:
[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.

Sponsors