public static Bitmap RotateImage(Image image, int iw, int ih, float angle, out Point[] points) { if (image == null) throw new ArgumentNullException("image"); const double pi2 = Math.PI / 2.0; // Why can't C# allow these to be const, or at least readonly // *sigh* I'm starting to talk like Christian Graus :omg: double oldWidth = (double)iw; double oldHeight = (double)ih; // Convert degrees to radians double theta = ((double)angle) * Math.PI / 180.0; double locked_theta = theta; // Ensure theta is now [0, 2pi) while (locked_theta < 0.0) locked_theta += 2 * Math.PI; double newWidth, newHeight; int nWidth, nHeight; // The newWidth/newHeight expressed as ints double adjacentTop, oppositeTop; double adjacentBottom, oppositeBottom; // We need to calculate the sides of the triangles based // on how much rotation is being done to the bitmap. // Refer to the first paragraph in the explaination above for // reasons why. if ((locked_theta >= 0.0 && locked_theta < pi2) || (locked_theta >= Math.PI && locked_theta < (Math.PI + pi2))) { adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth; oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth; adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight; oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight; } else { adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight; oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight; adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth; oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth; } newWidth = adjacentTop + oppositeBottom; newHeight = adjacentBottom + oppositeTop; nWidth = (int)Math.Ceiling(newWidth); nHeight = (int)Math.Ceiling(newHeight); Bitmap rotatedBmp = new Bitmap(nWidth, nHeight); using (Graphics g = Graphics.FromImage(rotatedBmp)) { // This array will be used to pass in the three points that // make up the rotated image //Point[] points; /* * The values of opposite/adjacentTop/Bottom are referring to * fixed locations instead of in relation to the * rotating image so I need to change which values are used * based on the how much the image is rotating. * * For each point, one of the coordinates will always be 0, * nWidth, or nHeight. This because the Bitmap we are drawing on * is the bounding box for the rotated bitmap. If both of the * corrdinates for any of the given points wasn't in the set above * then the bitmap we are drawing on WOULDN'T be the bounding box * as required. */ if (locked_theta >= 0.0 && locked_theta < pi2) { points = new Point[] { new Point( (int) oppositeBottom, 0 ), new Point( nWidth, (int) oppositeTop ), new Point( 0, (int) adjacentBottom), new Point((int)(nWidth - oppositeBottom), (int)(oppositeTop + adjacentBottom)) }; } else if (locked_theta >= pi2 && locked_theta < Math.PI) { points = new Point[] { new Point( nWidth, (int) oppositeTop ), new Point( (int) adjacentTop, nHeight ), new Point( (int) oppositeBottom, 0 ), new Point((int)(oppositeBottom - (nWidth-adjacentTop)), (int)(nHeight - oppositeTop)) }; } else if (locked_theta >= Math.PI && locked_theta < (Math.PI + pi2)) { points = new Point[] { new Point( (int) adjacentTop, nHeight ), new Point( 0, (int) adjacentBottom ), new Point( nWidth, (int) oppositeTop ), new Point((int)(nWidth - adjacentTop), (int)(oppositeTop + adjacentBottom - nHeight)) }; } else { points = new Point[] { new Point( 0, (int) adjacentBottom ), new Point( (int) oppositeBottom, 0 ), new Point( (int) adjacentTop, nHeight ), new Point((int)(adjacentTop + oppositeBottom), (int)(nHeight - adjacentBottom)) }; } Point[] ps = new Point[] { points[0], points[1], points[2] }; g.DrawImage(image, ps); } return rotatedBmp; }