C# 如何在 WinForms 中旋转图片
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2163829/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I rotate a picture in WinForms
提问by Arlen Beiler
I want to have one picture in my application that I can rotate to indicate directions, like wind direction. Or even the time. What code do I use to rotate the picture? Thanks
我想在我的应用程序中有一张图片,我可以旋转它来指示方向,比如风向。甚至时间。我用什么代码来旋转图片?谢谢
Update: I am using .NET 2.0, Windows 2000, VS C# 2005
更新:我正在使用 .NET 2.0、Windows 2000、VS C# 2005
采纳答案by Tony The Lion
Here's a method you can use to rotate an image in C#:
这是一种可用于在 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;
}
回答by Timeless
I found this 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;
}
回答by net_prog
Simple method:
简单方法:
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;
}
回答by user
I've written a simple class for rotating image. All you've to do is input image and angle of rotation in Degree. Angle must be between -90 and +90.
我写了一个简单的类来旋转图像。您所要做的就是以度数输入图像和旋转角度。角度必须在 -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;
}
}
}
回答by RenniePet
This is an old thread, and there are several other threads about C# WinForms image rotation, but now that I've come up with my solution I figure this is as good a place to post it as any.
这是一个旧线程,还有其他几个关于 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;
}
This is the result of many sources of inspiration, here at StackOverflow and elsewhere. Naveen's answer on this threadwas especially helpful.
这是 StackOverflow 和其他地方许多灵感来源的结果。Naveen 在这个线程上的回答特别有帮助。
回答by Particleman
Richard Cox has a good solution to this https://stackoverflow.com/a/5200280/1171321I have used in the past. It is also worth noting the DPI must be 96 for this to work correctly. Several of the solutions on this page do not work at all.
理查德考克斯有一个很好的解决方案https://stackoverflow.com/a/5200280/1171321我过去使用过。还值得注意的是 DPI 必须为 96 才能正常工作。此页面上的几个解决方案根本不起作用。
回答by user2126375
Rotating image is one thing, proper image boundaries in another. Here is a code which can help anyone. I created this based on some search on internet long ago.
旋转图像是一回事,适当的图像边界是另一回事。这是一个可以帮助任何人的代码。我很久以前根据互联网上的一些搜索创建了这个。
/// <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());
}
回答by sraboy
Old question but I had to address MrFox's comment in the accepted answer. Rotating an image when the size changes cuts off the edges of the image. One solution is to redraw the original on a larger image, centered, where the larger image's dimensions compensate for the need of not clipping the edges. For example, I wanted to be able to design a game's tiles at a normal angle but re-draw them at a 45-degree angle for an isometric view.
老问题,但我不得不在接受的答案中解决 MrFox 的评论。当尺寸改变时旋转图像会切断图像的边缘。一种解决方案是在较大的图像上重绘原始图像,居中,其中较大图像的尺寸补偿了不剪裁边缘的需要。例如,我希望能够以正常角度设计游戏的瓷砖,但以 45 度角重新绘制它们以获得等距视图。
Here are example images (yellow borders are to make it easier to see here).
这是示例图像(黄色边框是为了更容易在此处查看)。
The centered tile in a larger image:
The rotated image (where you rotate the larger image, not the original):
The code (based in part on 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;
}
回答by Vpnm
This will work as long as the image you want to rotate is already in your Properties resources folder.
只要您要旋转的图像已经在您的属性资源文件夹中,这就会起作用。
In Partial Class:
在部分课程中:
Bitmap bmp2;
OnLoad:
负载:
bmp2 = new Bitmap(Tycoon.Properties.Resources.save2);
pictureBox6.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox6.Image = bmp2;
Button or Onclick
按钮或点击
private void pictureBox6_Click(object sender, EventArgs e)
{
if (bmp2 != null)
{
bmp2.RotateFlip(RotateFlipType.Rotate90FlipNone);
pictureBox6.Image = bmp2;
}
}
回答by Mehdi Souregi
You can easily do it by calling this method :
您可以通过调用此方法轻松完成:
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;
}
don't forget to add a reference to System.Drawing.dll on your project
不要忘记在您的项目中添加对 System.Drawing.dll 的引用
Example of this method call :
此方法调用的示例:
Image image = new Bitmap("waves.png");
Image newImage = RotateImage(image, 360);
newImage.Save("newWaves.png");