使用GDI+进行图像旋转

以前总是用大段大段的cos/sin来写旋转图像的代码,而且旋转出来还经常因为插值的问题导致图像出错。后来稍微研究了一下GDI+,发现直接用GDI+来旋转效果比我自己写好太多了,网上搜到了关于旋转的代码,在这里和大家分享。

/**/ /// <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

            
Explaination of the calculations#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;
        }

    


 

你可能感兴趣的:(使用GDI+进行图像旋转)