14

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

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

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

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

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

我发现几乎像我想要的那样工作的功能是:

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

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

知道我该怎么做吗?

答案 我在这里找到了适用于我的图像的解决方案,该解决方案的分辨率为300

4

2 回答 2

36

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

在此处输入图像描述

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

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 弧度)

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

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

于 2013-01-06T17:50:15.523 回答
1

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

代码中有两个小错误

a) 模数后的第一次检查应该一分为二,或者改为例如

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

于 2016-01-18T00:58:43.307 回答