Вращение изображения c#

101
18 ноября 2021, 22:20

Всем привет, Сразу к делу : Моя задача вращать картинку в pictureBox (есть ракета, она должна плавно отклоняться на угол от -30° до 30° в зависимости от значения переменной причем вращение должно происходить вокруг заданной мною точки на данный момент у меня есть этот код, который работает не совсем правильно

  public partial class Form1 : Form
{
    private static System.Timers.Timer aTimer;
    public Image img = Image.FromFile(Application.StartupPath.ToString() + @"\image\Rocket1.png");
    public float rotationAngle;
    public Bitmap bmp;
    public Form1()
    {  
        InitializeComponent();
        pictureBox1.Image = img;
        aTimer = new System.Timers.Timer(100);
        aTimer.Elapsed += OnTimedEvent;
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
        int sizeWith = img.Size.Width;
        int sizeHeight = img.Size.Height;
        bmp = new Bitmap(pictureBox1.Image, new Size(sizeWith, sizeHeight));
    }
    public void OnTimedEvent(Object source, ElapsedEventArgs e)
    { 
        rotationAngle = rotationAngle + 1;
        RotateImage(img, rotationAngle);
    }
    public void RotateImage(Image img, float rotationAngle)
    {
        using (Graphics gfx = Graphics.FromImage(bmp))
        {
            gfx.TranslateTransform((float)bmp.Width, (float)bmp.Height);
            gfx.RotateTransform(rotationAngle);
            gfx.TranslateTransform(-(float)bmp.Width, -(float)bmp.Height);
            gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
            gfx.DrawImage(bmp, new Point(0, 0));
            gfx.Dispose();    
            pictureBox1.Image = bmp;
        }
    }

после всех этих махинаций у меня получается следующее

Вопрос, как исправить все это

Answer 1

Подозреваю, что проблема в том, что вы рисуете на одном и том же Image => каждые поворот накладывается на предыдущий и вы получаете вот такой эффект.

Как вариант, создавайте новый Image и на нем отрисовывайте повернутое изображение.

Т.е у вас должно быть 2 Bitmap'а:

  1. Bitmap, который хранит текущую повернутую картинку, которая в данный момент отображается
  2. Чистый Bitmap на котором вы довернули до нового угла старый Bitmap.

После доворота, выставляете в Control новый Bitmap, а про старый забываете, вызвав Dispose().

P.S В gfx.Dispose(); нету смысла, так как using это сам сделает.

Answer 2

Вообщем скидываю решение, всем кто помогал спасибо

  protected override void OnPaint(PaintEventArgs e)
    {
        using (Bitmap clone = (Bitmap)pictureBox1.Image.Clone()) 
        {
            using (Graphics gfx = Graphics.FromImage(clone))
            {
                gfx.Clear(Color.Transparent);
                gfx.TranslateTransform(pictureBox1.Image.Width / 2, pictureBox1.Image.Height / 2);
                gfx.RotateTransform(rotationAngle);
                gfx.DrawImage(pictureBox1.Image, -pictureBox1.Image.Width / 2, -pictureBox1.Image.Height / 2);
            }
            pictureBox1.Image = (Bitmap)clone.Clone();
        }
    }

вызов метода происходит с помощью

Invalidate();

Еще есть вот такая вот переменная(путь к картинке которую мы собираемся вращать)

 public Image img = Image.FromFile(Application.StartupPath.ToString() + @"\image\Rocket1.png");

которую мы в начале скрипта записываем в

   pictureBox1.Image = img;

данный метод вращает изображение на заданный вами угол т.е. если переменная rotationAngle = 30, то результат будет следующим:

Сразу скажу что при повороте изображение теряет качество

чем больше вы его раз повернете тем хуже качество, пока решение этой проблемы не нашел( скорее всего качество теряется из-за того что мы поворачиваем уже повернутый объект,поэтому со временем картинка начинает терять качество, если при каждом повороте брать нашу начальную картинку, то я думаю потери качества можно избежать) надеюсь понятно и дословно объяснил.

Answer 3

Напишем простой контрол для вашего случая:

public sealed class RotatableImage : Control
{
    private Bitmap _bitmap;
    private float _angle;
    public Bitmap Bitmap
    {
        get { return _bitmap; }
        set
        {
            _bitmap = value;
            if (_bitmap is null)
            {
                return;
            }
            Invalidate(); // для вызова метода отрисовки OnPaint(...).
        }
    }
    public float Angle
    {
        get { return _angle; }
        set
        {
            _angle = value;
            if (_bitmap is null)
            {
                return;
            }
            Invalidate(); // для вызова метода отрисовки OnPaint(...).
        }
    }
    protected override void Dispose(bool disposing)
    {
        Bitmap?.Dispose();
        if (disposing)
        {
            Bitmap = null;
            Angle = .0f;
        }
        base.Dispose(disposing);
    }
    public RotatableImage()
    {
        DoubleBuffered = true; // что бы не было мерцаний.
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.Clear(BackColor); // можно изменить на любой другой, я использую фоновый цвет.
        if (Bitmap is null)
        {
            base.OnPaint(e);
            return;
        }
        e.Graphics.TranslateTransform(Bitmap.Width + .0f, Bitmap.Height + .0f);
        e.Graphics.RotateTransform(Angle);
        e.Graphics.TranslateTransform(-Bitmap.Width + .0f, -Bitmap.Height + .0f);
        e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        e.Graphics.DrawImage(Bitmap, new Point(0, 0));
        base.OnPaint(e);
    }
}

Нажмите Ctrl+Shift+B, добавьте новый контрол на форму.

Далее, определимся как будем загружать изображение, в моем примере, я его загружаю при помощи кнопки:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        // привязываемся к изменению позиции трекбара, и передаем его в `RotatbleImage`
        RotatableImage.DataBindings.Add
        (
            new Binding("Angle", AngleTrackBar, "Value")
        );
        OpenBtn.Click += OpenBtnOnClick;
    }
    private void OpenBtnOnClick(object sender, EventArgs e)
    {
        using (OpenFileDialog ofd = new OpenFileDialog())
        {
            if (ofd.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            try
            {
                RotatableImage.Bitmap = new Bitmap(ofd.FileName);
            }
            catch (FileNotFoundException fileNotFoundException)
            {
                RotatableImage.Bitmap = null;
                MessageBox.Show
                (
                    fileNotFoundException.Message,
                    Resources.FileNotFoundCaption,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error
                );
            }
        }
    }
}

Запускаем приложение, открываем изображение, двигаем трекбар.

Результат:

P.S. Зеленый фон... Баг программы записи.

Answer 4

Вот рабочий метод только image мерцает

 PaintEventArgs p = new PaintEventArgs(pictureBox1.CreateGraphics(), pictureBox1.Bounds); //Компонент на котором нужно рисовать и область на которой нужно рисовать
 Rotate(sender, p);

с помощью данного кода мы запускаем наш метод

 public void Rotate(object sender, PaintEventArgs e)
    {     
        Bitmap bitmap = new Bitmap(img, img.Width, img.Height); // создаем новый битмап
        e.Graphics.Clear(Color.Transparent); // трем старый рисунок
        e.Graphics.TranslateTransform(bitmap.Width /2 , bitmap.Height + 200); // перемещение в picturebox
        e.Graphics.RotateTransform(Convert.ToInt32(RotationAngle / 1.5)); // угол вращения (Переменная RotationAngle)
        e.Graphics.TranslateTransform(-bitmap.Width/ 2, -bitmap.Height - 200); // задаем точку вокруг которой осуществляется вращение
        e.Graphics.DrawImage(bitmap, bitmap.Width / 6, bitmap.Height / 6);     // проецируем изображение
    }

а это сам метод

READ ALSO
Работа с mysql c#

Работа с mysql c#

ПодскажитеЯ кодил в большинстве случаях на php и в основном на yii2

194
Обработка событий в MVVM

Обработка событий в MVVM

Моя цель - обработать событие загрузки приложения, при этом применяя паттерн MVVM

184
Установка image через Uri Xamain

Установка image через Uri Xamain

Есть приложение написанное на C# Xamarin (Android, IOS)Необходимо показывать изображение которое распологается на сайте

140
Сессия для языкового переключателя

Сессия для языкового переключателя

Доброго времени суток Сделал языковой переключатель и вот такую логику от которой подключая языковые пакеты и отображаю на выбранном языке...

69