[c#] How do I rotate a picture in WinForms

I want to have one picture in my application that I can rotate to indicate directions, like wind direction. Or even the time. What code do I use to rotate the picture? Thanks

Update: I am using .NET 2.0, Windows 2000, VS C# 2005

This question is related to c# winforms image

The answer is


I've written a simple class for rotating image. All you've to do is input image and angle of rotation in Degree. Angle must be between -90 and +90.

public class ImageRotator
{
    private readonly Bitmap image;
    public Image OriginalImage
    {
        get { return image; }
    }


    private ImageRotator(Bitmap image)
    {
        this.image = image;
    }


    private double GetRadian(double degree)
    {
        return degree * Math.PI / (double)180;
    }


    private Size CalculateSize(double angle)
    {
        double radAngle = GetRadian(angle);
        int width = (int)(image.Width * Math.Cos(radAngle) + image.Height * Math.Sin(radAngle));
        int height = (int)(image.Height * Math.Cos(radAngle) + image.Width * Math.Sin(radAngle));
        return new Size(width, height);
    }

    private PointF GetTopCoordinate(double radAngle)
    {
        Bitmap image = CurrentlyViewedMappedImage.BitmapImage;
        double topX = 0;
        double topY = 0;

        if (radAngle > 0)
        {
            topX = image.Height * Math.Sin(radAngle);
        }
        if (radAngle < 0)
        {
            topY = image.Width * Math.Sin(-radAngle);
        }
        return new PointF((float)topX, (float)topY);
    }

    public Bitmap RotateImage(double angle)
    {
        SizeF size = CalculateSize(radAngle);
        Bitmap rotatedBmp = new Bitmap((int)size.Width, (int)size.Height);

        Graphics g = Graphics.FromImage(rotatedBmp);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;

        g.TranslateTransform(topPoint.X, topPoint.Y);
        g.RotateTransform(GetDegree(radAngle));
        g.DrawImage(image, new RectangleF(0, 0, size.Width, size.Height));

        g.Dispose();
        return rotatedBmp;
    }


    public static class Builder
    {
        public static ImageRotator CreateInstance(Image image)
        {
            ImageRotator rotator = new ImageRotator(image as Bitmap);
            return rotator;
        }
    }
}

This solution assumes that you want to draw the image in a picture box and that the image orientation will follow the mouse movements over this picture box. No image is assigned to the picture box. Instead I'm getting the image from a project resource.

private float _angle;

public Form1()
{
    InitializeComponent();
}

private void PictureBox_MouseMove(object sender, MouseEventArgs e)
{
    (float centerX, float centerY) = GetCenter(pictureBox1.ClientRectangle);
    _angle = (float)(Math.Atan2(e.Y - centerY, e.X - centerX) * 180.0 / Math.PI);
    pictureBox1.Invalidate(); // Triggers redrawing
}

private void PictureBox_Paint(object sender, PaintEventArgs e)
{
    Bitmap image = Properties.Resources.ExampleImage;
    float scale = (float)pictureBox1.Width / image.Width;

    (float centerX, float centerY) = GetCenter(e.ClipRectangle);

    e.Graphics.TranslateTransform(centerX, centerY);
    e.Graphics.RotateTransform(_angle);
    e.Graphics.TranslateTransform(-centerX, -centerY);
    e.Graphics.ScaleTransform(scale, scale);
    e.Graphics.DrawImage(image, 0, 0);
}

// Uses C# 7.0 value tuples / .NET Framework 4.7.
// For previous versions, return a PointF instead.
private static (float, float) GetCenter(Rectangle rect)
{
    float centerX = (rect.Left + rect.Right) * 0.5f;
    float centerY = (rect.Top + rect.Bottom) * 0.5f;
    return (centerX, centerY);
}

Make sure to to select the mouse event handlers PictureBox_MouseMove and PictureBox_Paint in properties window of the picture box for these events, after you copy/pasted this code into the form.

Note: You could also use a simple Panel or any other control, like a label; however, the PictureBox has the advantage to use double buffering by default, which eliminates flickering.


You can easily do it by calling this method :

public static Bitmap RotateImage(Image image, float angle)
{
    if (image == null)
        throw new ArgumentNullException("image");

    PointF offset = new PointF((float)image.Width / 2, (float)image.Height / 2);

    //create a new empty bitmap to hold rotated image
    Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
    rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    //make a graphics object from the empty bitmap
    Graphics g = Graphics.FromImage(rotatedBmp);

    //Put the rotation point in the center of the image
    g.TranslateTransform(offset.X, offset.Y);

    //rotate the image
    g.RotateTransform(angle);

    //move the image back
    g.TranslateTransform(-offset.X, -offset.Y);

    //draw passed in image onto graphics object
    g.DrawImage(image, new PointF(0, 0));

    return rotatedBmp;
}

don't forget to add a reference to System.Drawing.dll on your project

Example of this method call :

Image image = new Bitmap("waves.png");
Image newImage = RotateImage(image, 360);
newImage.Save("newWaves.png");

I found this article

  /// <summary>
    /// Creates a new Image containing the same image only rotated
    /// </summary>
    /// <param name=""image"">The <see cref=""System.Drawing.Image"/"> to rotate
    /// <param name=""offset"">The position to rotate from.
    /// <param name=""angle"">The amount to rotate the image, clockwise, in degrees
    /// <returns>A new <see cref=""System.Drawing.Bitmap"/"> of the same size rotated.</see>
    /// <exception cref=""System.ArgumentNullException"">Thrown if <see cref=""image"/"> 
    /// is null.</see>
    public static Bitmap RotateImage(Image image, PointF offset, float angle)
    {
        if (image == null)
            throw new ArgumentNullException("image");

        //create a new empty bitmap to hold rotated image
        Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
        rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        //make a graphics object from the empty bitmap
        Graphics g = Graphics.FromImage(rotatedBmp);

        //Put the rotation point in the center of the image
        g.TranslateTransform(offset.X, offset.Y);

        //rotate the image
        g.RotateTransform(angle);

        //move the image back
        g.TranslateTransform(-offset.X, -offset.Y);

        //draw passed in image onto graphics object
        g.DrawImage(image, new PointF(0, 0));

        return rotatedBmp;
    }

This is an old thread, and there are several other threads about C# WinForms image rotation, but now that I've come up with my solution I figure this is as good a place to post it as any.

  /// <summary>
  /// Method to rotate an Image object. The result can be one of three cases:
  /// - upsizeOk = true: output image will be larger than the input, and no clipping occurs 
  /// - upsizeOk = false & clipOk = true: output same size as input, clipping occurs
  /// - upsizeOk = false & clipOk = false: output same size as input, image reduced, no clipping
  /// 
  /// A background color must be specified, and this color will fill the edges that are not 
  /// occupied by the rotated image. If color = transparent the output image will be 32-bit, 
  /// otherwise the output image will be 24-bit.
  /// 
  /// Note that this method always returns a new Bitmap object, even if rotation is zero - in 
  /// which case the returned object is a clone of the input object. 
  /// </summary>
  /// <param name="inputImage">input Image object, is not modified</param>
  /// <param name="angleDegrees">angle of rotation, in degrees</param>
  /// <param name="upsizeOk">see comments above</param>
  /// <param name="clipOk">see comments above, not used if upsizeOk = true</param>
  /// <param name="backgroundColor">color to fill exposed parts of the background</param>
  /// <returns>new Bitmap object, may be larger than input image</returns>
  public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsizeOk, 
                                   bool clipOk, Color backgroundColor)
  {
     // Test for zero rotation and return a clone of the input image
     if (angleDegrees == 0f)
        return (Bitmap)inputImage.Clone();

     // Set up old and new image dimensions, assuming upsizing not wanted and clipping OK
     int oldWidth = inputImage.Width;
     int oldHeight = inputImage.Height;
     int newWidth = oldWidth;
     int newHeight = oldHeight;
     float scaleFactor = 1f;

     // If upsizing wanted or clipping not OK calculate the size of the resulting bitmap
     if (upsizeOk || !clipOk)
     {
        double angleRadians = angleDegrees * Math.PI / 180d;

        double cos = Math.Abs(Math.Cos(angleRadians));
        double sin = Math.Abs(Math.Sin(angleRadians));
        newWidth = (int)Math.Round(oldWidth * cos + oldHeight * sin);
        newHeight = (int)Math.Round(oldWidth * sin + oldHeight * cos);
     }

     // If upsizing not wanted and clipping not OK need a scaling factor
     if (!upsizeOk && !clipOk)
     {
        scaleFactor = Math.Min((float)oldWidth / newWidth, (float)oldHeight / newHeight);
        newWidth = oldWidth;
        newHeight = oldHeight;
     }

     // Create the new bitmap object. If background color is transparent it must be 32-bit, 
     //  otherwise 24-bit is good enough.
     Bitmap newBitmap = new Bitmap(newWidth, newHeight, backgroundColor == Color.Transparent ? 
                                      PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb);
     newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution);

     // Create the Graphics object that does the work
     using (Graphics graphicsObject = Graphics.FromImage(newBitmap))
     {
        graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality;
        graphicsObject.SmoothingMode = SmoothingMode.HighQuality;

        // Fill in the specified background color if necessary
        if (backgroundColor != Color.Transparent)
           graphicsObject.Clear(backgroundColor);

        // Set up the built-in transformation matrix to do the rotation and maybe scaling
        graphicsObject.TranslateTransform(newWidth / 2f, newHeight / 2f);

        if (scaleFactor != 1f)
           graphicsObject.ScaleTransform(scaleFactor, scaleFactor);

        graphicsObject.RotateTransform(angleDegrees);
        graphicsObject.TranslateTransform(-oldWidth / 2f, -oldHeight / 2f);

        // Draw the result 
        graphicsObject.DrawImage(inputImage, 0, 0);
     }

     return newBitmap;
  }

This is the result of many sources of inspiration, here at StackOverflow and elsewhere. Naveen's answer on this thread was especially helpful.


Rotating image is one thing, proper image boundaries in another. Here is a code which can help anyone. I created this based on some search on internet long ago.

    /// <summary>
    /// Rotates image in radian angle
    /// </summary>
    /// <param name="bmpSrc"></param>
    /// <param name="theta">in radian</param>
    /// <param name="extendedBitmapBackground">Because of rotation returned bitmap can have different boundaries from original bitmap. This color is used for filling extra space in bitmap</param>
    /// <returns></returns>
    public static Bitmap RotateImage(Bitmap bmpSrc, double theta, Color? extendedBitmapBackground = null)
    {
        theta = Convert.ToSingle(theta * 180 / Math.PI);
        Matrix mRotate = new Matrix();
        mRotate.Translate(bmpSrc.Width / -2, bmpSrc.Height / -2, MatrixOrder.Append);
        mRotate.RotateAt((float)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))
            {
                if (extendedBitmapBackground != null)
                {
                    gDest.Clear(extendedBitmapBackground.Value);
                }
                // 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);
                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());
    }

Richard Cox has a good solution to this https://stackoverflow.com/a/5200280/1171321 I have used in the past. It is also worth noting the DPI must be 96 for this to work correctly. Several of the solutions on this page do not work at all.


Simple method:

public Image RotateImage(Image img)
{
    var bmp = new Bitmap(img);

    using (Graphics gfx = Graphics.FromImage(bmp))
    {
        gfx.Clear(Color.White);
        gfx.DrawImage(img, 0, 0, img.Width, img.Height);
    }

    bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
    return bmp;
}

I have modified the function of Mr.net_prog which gets only the picture box and rotate the image in it.

    public static void RotateImage(PictureBox picBox)
    {

        Image img = picBox.Image;
        var bmp = new Bitmap(img);

        using (Graphics gfx = Graphics.FromImage(bmp))
        {
            gfx.Clear(Color.White);
            gfx.DrawImage(img, 0, 0, img.Width, img.Height);
        }

        bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
        picBox.Image = bmp;
    }

Old question but I had to address MrFox's comment in the accepted answer. Rotating an image when the size changes cuts off the edges of the image. One solution is to redraw the original on a larger image, centered, where the larger image's dimensions compensate for the need of not clipping the edges. For example, I wanted to be able to design a game's tiles at a normal angle but re-draw them at a 45-degree angle for an isometric view.

Here are example images (yellow borders are to make it easier to see here).

The original image: water tile

The centered tile in a larger image: enter image description here

The rotated image (where you rotate the larger image, not the original): enter image description here

The code (based in part on this answer in another question):

private Bitmap RotateImage(Bitmap rotateMe, float angle)
{
    //First, re-center the image in a larger image that has a margin/frame
    //to compensate for the rotated image's increased size

    var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width / 2), rotateMe.Height + (rotateMe.Height / 2));

    using (Graphics g = Graphics.FromImage(bmp))
        g.DrawImageUnscaled(rotateMe, (rotateMe.Width / 4), (rotateMe.Height / 4), bmp.Width, bmp.Height);

    bmp.Save("moved.png");
    rotateMe = bmp;

    //Now, actually rotate the image
    Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height);

    using (Graphics g = Graphics.FromImage(rotatedImage))
    {
        g.TranslateTransform(rotateMe.Width / 2, rotateMe.Height / 2);   //set the rotation point as the center into the matrix
        g.RotateTransform(angle);                                        //rotate
        g.TranslateTransform(-rotateMe.Width / 2, -rotateMe.Height / 2); //restore rotation point into the matrix
        g.DrawImage(rotateMe, new Point(0, 0));                          //draw the image on the new bitmap
    }

    rotatedImage.Save("rotated.png");
    return rotatedImage;
}

This will work as long as the image you want to rotate is already in your Properties resources folder.

In Partial Class:

Bitmap bmp2;

OnLoad:

 bmp2 = new Bitmap(Tycoon.Properties.Resources.save2);
            pictureBox6.SizeMode = PictureBoxSizeMode.StretchImage;
            pictureBox6.Image = bmp2;

Button or Onclick

private void pictureBox6_Click(object sender, EventArgs e)
        {
            if (bmp2 != null)
            {
                bmp2.RotateFlip(RotateFlipType.Rotate90FlipNone);
                pictureBox6.Image = bmp2;
            }
        }

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to winforms

How to set combobox default value? Get the cell value of a GridView row Getting the first and last day of a month, using a given DateTime object Check if a record exists in the database Delete a row in DataGridView Control in VB.NET How to make picturebox transparent? Set default format of datetimepicker as dd-MM-yyyy Changing datagridview cell color based on condition C# Inserting Data from a form into an access Database How to use ConfigurationManager

Examples related to image

Reading images in python Numpy Resize/Rescale Image Convert np.array of type float64 to type uint8 scaling values Extract a page from a pdf as a jpeg How do I stretch an image to fit the whole background (100% height x 100% width) in Flutter? Angular 4 img src is not found How to make a movie out of images in python Load local images in React.js How to install "ifconfig" command in my ubuntu docker image? How do I display local image in markdown?