2010-01-29 52 views
36

我想在我的应用程序中有一张图片,可以旋转以指示方向,如风向。甚至是时间。我用什么代码来旋转图片?由于如何在WinForms中旋转图片

更新:我使用.NET 2.0,Windows 2000中,VS C#2005

+0

是否使用的WinForms或WPF? – RandomEngy 2010-01-29 17:35:47

+0

不是WPF,我不认为winforms。 – 2010-01-29 17:37:48

+2

如果你没有使用WPF(带有.xaml文件等),并且你正在Visual Studio中用C#开发UI,那么你就是在WinForms中开发的。它是Windows窗体的简称。 – RandomEngy 2010-01-29 18:15:01

回答

31

这里是你可以用它来旋转在C#中的图像的方法:

/// <summary> 
/// method to rotate an image either clockwise or counter-clockwise 
/// </summary> 
/// <param name="img">the image to be rotated</param> 
/// <param name="rotationAngle">the angle (in degrees). 
/// NOTE: 
/// Positive values will rotate clockwise 
/// negative values will rotate counter-clockwise 
/// </param> 
/// <returns></returns> 
public static Image RotateImage(Image img, float rotationAngle) 
{ 
    //create an empty Bitmap image 
    Bitmap bmp = new Bitmap(img.Width, img.Height); 

    //turn the Bitmap into a Graphics object 
    Graphics gfx = Graphics.FromImage(bmp); 

    //now we set the rotation point to the center of our image 
    gfx.TranslateTransform((float)bmp.Width/2, (float)bmp.Height/2); 

    //now rotate the image 
    gfx.RotateTransform(rotationAngle); 

    gfx.TranslateTransform(-(float)bmp.Width/2, -(float)bmp.Height/2); 

    //set the InterpolationMode to HighQualityBicubic so to ensure a high 
    //quality image once it is transformed to the specified size 
    gfx.InterpolationMode = InterpolationMode.HighQualityBicubic; 

    //now draw our new image onto the graphics object 
    gfx.DrawImage(img, new Point(0, 0)); 

    //dispose of our Graphics object 
    gfx.Dispose(); 

    //return the image 
    return bmp; 
} 
+12

你有没有试过这段代码?它不能正常工作 – 2011-09-25 21:41:08

+0

漂亮,紧凑的实现。 – TheBlastOne 2011-10-07 12:35:41

+6

旋转后的图像可能比原来的图像大,如果你在0到90度之间旋转,比如45度它会在边缘上流动,你必须为此留出空间。 – MrFox 2012-08-01 18:33:03

5

我发现这个article

/// <summary> 
    /// Creates a new Image containing the same image only rotated 
    /// </summary> 
    /// <param name=""image"">The <see cref=""System.Drawing.Image"/"> to rotate 
    /// <param name=""offset"">The position to rotate from. 
    /// <param name=""angle"">The amount to rotate the image, clockwise, in degrees 
    /// <returns>A new <see cref=""System.Drawing.Bitmap"/"> of the same size rotated.</see> 
    /// <exception cref=""System.ArgumentNullException"">Thrown if <see cref=""image"/"> 
    /// is null.</see> 
    public static Bitmap RotateImage(Image image, PointF offset, float angle) 
    { 
     if (image == null) 
      throw new ArgumentNullException("image"); 

     //create a new empty bitmap to hold rotated image 
     Bitmap rotatedBmp = new Bitmap(image.Width, image.Height); 
     rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution); 

     //make a graphics object from the empty bitmap 
     Graphics g = Graphics.FromImage(rotatedBmp); 

     //Put the rotation point in the center of the image 
     g.TranslateTransform(offset.X, offset.Y); 

     //rotate the image 
     g.RotateTransform(angle); 

     //move the image back 
     g.TranslateTransform(-offset.X, -offset.Y); 

     //draw passed in image onto graphics object 
     g.DrawImage(image, new PointF(0, 0)); 

     return rotatedBmp; 
    } 
18

简单的方法:

public Image RotateImage(Image img) 
{ 
    var bmp = new Bitmap(img); 

    using (Graphics gfx = Graphics.FromImage(bmp)) 
    { 
     gfx.Clear(Color.White); 
     gfx.DrawImage(img, 0, 0, img.Width, img.Height); 
    } 

    bmp.RotateFlip(RotateFlipType.Rotate270FlipNone); 
    return bmp; 
} 
+2

嗯,为什么要创建Graphics对象并使用它来清除和重绘Bitmap对象?这不是没有必要吗?代码似乎没有这些工作,至少在Bitmap.RotateFlip()可以使用的情况下。 – RenniePet 2013-04-13 15:19:45

+0

这很好用!如果你想旋转90度,你应该使用bmp.RotateFlip(RotateFlipType.Rotate90FlipNone); – Oleg 2013-09-22 12:21:21

+2

这里完全有很多额外的努力。我们可以做到这一点,而不会将它膨胀到“位图”并回到“图像”。 'img.RotateFlip(RotateFlipType.Rotate270FlipNone);' – psyklopz 2015-06-09 16:57:40

5

我写了一个简单的旋转图像类。你所要做的就是在Degree中输入图像和旋转角度。角度必须在-90到+90之间。

public class ImageRotator 
{ 
    private readonly Bitmap image; 
    public Image OriginalImage 
    { 
     get { return image; } 
    } 


    private ImageRotator(Bitmap image) 
    { 
     this.image = image; 
    } 


    private double GetRadian(double degree) 
    { 
     return degree * Math.PI/(double)180; 
    } 


    private Size CalculateSize(double angle) 
    { 
     double radAngle = GetRadian(angle); 
     int width = (int)(image.Width * Math.Cos(radAngle) + image.Height * Math.Sin(radAngle)); 
     int height = (int)(image.Height * Math.Cos(radAngle) + image.Width * Math.Sin(radAngle)); 
     return new Size(width, height); 
    } 

    private PointF GetTopCoordinate(double radAngle) 
    { 
     Bitmap image = CurrentlyViewedMappedImage.BitmapImage; 
     double topX = 0; 
     double topY = 0; 

     if (radAngle > 0) 
     { 
      topX = image.Height * Math.Sin(radAngle); 
     } 
     if (radAngle < 0) 
     { 
      topY = image.Width * Math.Sin(-radAngle); 
     } 
     return new PointF((float)topX, (float)topY); 
    } 

    public Bitmap RotateImage(double angle) 
    { 
     SizeF size = CalculateSize(radAngle); 
     Bitmap rotatedBmp = new Bitmap((int)size.Width, (int)size.Height); 

     Graphics g = Graphics.FromImage(rotatedBmp); 
     g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; 
     g.CompositingQuality = CompositingQuality.HighQuality; 
     g.SmoothingMode = SmoothingMode.HighQuality; 
     g.PixelOffsetMode = PixelOffsetMode.HighQuality; 

     g.TranslateTransform(topPoint.X, topPoint.Y); 
     g.RotateTransform(GetDegree(radAngle)); 
     g.DrawImage(image, new RectangleF(0, 0, size.Width, size.Height)); 

     g.Dispose(); 
     return rotatedBmp; 
    } 


    public static class Builder 
    { 
     public static ImageRotator CreateInstance(Image image) 
     { 
      ImageRotator rotator = new ImageRotator(image as Bitmap); 
      return rotator; 
     } 
    } 
} 
+2

这不会编译 - 有两个未定义的变量和一个未定义的方法。 – RenniePet 2013-04-14 19:35:07

16

这是一个古老的线程,并有关于C#的WinForms图像旋转其他几个线程,但现在,我已经拿出我的解决方案我想这是一个很好的将它张贴任何地方。

/// <summary> 
    /// Method to rotate an Image object. The result can be one of three cases: 
    /// - upsizeOk = true: output image will be larger than the input, and no clipping occurs 
    /// - upsizeOk = false & clipOk = true: output same size as input, clipping occurs 
    /// - upsizeOk = false & clipOk = false: output same size as input, image reduced, no clipping 
    /// 
    /// A background color must be specified, and this color will fill the edges that are not 
    /// occupied by the rotated image. If color = transparent the output image will be 32-bit, 
    /// otherwise the output image will be 24-bit. 
    /// 
    /// Note that this method always returns a new Bitmap object, even if rotation is zero - in 
    /// which case the returned object is a clone of the input object. 
    /// </summary> 
    /// <param name="inputImage">input Image object, is not modified</param> 
    /// <param name="angleDegrees">angle of rotation, in degrees</param> 
    /// <param name="upsizeOk">see comments above</param> 
    /// <param name="clipOk">see comments above, not used if upsizeOk = true</param> 
    /// <param name="backgroundColor">color to fill exposed parts of the background</param> 
    /// <returns>new Bitmap object, may be larger than input image</returns> 
    public static Bitmap RotateImage(Image inputImage, float angleDegrees, bool upsizeOk, 
            bool clipOk, Color backgroundColor) 
    { 
    // Test for zero rotation and return a clone of the input image 
    if (angleDegrees == 0f) 
     return (Bitmap)inputImage.Clone(); 

    // Set up old and new image dimensions, assuming upsizing not wanted and clipping OK 
    int oldWidth = inputImage.Width; 
    int oldHeight = inputImage.Height; 
    int newWidth = oldWidth; 
    int newHeight = oldHeight; 
    float scaleFactor = 1f; 

    // If upsizing wanted or clipping not OK calculate the size of the resulting bitmap 
    if (upsizeOk || !clipOk) 
    { 
     double angleRadians = angleDegrees * Math.PI/180d; 

     double cos = Math.Abs(Math.Cos(angleRadians)); 
     double sin = Math.Abs(Math.Sin(angleRadians)); 
     newWidth = (int)Math.Round(oldWidth * cos + oldHeight * sin); 
     newHeight = (int)Math.Round(oldWidth * sin + oldHeight * cos); 
    } 

    // If upsizing not wanted and clipping not OK need a scaling factor 
    if (!upsizeOk && !clipOk) 
    { 
     scaleFactor = Math.Min((float)oldWidth/newWidth, (float)oldHeight/newHeight); 
     newWidth = oldWidth; 
     newHeight = oldHeight; 
    } 

    // Create the new bitmap object. If background color is transparent it must be 32-bit, 
    // otherwise 24-bit is good enough. 
    Bitmap newBitmap = new Bitmap(newWidth, newHeight, backgroundColor == Color.Transparent ? 
             PixelFormat.Format32bppArgb : PixelFormat.Format24bppRgb); 
    newBitmap.SetResolution(inputImage.HorizontalResolution, inputImage.VerticalResolution); 

    // Create the Graphics object that does the work 
    using (Graphics graphicsObject = Graphics.FromImage(newBitmap)) 
    { 
     graphicsObject.InterpolationMode = InterpolationMode.HighQualityBicubic; 
     graphicsObject.PixelOffsetMode = PixelOffsetMode.HighQuality; 
     graphicsObject.SmoothingMode = SmoothingMode.HighQuality; 

     // Fill in the specified background color if necessary 
     if (backgroundColor != Color.Transparent) 
      graphicsObject.Clear(backgroundColor); 

     // Set up the built-in transformation matrix to do the rotation and maybe scaling 
     graphicsObject.TranslateTransform(newWidth/2f, newHeight/2f); 

     if (scaleFactor != 1f) 
      graphicsObject.ScaleTransform(scaleFactor, scaleFactor); 

     graphicsObject.RotateTransform(angleDegrees); 
     graphicsObject.TranslateTransform(-oldWidth/2f, -oldHeight/2f); 

     // Draw the result 
     graphicsObject.DrawImage(inputImage, 0, 0); 
    } 

    return newBitmap; 
    } 

这是很多灵感来源的结果,在这里StackOverflow和其他地方。 Naveen在this thread上的回答特别有用。

+0

我一直在寻找的东西,有史以来最好的答案! – 2015-09-22 17:45:36

+0

我也在寻找一个好的C#图像旋转解决方案,并试用过这个:尽管它确实正确地旋转了图像,但它返回的图像周围有一个很大的空白区域。我明白,旋转的图像不一定具有相同的尺寸,但为什么它周围有一个空的边框?不幸的是,这些参数并没有帮助:我设置了clipOk = false和upsizeOk = true,然后我得到一个图像,其周围有一个很大的空白空间,如果我设置了upsizeOk = false,那么图像具有原始大小,但仍有一些边框原来没有一个...有关于此的任何想法? – 2015-11-25 19:06:25

+0

@ ab-tools:你确定你的输入图像在图像的可见部分周围没有额外的空间吗?这是一个可能的解释... – RenniePet 2015-11-25 20:19:20

3

旋转图像是一回事,在另一个图像边界合适。这是一个可以帮助任何人的代码。我早就基于互联网上的一些搜索创建了它。

/// <summary> 
    /// Rotates image in radian angle 
    /// </summary> 
    /// <param name="bmpSrc"></param> 
    /// <param name="theta">in radian</param> 
    /// <param name="extendedBitmapBackground">Because of rotation returned bitmap can have different boundaries from original bitmap. This color is used for filling extra space in bitmap</param> 
    /// <returns></returns> 
    public static Bitmap RotateImage(Bitmap bmpSrc, double theta, Color? extendedBitmapBackground = null) 
    { 
     theta = Convert.ToSingle(theta * 180/Math.PI); 
     Matrix mRotate = new Matrix(); 
     mRotate.Translate(bmpSrc.Width/-2, bmpSrc.Height/-2, MatrixOrder.Append); 
     mRotate.RotateAt((float)theta, new Point(0, 0), MatrixOrder.Append); 
     using (GraphicsPath gp = new GraphicsPath()) 
     { // transform image points by rotation matrix 
      gp.AddPolygon(new Point[] { new Point(0, 0), new Point(bmpSrc.Width, 0), new Point(0, bmpSrc.Height) }); 
      gp.Transform(mRotate); 
      PointF[] pts = gp.PathPoints; 

      // create destination bitmap sized to contain rotated source image 
      Rectangle bbox = BoundingBox(bmpSrc, mRotate); 
      Bitmap bmpDest = new Bitmap(bbox.Width, bbox.Height); 

      using (Graphics gDest = Graphics.FromImage(bmpDest)) 
      { 
       if (extendedBitmapBackground != null) 
       { 
        gDest.Clear(extendedBitmapBackground.Value); 
       } 
       // draw source into dest 
       Matrix mDest = new Matrix(); 
       mDest.Translate(bmpDest.Width/2, bmpDest.Height/2, MatrixOrder.Append); 
       gDest.Transform = mDest; 
       gDest.DrawImage(bmpSrc, pts); 
       return bmpDest; 
      } 
     } 
    } 


    private static Rectangle BoundingBox(Image img, Matrix matrix) 
    { 
     GraphicsUnit gu = new GraphicsUnit(); 
     Rectangle rImg = Rectangle.Round(img.GetBounds(ref gu)); 

     // Transform the four points of the image, to get the resized bounding box. 
     Point topLeft = new Point(rImg.Left, rImg.Top); 
     Point topRight = new Point(rImg.Right, rImg.Top); 
     Point bottomRight = new Point(rImg.Right, rImg.Bottom); 
     Point bottomLeft = new Point(rImg.Left, rImg.Bottom); 
     Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft }; 
     GraphicsPath gp = new GraphicsPath(points, new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line }); 
     gp.Transform(matrix); 
     return Rectangle.Round(gp.GetBounds()); 
    } 
1

老问题,但我不得不在接受的答案中解决MrFox的评论。当尺寸改变时旋转图像切断图像的边缘。一种解决方案是将原件重新绘制在中央的较大图像上,其中较大图像的尺寸补偿了不裁剪边缘的需要。例如,我希望能够以正常角度设计游戏的瓷砖,但是为了等轴测视图而以45度角重新绘制它们。

下面是示例图像(黄色边框使其更容易在此处看到)。

原始图像: water tile

在较大的图像的中心的瓦片: enter image description here

旋转后的图像(其中,您旋转较大的图像,而不是原始): enter image description here

该代码(部分基于this answer in another question):

private Bitmap RotateImage(Bitmap rotateMe, float angle) 
{ 
    //First, re-center the image in a larger image that has a margin/frame 
    //to compensate for the rotated image's increased size 

    var bmp = new Bitmap(rotateMe.Width + (rotateMe.Width/2), rotateMe.Height + (rotateMe.Height/2)); 

    using (Graphics g = Graphics.FromImage(bmp)) 
     g.DrawImageUnscaled(rotateMe, (rotateMe.Width/4), (rotateMe.Height/4), bmp.Width, bmp.Height); 

    bmp.Save("moved.png"); 
    rotateMe = bmp; 

    //Now, actually rotate the image 
    Bitmap rotatedImage = new Bitmap(rotateMe.Width, rotateMe.Height); 

    using (Graphics g = Graphics.FromImage(rotatedImage)) 
    { 
     g.TranslateTransform(rotateMe.Width/2, rotateMe.Height/2); //set the rotation point as the center into the matrix 
     g.RotateTransform(angle);          //rotate 
     g.TranslateTransform(-rotateMe.Width/2, -rotateMe.Height/2); //restore rotation point into the matrix 
     g.DrawImage(rotateMe, new Point(0, 0));       //draw the image on the new bitmap 
    } 

    rotatedImage.Save("rotated.png"); 
    return rotatedImage; 
} 
0

只要您要旋转的图像已经存在于您的Properties资源文件夹中,就会工作。

在分部类:

Bitmap bmp2; 

的OnLoad:

bmp2 = new Bitmap(Tycoon.Properties.Resources.save2); 
      pictureBox6.SizeMode = PictureBoxSizeMode.StretchImage; 
      pictureBox6.Image = bmp2; 

按钮或ONCLICK

private void pictureBox6_Click(object sender, EventArgs e) 
     { 
      if (bmp2 != null) 
      { 
       bmp2.RotateFlip(RotateFlipType.Rotate90FlipNone); 
       pictureBox6.Image = bmp2; 
      } 
     } 
0

您可以轻松地调用此方法做到这一点:

public static Bitmap RotateImage(Image image, float angle) 
{ 
    if (image == null) 
     throw new ArgumentNullException("image"); 

    PointF offset = new PointF((float)image.Width/2, (float)image.Height/2); 

    //create a new empty bitmap to hold rotated image 
    Bitmap rotatedBmp = new Bitmap(image.Width, image.Height); 
    rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution); 

    //make a graphics object from the empty bitmap 
    Graphics g = Graphics.FromImage(rotatedBmp); 

    //Put the rotation point in the center of the image 
    g.TranslateTransform(offset.X, offset.Y); 

    //rotate the image 
    g.RotateTransform(angle); 

    //move the image back 
    g.TranslateTransform(-offset.X, -offset.Y); 

    //draw passed in image onto graphics object 
    g.DrawImage(image, new PointF(0, 0)); 

    return rotatedBmp; 
} 

不要忘了在你的项目中添加对System.Drawing.dll程序参考

实例调用此方法的:

Image image = new Bitmap("waves.png"); 
Image newImage = RotateImage(image, 360); 
newImage.Save("newWaves.png");