图片旋转老外写的代码

/// <summary>
/// Creates a new Image containing the same image only rotated
/// </summary>
/// <param name="image">The <see cref="System.Drawing.Image"/> to rotate</param>
/// <param name="angle">The amount to rotate the image, clockwise, in degrees</param>
/// <returns>A new <see cref="System.Drawing.Bitmap"/> that is just large enough
/// to contain the rotated image without cutting any corners off.</returns>
/// <exception cref="System.ArgumentNullException">Thrown if <see cref="image"/> is null.</exception>
public static Bitmap RotateImage(Image image, float angle)
{
	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) image.Width;
	double oldHeight = (double) image.Height;
	
	// 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

	#region Explaination of the calculations
	/*
	 * The trig involved in calculating the new width and height
	 * is fairly simple; the hard part was remembering that when 
	 * PI/2 <= theta <= PI and 3PI/2 <= theta < 2PI the width and 
	 * height are switched.
	 * 
	 * When you rotate a rectangle, r, the bounding box surrounding r
	 * contains for right-triangles of empty space.  Each of the 
	 * triangles hypotenuse's are a known length, either the width or
	 * the height of r.  Because we know the length of the hypotenuse
	 * and we have a known angle of rotation, we can use the trig
	 * function identities to find the length of the other two sides.
	 * 
	 * sine = opposite/hypotenuse
	 * cosine = adjacent/hypotenuse
	 * 
	 * solving for the unknown we get
	 * 
	 * opposite = sine * hypotenuse
	 * adjacent = cosine * hypotenuse
	 * 
	 * Another interesting point about these triangles is that there
	 * are only two different triangles. The proof for which is easy
	 * to see, but its been too long since I've written a proof that
	 * I can't explain it well enough to want to publish it.  
	 * 
	 * Just trust me when I say the triangles formed by the lengths 
	 * width are always the same (for a given theta) and the same 
	 * goes for the height of r.
	 * 
	 * Rather than associate the opposite/adjacent sides with the
	 * width and height of the original bitmap, I'll associate them
	 * based on their position.
	 * 
	 * adjacent/oppositeTop will refer to the triangles making up the 
	 * upper right and lower left corners
	 * 
	 * adjacent/oppositeBottom will refer to the triangles making up 
	 * the upper left and lower right corners
	 * 
	 * The names are based on the right side corners, because thats 
	 * where I did my work on paper (the right side).
	 * 
	 * Now if you draw this out, you will see that the width of the 
	 * bounding box is calculated by adding together adjacentTop and 
	 * oppositeBottom while the height is calculate by adding 
	 * together adjacentBottom and oppositeTop.
	 */
	#endregion

	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 )
								 };

		}
		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 )						 
								 };
		}
		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 )
								 };
		}
		else
		{
			points = new Point[] { 
									 new Point( 0, (int) adjacentBottom ), 
									 new Point( (int) oppositeBottom, 0 ),
									 new Point( (int) adjacentTop, nHeight )		
								 };
		}

		g.DrawImage(image, points);
	}

	return rotatedBmp;
}

原文地址:https://www.cnblogs.com/whisht/p/3085059.html