Как отменить операцию рисования с помощью C # - PullRequest
1 голос
/ 28 июня 2011

У меня есть изображение, загруженное в picturebox. Я выполняю операцию рисования на изображении с помощью события mouseclick. Оно закрашивает небольшую прямоугольную область черным цветом при щелчке мышью в этой точке. отменить операцию для этого. Когда я нажимаю кнопку, последняя операция рисования должна быть отменена. Вот мой код для операции рисования ..

      private void pictureBox1_MouseClick(object sender, MouseEventArgs e)
    {

            rect.Width = 0;
            rect.Height = 0;
            pictureBox1.Invalidate();


            int radius = 10; //Set the number of pixel you want to use here
            //Calculate the numbers based on radius
            int x0 = Math.Max(e.X - (radius / 2), 0),
                y0 = Math.Max(e.Y - (radius / 2), 0),
                x1 = Math.Min(e.X + (radius / 2), pictureBox1.Width),
                y1 = Math.Min(e.Y + (radius / 2), pictureBox1.Height);
            Bitmap bm = pictureBox1.Image as Bitmap; //Get the bitmap (assuming it is stored that way)
            for (int ix = x0; ix < x1; ix++)
            {
                for (int iy = y0; iy < y1; iy++)
                {
                    bm.SetPixel(ix, iy, Color.Black); //Change the pixel color, maybe should be relative to bitmap
                }
            }
            pictureBox1.Refresh(); //Force refresh
          }

Любой, пожалуйста, помогите мне, как я могу отменить последнюю выполненную операцию.

Ответы [ 3 ]

5 голосов
/ 28 июня 2011

Поскольку вы работаете с растровым изображением в памяти, вы не можете просто отменить операцию.Для этого может быть несколько решений:

  1. Сохраняйте исходное изображение в памяти и для каждой операции сохраняйте параметры рисования: что было нарисовано, где, каким цветом.Когда вам понадобится отменить, вам просто нужно будет повторить все операции с первого до последнего (у вас также могут быть контрольные точки, где вы храните промежуточное изображение)
  2. После каждой операции сохраняйте снимок изображения- это будет очень занимать память.Отменить - восстановить предыдущее изображение в списке.
  3. Сохранять измененные пиксели - при каждой операции анализировать предыдущее и новое изображение и сохранять изменения пикселей.Вы сможете вернуться к предыдущему, скопировав эти пиксели обратно.
1 голос
/ 28 июня 2011

Вы можете объявить частное поле изображения и сохранить в нем состояние изображения для использования в откатах, используя Шаблон дизайна Memento для сохранения и загрузки состояния «изображение» объекта - это лучшая практика..

Однако вместо одной операции отмены / возврата лучшим решением является реализация стратегии multi-undo / redo следующим образом:

  • Объявите два стека однимдля отмены и другие для повторения:
  • Когда отменить вытолкнуть действие «изображение» или «состояние изображения» из стека отмены и перенести его в стек повторного выполнения.
  • Когда redo извлекает действие «изображение» или «состояние изображения» из стека повторов и помещает его в стек отмены.

Пример:

private Stack<Image> _undoStack = new Stack<Image>();
private Stack<Image> _redoStack = new Stack<Image>();

private readonly object _undoRedoLocker = new object();

private void Undo()
{
    lock (_undoRedoLocker)
    {
        if (_undoStack.Count > 0)
        {
            _redoStack.Push(_undoStack.Pop());

            //OnUndo();
            pictureBox1.Image = _redoStack.Peek();
            pictureBox1.Refresh();
        }
    }
}

private void Redo()
{
    lock (_undoRedoLocker)
    {
        if (_redoStack.Count > 0)
        {
            _undoStack.Push(_redoStack.Pop());

            //OnRedo();
            pictureBox1.Image = _undoStack.Peek();
            pictureBox1.Refresh();
        }
    } 
}

//And whenever image need to be modified, add it to the undo stack first and then modify it
private void UpdateImageData(Action updateImage)
{
    lock (_undoRedoLocker)
    {
        _undoStack.Push(pictureBox1.Image);//image);

        try
        { 
            //manipulate the image here.
            updateImage();
        }
        catch
        {
            _undoStack.Pop();//because of exception remove the last added frame from stack
            throw;
        }
    }
}

private void pictureBox1_MouseClick(object sender, EventArgs e)
{
    UpdateImageData(delegate()
    {
        rect.Width = 0;
        rect.Height = 0;
        pictureBox1.Invalidate();

        int radius = 10; //Set the number of pixel you want to use here
        //Calculate the numbers based on radius
        int x0 = Math.Max(e.X - (radius / 2), 0),
            y0 = Math.Max(e.Y - (radius / 2), 0),
            x1 = Math.Min(e.X + (radius / 2), pictureBox1.Width),
            y1 = Math.Min(e.Y + (radius / 2), pictureBox1.Height);
        Bitmap bm = pictureBox1.Image as Bitmap; //Get the bitmap (assuming it is stored that way)
        for (int ix = x0; ix < x1; ix++)
        {
            for (int iy = y0; iy < y1; iy++)
            {
                bm.SetPixel(ix, iy, Color.Black); //Change the pixel color, maybe should be relative to bitmap
            }
        }
        pictureBox1.Refresh(); //Force refresh
    }
}
  • Всякий раз, когда пользователь хочет отменить «например, нажимает Ctrl + Z» в форме, просто вызывать Undo ();
  • Всякий раз, когда пользователь хочет повторить в форме, просто вызвать Redo ();

Примечание: я не тестировал приведенный выше код, но он, вероятно, должен работать, если вы обнаружите какую-либо проблему, оставьте сообщениеЗакоментировать

1 голос
/ 28 июня 2011

Один из способов сделать это - сохранить bitmap, как это было до последней операции, и просто перерисовать bitmap в picturebox.Это может быть не самым эффективным, так как растровые изображения могут становиться достаточно большими, в зависимости от их размера, но это один из самых простых и быстрых способов.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...