Search code examples
c#winformsrotationsystem.drawing

Get resulting size of RotateTransform


I've got the following code for rotating an image in C#:

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)returnBitmap.Width / 2, (float)returnBitmap.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 Rectangle(new Point(0, 0), new Size(b.Width, b.Height)));
    return returnBitmap;
}

It works very well, except that it clips the result when it exceeds original bounds.

As I understood, I have to set returnBitmap's size to the size of image after rotation. But how do I find how big the result will be, to set size of the new bitmap accordingly?


Solution

  • You need to rotate the four corners of your original image and calculate the bounding box for the new coordinates:

        private static Bitmap RotateImage(Image b, float angle)
        {
            var corners = new[]
                {new PointF(0, 0), new Point(b.Width, 0), new PointF(0, b.Height), new PointF(b.Width, b.Height)};
    
            var xc = corners.Select(p => Rotate(p, angle).X);
            var yc = corners.Select(p => Rotate(p, angle).Y);
    
            //create a new empty bitmap to hold rotated image
            Bitmap returnBitmap = new Bitmap((int)Math.Abs(xc.Max() - xc.Min()), (int)Math.Abs(yc.Max() - yc.Min()));
            ...
        }
    
        /// <summary>
        /// Rotates a point around the origin (0,0)
        /// </summary>
        private static PointF Rotate(PointF p, float angle)
        {
            // convert from angle to radians
            var theta = Math.PI*angle/180;
            return new PointF(
                (float) (Math.Cos(theta)*(p.X) - Math.Sin(theta)*(p.Y)),
                (float) (Math.Sin(theta)*(p.X) + Math.Cos(theta)*(p.Y)));
        }