Подтвердить что ты не робот

Как повернуть изображение x градусов в С#?

Я сделал несколько поисков, и я не могу найти какую-либо функцию, которая делает то, что я хочу, чтобы сделать это.

У меня есть файл изображения отсканированного документа с текстом, но документ повернут на несколько градусов, поэтому я хочу его повернуть, чтобы текст был встроен друг в друга.

В идеальном мире его должна быть функция, выполняющая это автоматически, но я не могу найти что-либо и то, что я понимаю, чтобы заставить его работать автоматически, чтобы он был каким-то анализом изображения, и я думаю, что это большая вещь. /p >

Но затем я сделал инструмент для поворота изображения на веб-сайте вручную, но теперь мне нужна функция, чтобы сохранить поворот в файл изображения.

Кажется, что это несколько разных методов, но никто не проверял, что я хочу.

Функция я обнаружила, что работает почти так, как я хочу:

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 на старом ответе здесь.

4b9b3361

Ответ 1

Если я правильно понял ваш вопрос, вы, по сути, хотите выработать новый размер изображения, когда он повернут, и как поместить повернутое изображение в него новым растровым изображением.

enter image description here

Диаграмма, надеюсь, поможет прояснить решение. Вот несколько псевдокодов:

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 Radians) для функций триггера

Изменить: большой проблемой были отрицательные значения sin, и я получаю ширину/высоту путаницы при вычислении начала x/y - теперь это должно работать нормально (проверено)

Изменить: измененный код для обработки любого угла

Ответ 2

Это строго комментарий к приятному ответу 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.

.... И расщепляющие палочки, промежуточные вычисления размеров и смещений должны храниться в два раза и только сводиться к поплавке последнего