如何在c#中旋转图像x度?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14184700/
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 to rotate image x degrees in c#?
提问by RickardP
I have done some searching and i can not find any function thats doing what i whant it todo.
我已经做了一些搜索,但我找不到任何正在做我想做的事情的功能。
I have a image file of a scanned document with text, but the document is some degrees rotated so i whant to rotate it so the text being inline with each other.
我有一个带有文本的扫描文档的图像文件,但是该文档旋转了一些度数,所以我想旋转它以使文本彼此内联。
In a perfect world its should be a function doing this automaticly but i can not find anything and what i understand to get it to work automaticly its needed to be some analyze of the image and i think its to big thing todo.
在一个完美的世界中,它应该是一个自动执行此操作的功能,但我找不到任何东西以及我所理解的让它自动工作的内容,它需要对图像进行一些分析,我认为这是一件大事。
But then i have done a tool to rotate the image on a website manually, but now i need a function to save the rotation to the image file.
但是后来我做了一个工具来手动旋转网站上的图像,但现在我需要一个函数来将旋转保存到图像文件中。
This seems to be some differents methods for but no one i tested doing what i whant.
这似乎是一些不同的方法,但我没有测试过我想做的事情。
The function i have finded that works almost like i whant is:
我发现的功能几乎就像我想要的一样:
public static Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor) {
int w = bmp.Width;
int h = bmp.Height;
PixelFormat pf = default(PixelFormat);
if (bkColor == Color.Transparent)
{
pf = PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tempImg = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tempImg);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
//Using System.Drawing.Drawing2D.Matrix class
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tempImg, 0, 0);
g.Dispose();
tempImg.Dispose();
return newImg; }
But this do not change the height and width of the image file so the image file is in the same size but the image "object" has been scaled and rotated.
但这不会改变图像文件的高度和宽度,因此图像文件的大小相同,但图像“对象”已被缩放和旋转。
Any idea how i can do this good?
知道我怎么能做到这一点吗?
AnswerI find the solution that worked with my image that has a resolution on 300 at a old answer here.
采纳答案by VisualMelon
If I've understood your question correctly, you essentially want to work out the new size of an image once rotated, and how to position the rotated image in it's new bitmap.
如果我正确理解了您的问题,您基本上想计算旋转后图像的新大小,以及如何在新位图中定位旋转图像。
The diagram hopefully helps make clear the solution. Here is a bit of pseudo code:
该图希望有助于明确解决方案。下面是一段伪代码:
sinVal = abs(sin(angle))
cosVal = abs(cos(angle))
newImgWidth = sinVal * oldImgHeight + cosVal * oldImgWidth
newImgHeight = sinVal * oldImgWidth + cosVal * oldImgHeight
originX = 0
originY = sinVal * oldImgWidth
You want to make the new image from the newImgWidth and newImgHeight, and then perform a rotation around the origin (originX, originY) and then render the image to this point. This will fall over if the angle (in degrees) isn't between -90 and 0 degrees (depicted). If it is between 0 and 90 degrees, then you just change the origin:
你想从newImgWidth和newImgHeight制作新的图像,然后绕原点(originX,originY)进行旋转,然后将图像渲染到这一点。如果角度(以度为单位)不在 -90 和 0 度之间(如图所示),这将倒塌。如果它在 0 到 90 度之间,那么您只需更改原点:
originX = sinVal * oldImgHeight
originY = 0
If it is in the range 90 degrees to 270 degrees (-90 degrees) then it is a little tricker (see example code below).
如果它在 90 度到 270 度(-90 度)的范围内,那么它就是一个小技巧(参见下面的示例代码)。
Your code re-written (briefly tested) - it is slightly dodgy but seems to work:
您的代码重写(简要测试) - 它有点狡猾但似乎有效:
public static Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
{
angle = angle % 360;
if (angle > 180)
angle -= 360;
System.Drawing.Imaging.PixelFormat pf = default(System.Drawing.Imaging.PixelFormat);
if (bkColor == Color.Transparent)
{
pf = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
float sin = (float)Math.Abs(Math.Sin(angle * Math.PI / 180.0)); // this function takes radians
float cos = (float)Math.Abs(Math.Cos(angle * Math.PI / 180.0)); // this one too
float newImgWidth = sin * bmp.Height + cos * bmp.Width;
float newImgHeight = sin * bmp.Width + cos * bmp.Height;
float originX = 0f;
float originY = 0f;
if (angle > 0)
{
if (angle <= 90)
originX = sin * bmp.Height;
else
{
originX = newImgWidth;
originY = newImgHeight - sin * bmp.Width;
}
}
else
{
if (angle >= -90)
originY = sin * bmp.Width;
else
{
originX = newImgWidth - sin * bmp.Height;
originY = newImgHeight;
}
}
Bitmap newImg = new Bitmap((int)newImgWidth, (int)newImgHeight, pf);
Graphics g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(originX, originY); // offset the origin to our calculated values
g.RotateTransform(angle); // set up rotate
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(bmp, 0, 0); // draw the image at 0, 0
g.Dispose();
return newImg;
}
Note the Degrees to Radians Conversion (180 Degrees == Pi Radians) for the trig functions
注意三角函数的弧度转换(180 度 == Pi 弧度)
Edit: big issue was negative sin values, and me getting width/height confused when calculating origin x/y - this should work fine now (tested)
编辑:大问题是负 sin 值,我在计算原点 x/y 时对宽度/高度感到困惑 - 现在应该可以正常工作(已测试)
Edit: modified code to handle any angle
编辑:修改代码以处理任何角度
回答by Eske Rahn
This is strictly a comment to the nice answer by VisualMelon above, But I'm not allowed to add comments...
这严格是对上面 VisualMelon 的好答案的评论,但我不允许添加评论......
There are two tiny bugs in the code
代码中有两个小错误
a) The first check after the modulus should either be split into two, or changed to e.g.
a) 模数之后的第一次检查应该一分为二,或者改为例如
if (180<Math.Abs(angle)) angle -= 360*Math.Sign(angle);
Otherwise angles between -360 and -180 will fail, as only +180 to +360 were handled
否则 -360 和 -180 之间的角度将失败,因为只处理了 +180 到 +360
b) Just after the newImg assignment, a resolution assignment is missing, e.g.
b) 就在 newImg 赋值之后,缺少解析赋值,例如
newImg.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
If omitted the image will be scaled if the source is not 96 dpi.
如果省略,如果源不是 96 dpi,图像将被缩放。
....And splitting sticks, the intermediate calculations of dimensions and offsets ought to be kept in double, and only reduced to float last
....和分裂棒,尺寸和偏移量的中间计算应该保持双倍,并且只减少到最后浮动