如何在WinForms中旋转图片
我想在我的应用程序中有一张照片,可以旋转指示风向等方向。 甚至是时间。 我用什么代码来旋转图片? 谢谢
更新:我使用.NET 2.0,Windows 2000,VS C#2005
下面是一个可以用来在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; }
简单的方法:
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; }
这是一个旧的线程,还有几个关于C#WinForms图像旋转的其他线程,但现在我已经提出了我的解决scheme,我认为这是一个很好的地方张贴任何。
/// <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和其他地方。 纳文在这个post上的回答特别有帮助。
我发现这篇文章
/// <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; }
我已经写了一个简单的类来旋转图像。 所有你需要做的是在度数input图像和旋转angular度。 angular度必须在-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; } } }
旋转图像是一回事,在另一个适当的图像边界。 这是一个可以帮助任何人的代码。 我早就基于互联网上的一些search创build了这个。
/// <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()); }
理查德·考克斯有一个很好的解决scheme,这个我以前使用的https://stackoverflow.com/a/5200280/1171321 。 还值得注意的是,DPI必须是96才能正常工作。 这个网页上的几个解决scheme根本不起作用。
老问题,但我必须在接受的答案中解决MrFox的评论。 当尺寸改变时旋转图像切断图像的边缘。 一种解决scheme是在较大的图像上重新绘制原始图像,其中较大图像的尺寸补偿了不裁剪边缘的需要。 例如,我希望能够以正常的angular度devise游戏的瓷砖,但是为了等轴测视图而以45度angular重新绘制它们。
这里是示例图像(黄色的边框是为了更容易看到这里)。
原始图像:
在更大的图像中居中的瓷砖:
旋转的图像(您旋转较大的图像,而不是原来的):
代码( 在另一个问题中部分基于这个答案 ):
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; }
只要你要旋转的图像已经在你的属性资源文件夹中,这将工作。
在部分类中:
Bitmap bmp2;
负载:
bmp2 = new Bitmap(Tycoon.Properties.Resources.save2); pictureBox6.SizeMode = PictureBoxSizeMode.StretchImage; pictureBox6.Image = bmp2;
button或Onclick
private void pictureBox6_Click(object sender, EventArgs e) { if (bmp2 != null) { bmp2.RotateFlip(RotateFlipType.Rotate90FlipNone); pictureBox6.Image = bmp2; } }
您可以通过调用此方法轻松完成此操作:
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");