2010-01-29 42 views
36

Tôi muốn có một ảnh trong ứng dụng mà tôi có thể xoay để chỉ đường, như hướng gió. Hoặc thậm chí là thời gian. Tôi sử dụng mã nào để xoay hình ảnh? Cảm ơnLàm cách nào để xoay ảnh trong WinForms

Cập nhật: Tôi đang sử dụng .NET 2.0, Windows 2000, VS C# 2005

+0

Bạn đang sử dụng WinForms hoặc WPF? – RandomEngy

+0

Không phải WPF, tôi không nghĩ rằng winforms. –

+2

Nếu bạn không sử dụng WPF (với các tệp .xaml và tương tự) và bạn đang phát triển giao diện người dùng trong C# trong Visual Studio, bạn đang phát triển trong WinForms. Nó ngắn cho Windows Forms. – RandomEngy

Trả lời

31

Dưới đây là một phương pháp bạn có thể sử dụng để xoay một hình ảnh trong 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

bạn đã thử mã này chưa? nó không hoạt động đúng cách –

+0

Đẹp, thực hiện nhỏ gọn. – TheBlastOne

+6

Hình ảnh được xoay có thể lớn hơn ảnh gốc, nếu bạn xoay từ 0 đến 90 độ, nói 45 độ nó chảy qua các cạnh, bạn phải nhường chỗ cho điều này. – MrFox

5

Tôi thấy điều này 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

phương pháp đơn giản:

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

Um, tại sao tạo đối tượng Graphics và sử dụng nó để xóa và vẽ lại đối tượng Bitmap? Điều đó không cần thiết phải không? Mã dường như hoạt động tốt mà không có điều đó, ít nhất là đối với các tình huống mà Bitmap.RotateFlip() có thể được sử dụng. – RenniePet

+0

Điều đó hoạt động tuyệt vời! Nếu bạn muốn xoay 90 độ, bạn nên sử dụng bmp.RotateFlip (RotateFlipType.Rotate90FlipNone); – Oleg

+2

Hoàn toàn có thêm nhiều nỗ lực ở đây. Chúng ta có thể làm điều này mà không làm tăng nó lên một 'Bitmap' và quay lại một' Image'. 'img.RotateFlip (RotateFlipType.Rotate270FlipNone);' – psyklopz

5

Tôi đã viết một lớp đơn giản để xoay hình ảnh. Tất cả bạn phải làm là hình ảnh đầu vào và góc quay trong độ. Góc phải nằm trong khoảng từ -90 đến +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

Điều này không biên dịch - có hai biến không xác định và một phương thức không xác định. – RenniePet

16

Đây là một chủ đề cũ, và có một số chủ đề khác về C# WinForms ảnh xoay vòng, nhưng bây giờ mà tôi đã đưa ra giải pháp của tôi, tôi con số này là tốt một nơi để gửi nó như bất kỳ.

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

Đây là kết quả của nhiều nguồn cảm hứng, tại đây tại StackOverflow và các nơi khác. Câu trả lời của Naveen trên this thread đặc biệt hữu ích.

+0

Điều tương tự với những gì tôi đang tìm kiếm, Câu trả lời hay nhất từ ​​trước tới nay! –

+0

Tôi cũng đang tìm kiếm giải pháp xoay hình ảnh C# tốt và đã thử giải pháp này: mặc dù nó xoay hình ảnh chính xác nhưng nó trả về một hình ảnh có khoảng trống lớn xung quanh nó. Tôi hiểu rằng một hình ảnh xoay không nhất thiết phải có cùng kích thước nữa, nhưng tại sao có một đường viền trống xung quanh nó? Các thông số không may: tôi đặt clipOk = false và upsizeOk = true, sau đó tôi nhận được hình ảnh có khoảng trống lớn xung quanh và nếu tôi đặt upsizeOk = false thì ảnh có kích thước gốc nhưng vẫn có một số đường viền nơi bản gốc không có ... Bất cứ ý tưởng nào về điều đó? –

+0

@ ab-tools: Bạn có chắc chắn rằng hình ảnh đầu vào của bạn không có thêm khoảng trống xung quanh phần hiển thị của hình ảnh? Đó là một lời giải thích có thể ... – RenniePet

2

Richard Cox có giải pháp tốt cho điều này https://stackoverflow.com/a/5200280/1171321 Tôi đã sử dụng trong quá khứ. Nó cũng đáng chú ý là DPI phải 96 để làm việc này một cách chính xác. Một số giải pháp trên trang này không hoạt động.

3

Xoay hình ảnh là một thứ, ranh giới hình ảnh thích hợp trong một hình ảnh khác. Đây là một mã có thể giúp bất cứ ai. Tôi tạo ra điều này dựa trên một số tìm kiếm trên internet từ lâu.

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

Câu hỏi cũ nhưng tôi phải giải quyết nhận xét của MrFox trong câu trả lời được chấp nhận. Xoay hình ảnh khi kích thước thay đổi cắt các cạnh của hình ảnh. Một giải pháp là vẽ lại bản gốc trên một hình ảnh lớn hơn, ở giữa, nơi kích thước của hình ảnh lớn hơn bù đắp cho nhu cầu không cắt các cạnh. Ví dụ, tôi muốn có thể thiết kế gạch của trò chơi ở một góc bình thường nhưng vẽ lại chúng ở một góc 45 độ cho một góc nhìn đẳng động.

Dưới đây là hình ảnh ví dụ (đường viền màu vàng giúp bạn dễ dàng xem ở đây).

Những hình ảnh ban đầu: water tile

Các ngói làm trung tâm trong một hình ảnh lớn hơn: enter image description here

Hình ảnh xoay (nơi bạn xoay hình ảnh lớn hơn, không phải là bản gốc): enter image description here

Mã (dựa trên một phần trên 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

Điều này sẽ hoạt động miễn là hình ảnh bạn muốn xoay đã có trong thư mục Tài nguyên thuộc tính của bạn.

Trong lớp từng phần:

Bitmap bmp2; 

onload:

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

Nút hoặc onclick

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

Bạn có thể dễ dàng làm điều đó bằng cách gọi phương pháp này:

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

đừng quên để thêm một tham chiếu đến System.Drawing.dll vào dự án của bạn

Ví dụ về cuộc gọi phương pháp này:

Image image = new Bitmap("waves.png"); 
Image newImage = RotateImage(image, 360); 
newImage.Save("newWaves.png"); 
Các vấn đề liên quan