【问题标题】:How to rotate image x degrees in c#?如何在c#中将图像旋转x度?
【发布时间】:2012-12-20 12:26:18
【问题描述】:

我已经进行了一些搜索,但我找不到任何可以做我想做的事情的功能。

我有一个带有文本的扫描文档的图像文件,但该文档旋转了一些度数,所以我想旋转它以使文本彼此内联。

在一个完美的世界中,它应该是一个自动执行此操作的功能,但我找不到任何东西,我知道要让它自动工作,它需要对图像进行一些分析,我认为这是一件大事。

但后来我做了一个工具来手动旋转网站上的图像,但现在我需要一个函数来将旋转保存到图像文件中。

这似乎是一些不同的方法,但我测试过的人没有做我想做的事。

我发现的功能几乎和我想要的一样:

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

但这不会改变图像文件的高度和宽度,因此图像文件大小相同,但图像“对象”已被缩放和旋转。

知道我该怎么做吗?

回答 我在old answer here 找到了适用于我的图像的解决方案,该解决方案的分辨率为 300。

【问题讨论】:

标签: c# image graphics drawing


【解决方案1】:

如果我正确理解了您的问题,您基本上想计算出图像旋转后的新尺寸,以及如何在新位图中定位旋转后的图像。

该图有望帮助阐明解决方案。下面是一段伪代码:

sinVal = abs(sin(angle))
cosVal = abs(cos(angle))
newImgWidth = sinVal * oldImgHeight + cosVal * oldImgWidth
newImgHeight = sinVal * oldImgWidth + cosVal * oldImgHeight
originX = 0
originY = sinVal * oldImgWidth

你想从 newImgWidth 和 newImgHeight 制作新图像,然后围绕原点(originX,originY)执行旋转,然后将图像渲染到该点。如果角度(以度为单位)不在 -90 度和 0 度之间(如图所示),这将翻倒。如果它在 0 到 90 度之间,那么你只需改变原点:

originX = sinVal * oldImgHeight
originY = 0

如果它在 90 度到 270 度(-90 度)的范围内,那就有点小技巧了(参见下面的示例代码)。

您的代码已重新编写(经过简单测试) - 它有点不可靠,但似乎可以工作:

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

注意三角函数的度数到弧度的转换(180 度 == Pi 弧度)

编辑:大问题是负 sin 值,我在计算原点 x/y 时对宽度/高度感到困惑 - 现在应该可以正常工作(经过测试)

编辑:修改代码以处理任何角度

【讨论】:

  • 在我自己的答案中查看我的函数结果。
  • @RickardP 你能再试一次吗,我犯了两个愚蠢的错误,现在它可以工作了(我愚蠢地测试了它是一个接近方形的图像,这没有帮助!)
  • 最新代码的结果相同,是不是我的角度值有误?你看重什么?示例我从我的 jquery 插件中得到,我应该将它旋转 3.5 度或 -3.5 度,这就是我作为值发送的内容,这是错误的吗?
  • 新代码将采用任何角度(度),我一直在观察它在我的计算机上旋转(和工作)。我会确保有效的代码是相同的,以防我错误地复制出来。您的代码到底有什么问题?
  • Okej,发现这个功能和 VisualMelon 几乎一样,但有一些变化,它适用于我的大分辨率,请参阅stackoverflow.com/a/4320581/553770
【解决方案2】:

这严格来说是对上面 VisualMelon 的好答案的评论,但我不允许添加 cmets...

代码中有两个小错误

a) 模数后的第一个检查要么一分为二,要么改为 e.g.

if (180<Math.Abs(angle)) angle -= 360*Math.Sign(angle);

否则 -360 到 -180 之间的角度将失败,因为只处理 +180 到 +360

b) 在 newImg 分配之后,缺少分辨率分配,例如

newImg.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);

如果省略,如果源不是 96 dpi,图像将被缩放。

....和拆分棒,尺寸和偏移量的中间计算应该保持在double,最后只减少到float

【讨论】:

  • 谢谢,这些都是很好的 cmets,我的答案中的代码在任何层面上都不是很好,正如 RickardP 在评论中提到的那样,这个答案是代码的更实用的版本:@987654321 @。有一天我可能会清理我的答案,我认为代码的目的更多是为了证明基本的数学是有效的,而不是提供一个好的参考!
猜你喜欢
  • 2014-07-05
  • 2012-11-08
  • 2015-07-04
  • 1970-01-01
  • 2011-06-08
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
相关资源
最近更新 更多