• 图片旋转老外写的代码


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

  • 相关阅读:
    java 8 stream sql left join =》 jooq & Flink & Scala
    Maven error: lambda expressions are not supported in -source 1.7
    error C2039: 'SetWindowTextA' : is not a member of 'CString'
    循环队列(循环数组)中元素个数的计算
    数据结构之堆
    理解C语言声明的优先级规则
    内联汇编中的asm和__asm__
    程序启动时的堆栈
    局部变量与堆栈
    BCD码干什么用的?
  • 原文地址:https://www.cnblogs.com/whisht/p/3085059.html
Copyright © 2020-2023  润新知