Рисование в языке С#

Классы, объединенные в пространство имен Drawing, позволяют работать с различными изображениями. Существует два основных типа компьютерных изображений.
Растровые представляют собой набор точек. Примером могут служить фотографии и значки.
Векторная графика — это изображения, составленные из геометрических фигур: линий, окружностей, прямоугольников и т. д. Например, план дома удобно представлять в виде векторного изображения.
Для начала продемонстрируем работу с растровой графикой. На компьютере часто приходится выполнять обработку изображений, например, фотографий. Для этого в библиотеке классов .NET Framework имеется немало полезных средств.
Пример программы 8
Для создания программы, отображающей на форме рисунок, хранящийся в файле, нам понадобится специальный элемент управления. Для этой цели прекрасно подходит PictureBox.
Код программы 8
using System;
using System.Windows.Forms; using System.Drawing;
class PictureDisplayer : Form
{
Bitmap image1;
PictureBox pictureBox1;
// Метод-конструктор нашего класса public PictureDisplayer()
{
// Указываем размеры и заголовок окна
this.Text = “Искусство аборигенов”; this.Size = new Size(302, 240);
// Подготавливаем поле для размещения изображения
pictureBox1 = new PictureBox(); pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; pictureBox1.BorderStyle = BorderStyle.Fixed3D; pictureBox1.ClientSize = new Size(300, 196); // Добавляем изображение в элемент PictureBox
image1 = new Bitmap(@”../../images/Iskusstvo.jpg”); pictureBox1.Image = (Image)image1;
// Добавляем PictureBox (с изображением) на форму this.Controls.Add(pictureBox1);
}
static void Main()
{
// Создаем и запускаем форму
Application.Run(new PictureDisplayer());
}

Пример программы 9
Следующая программа загружает фотографию с диска и после нажатия кнопки «flip» (Перевернуть) позволяет получить ее зеркальное отражение, расположенное по горизонтали:
Код программы 9
using System; using System.Windows.Forms; using System.Drawing;
class PictureFlipper : Form
{
Button button1;
Bitmap image1;
PictureBox pictureBox1;
// Метод-конструктор нашего класса public PictureFlipper()
{
// Указываем размеры и заголовок окна
this.Text = “Поворот рисунка”; this.Size = new Size(302, 240); // Добавляем на форму кнопку
button1 = new Button(); button1.Text = “Поворот рисунка”; button1.Location = new Point(100, 150); button1.Size = new Size(70, 40);
button1.Click += new System.EventHandler(button1_Click); this.Controls.Add(button1);
// Добавляем элемент PictureBox на форму
pictureBox1 = new PictureBox(); pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; pictureBox1.BorderStyle = BorderStyle.Fixed3D; pictureBox1.ClientSize = new Size(300, 196); // Добавляем изображение в элемент PictureBox image1 = new Bitmap(@”../../images/Giraf.jpg”); pictureBox1.Image = (Image)image1; // Добавляем на форму элемент PictureBox this.Controls.Add(pictureBox1);
}
static void Main()
{
// Создаем и запускаем форму
Application.Run(new PictureFlipper());
}
// Обработчик события, срабатывающий при нажатии кнопки void button1_Click(object sender, EventArgs e)
{
// Flip the image along the X axis (horizontally) image1.RotateFlip(RotateFlipType.RotateNoneFlipX);
// Повторно вставляем изображение в элемент PictureBox pictureBox1.Image = (Image)image1;
// Обновляем заголовок окна
this.Text = “Рисунок после поворота!”; }
}

Теперь перейдем к примерам работы с векторной графикой — изображениям, составленным из геометрических фигур.
Во всех примерах будут создаваться кнопка и обработчик событий, отвечающий за то, чтобы работа с графикой начиналась только после нажатия кнопки.
Необходимо усвоить несколько важных принципов. Они вполне логичны, но все-таки следует уяснить их, чтобы избежать возможных затруднений.
- В обычном мире, прежде чем нарисовать линию, окружность, прямоугольник или иную фигуру, необходимо выбрать карандаш нужного цвета с грифелем определенной толщины.
Для отрисовки на компьютере простейших фигур надо сначала создать объект Pen (Перо). Например, с помощью данного фрагмента кода создается объект Pen, который рисует зеленую линию толщиной 3 пикселя:
Pen myGreenPen = new Pen(Color.Green, 3);
- Для рисования фигур с заливкой потребуется нечто вроде кисти с красками.
Предварительно следует создать объект Brush (Кисть), а затем выбрать цвет заливки и один из многочисленных типов кисти. В следующем фрагменте кода создается объект SolidBrush (Сплошная кисть) голубого цвета:
SolidBrush myBlueBrush = new SolidBrush(Color.Blue);
Пример программы 10
В этой программе в методе, названном DrawSomeShapes, рисуется линия, прямоугольник и эллипс.
Код программы 10
using System; using System.Windows.Forms; using System.Drawing;
class SimpleShapeMaker : Form
{
// Метод-конструктор нашего класса public SimpleShapeMaker()
{
// Меняем цвет фона формы на белый this.BackColor = Color.White;
// Добавляем на форму кнопку и привязываем ее к обработчику событий
Button button1 = new Button(); button1.Text = “Будем рисовать!”; button1.Location = new Point(110, 10); button1.Size = new Size(70, 40); button1.BackColor = Color.LightGray; button1.Click += new System.EventHandler(button1_Click); this.Controls.Add(button1);
}
// Обработчик события, срабатывающий при нажатии кнопки void button1_Click(object o, System.EventArgs e)
{
// Вызов метода
DrawSomeShapes();
}
// Метод для отрисовки на поверхности формы нескольких фигур void DrawSomeShapes()
{
// Подготовка области рисования на форме
Graphics g = this.CreateGraphics();
// Подготавливаем перо, рисующее красную линию толщиной 3 пикселя
Pen redPen = new Pen(Color.Red, 3);
// С помощью пера рисуем прямую линию, прямоугольник и эллипс g.DrawLine(redPen, 140, 170, 140, 230);
g.DrawRectangle(redPen, 50, 60, 50, 60);
g.DrawEllipse(redPen, 150, 100, 100, 60);
// Очистка
g.Dispose(); }
static void Main()
{
// Создаем и запускаем форму
Application.Run(new SimpleShapeMaker()); }
}

Пример программы 11
Теперь попробуем поиграть с мышкой – работать с графикой удобнее при помощи мыши, а не клавиатуры. Мы будем обрабатывать как растровые, так и с векторные изображения, используя некоторые события мыши.
Постараемся освоить некоторые новые действия, а именно — действия с точечными рисунками. Тратить время на подробное описание мы не будем, но небольшое вступление необходимо, чтобы рассказать о принципах работы приведенного ниже кода.
Компьютерные программы формируют изображение на экране монитора, управляя цветом и яркостью маленьких точек, которые называются пикселями.
Цвет пикселя определяется тремя цветовыми компонентами: красной (red), зеленой (green) и синей (blue) – в языках программирования часто используется сокращение RGB. Цвет и яркость пикселя можно изменять, регулируя интенсивность компонентов RGB, в пределах от 0 до 255 единиц. Например:
если red=255, green=0, blue=0 — цвет пикселя будет ярко-красным; если red=255, green=255, blue=0 — цвет пикселя желтый.
Компьютер может отслеживать положение курсора мыши, определяемое координатами X и Y (горизонтальная и вертикальная координаты). Так, верхний левый угол экрана имеет координаты X=0 и Y=0.
Код программы 11
using System; using System.Windows.Forms; using System.Drawing;
class FunWithTheMouse : Form
{
// Объявляем объекты, доступные для разных методов
PictureBox pictureBox1;
Label label1;
Point spotClicked;
// Метод-конструктор нашего класса public FunWithTheMouse()
{
// Задаем размеры окна this.Size = new Size(640, 480);
// Загружаем рисунок в элемент PictureBox и вставляем в форму pictureBox1 = new PictureBox();
pictureBox1.Image = (Image)new Bitmap(@”../../images/Dog.bmp”); pictureBox1.SizeMode = PictureBoxSizeMode.Normal; pictureBox1.Dock = DockStyle.Fill; this.Controls.Add(pictureBox1);
// Добавляем метку с инструкциями в нижнюю часть экрана
label1 = new Label(); label1.BackColor = Color.Wheat; label1.Dock = DockStyle.Bottom; label1.Text =
“При нажатой левой кнопке мыши можно рисовать прямоугольники. “ +
“Нажатая правая кнопка изменяет яркость прямоугольника “ + “Нажав SHIFT и перемещая мышь, рисуем желтые кружки.”; label1.TextAlign = ContentAlignment.MiddleCenter; this.Controls.Add(label1);
// Привязываем PictureBox к обработчикам событий мыши
this.pictureBox1.MouseDown += new MouseEventHandler(MouseButtonIsDown); this.pictureBox1.MouseUp += new MouseEventHandler(MouseButtonIsUp); this.pictureBox1.MouseMove += new MouseEventHandler(TheMouseMoved);
}
// Обработчик событий, срабатывающий при ПЕРЕМЕЩЕНИИ мыши public void TheMouseMoved(object sender, MouseEventArgs e)
{
// Если на клавиатуре нажата клавиша SHIFT
if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
{
// Подготовка области рисования на изображении
System.Drawing.Graphics g = this.pictureBox1.CreateGraphics();
// Используем желтое перо
System.Drawing.Pen yellowPen = new
System.Drawing.Pen(Color.Yellow, 3);
// Рисуем окружность (эллипс, вписанный в квадрат) // Верхний левый угол квадрата имеет координаты X и Y // текущего положения мыши.
g.DrawEllipse(yellowPen, e.X, e.Y, 40, 40);
// Очистка
g.Dispose();
}
}
// Обработчик событий, срабатывающий при НАЖАТИИ кнопки мыши public void MouseButtonIsDown(object sender, MouseEventArgs e)
{
// Запоминаем точку, в которой произошло нажатие кнопки мыши. // Когда кнопка будет отпущена, нам понадобятся ее координаты
spotClicked.X = e.X;// горизонтальная координата spotClicked.Y = e.Y;// вертикальная координата
}
// Обработчик событий, срабатывающий при ОТЖАТИИ кнопки мыши public void MouseButtonIsUp(object sender, MouseEventArgs e) {
/* Пользователь отпустил кнопку мыши! */
// Создаем прямоугольник (пока он еще не виден), ограничивающий
// область изображения, с которой пользователь будет работать
Rectangle r = new Rectangle();
// Левый верхний угол прямоугольника соответствует точке, // в которой была нажата кнопка мыши. // Мы сохранили ее координаты.
r.X = spotClicked.X;
r.Y = spotClicked.Y;
// Ширина и высота прямоугольника вычисляется
// путем вычитания координат мыши в точке нажатия // из текущих координат (в точке отжатия кнопки).
r.Width = e.X – spotClicked.X;
r.Height = e.Y – spotClicked.Y;
if (e.Button == MouseButtons.Left) {
/* Если была нажата и отпущена левая кнопка мыши, рисуем видимый контур прямоугольника */
// Подготовка области рисования на изображении
Graphics g = this.pictureBox1.CreateGraphics();
// Рисуем красный контур прямоугольника
Pen redPen = new Pen(Color.Red, 2); g.DrawRectangle(redPen, r); } else {
// Если была нажата другая кнопка, вызываем
// метод, подсвечивающий область изображения
ChangeLightness(r);
}
}
// Метод, увеличивающий яркость выбранного участка изображения // путем увеличения яркости каждого пикселя этого участка public void ChangeLightness(Rectangle rect)
{ int newRed, newGreen, newBlue; Color pixel;
// Копируем изображение, загруженное в PictureBox
System.Drawing.Bitmap picture = new
Bitmap(this.pictureBox1.Image);
// Операция увеличения яркости может занять много времени, // пользователя предупреждают, если выбран большой участок.
if ((rect.Width > 150) || (rect.Height > 150)) {
DialogResult result = MessageBox.Show(
“Выделенная область велика! “ +
“Изменение яркости может требовать значительного времени!”,
“Warning”, MessageBoxButtons.OKCancel);
// При нажатии кнопки Cancel (Отмена) выходим из метода
// и возвращаемся к месту его вызова
if (result == DialogResult.Cancel) return;
}
/* Перебираем последовательно все пиксели данного участка и удваиваем значение яркости компонент RGB пикселей */ // Перебор по горизонтали слева направо…
for (int x = rect.X; x < rect.X + rect.Width; x++)
{
// и по вертикали сверху вниз…
for (int y = rect.Y; y < (rect.Y + rect.Height); y++) {
// Считываем текущий пиксель pixel = picture.GetPixel(x, y);
// Увеличиваем яркость цветовых компонент пикселя
newRed = (int)Math.Round(pixel.R * 2.0, 0); if (newRed > 255) newRed = 255; newGreen = (int)Math.Round(pixel.G * 2.0, 0); if (newGreen > 255) newGreen = 255; newBlue = (int)Math.Round(pixel.B * 2.0, 0); if (newBlue > 255) newBlue = 255;
// Присваиваем пикселю новые цветовые значения
picture.SetPixel
(x, y, Color.FromArgb(
(byte)newRed, (byte)newGreen, (byte)newBlue)); }
}
// Помещаем измененную копию изображения в PictureBox,
// чтобы изменения отобразились на экране this.pictureBox1.Image = picture;
}
static void Main() {
// Создаем экземпляр класса формы
Application.Run(new FunWithTheMouse());
}
}
