Вырезаем прямоугольную область изображения в C#
Из архива...
Недавно пришлось сделать простенькую подгонялку фотографий в заданные рамки, так чтобы пользователь мог собственноручно выбрать область на фото источнике и вырезать её. Впринципе ничего сложного, самое сложное пожалуй — это отрисовка прямоугольника выделения, когда нажали на кнопку мыши и перемещаем её по изображению — выделяя необходимую нам область.
Сначала самое важное. У картинки pictureBox сразу включаем свойство SizeMode в AutoSize, ни в коем случае ни какие нибудь там Zoom-ы если конечно нет желания поразбираться с масштабированием.
Далее — надо сделать так — чтобы работал скроллинг при выделении мышкой. Так уж получилось что это больное место в .NET (не работает оно само собой и всё тут).
Чтобы заработало делаем вот это:
[DllImport("user32.dll")]
public static extern int SendMessage(
int hWnd, // handle to destination window
uint Msg, // message
long wParam, // first message parameter
long lParam // second message parameter
);
И в обработчике события:
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pic.Width = e.X - begin_x;
pic.Height = e.Y - begin_y;
//Скроллинг...
scroller_hor = -1;
scroller_vert = -1;
if (e.X > panel2.Width - 5)
{ scroller_hor = 0; }
if (e.Y > panel2.Height - 5)
{ scroller_vert = 0; }
}
}
Теперь — если мы перемещаем курсор по картинке нажав левую кнопку мышки, то при подходе к границам будут перемещаться Scroll-бары и картинка будет смещаться (в случае если она больше чем видимая её область).
Теперь переходим непосредственно к функции которая нам вырежет кусочек картинки:
static public Image Copy(Image srcBitmap, Rectangle section)
{
// Вырезаем выбранный кусок картинки
Bitmap bmp = new Bitmap(section.Width, section.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(srcBitmap, 0, 0, section, GraphicsUnit.Pixel);
}
//Возвращаем кусок картинки.
return bmp;
}
Упс — чуть не забыл (для всего этого) нам понадобятся вот эти вот переменные:
PictureBox pic = new PictureBox(); //Картинка - вырезаемая область.
private int begin_x;
private int begin_y; //Координаты картинки на исходном pictureBox.
bool resize = false; //Эта специальная переменная уберегающая от случайных нажатий мышкой по изображению.
private int scroller_vert = -1;
private int scroller_hor = -1; //Включение выключение скроллинга - таймер проверяет эти значения и посылает сообщения на смещение ScrollBar-ов.
//И вот сам таймер для скроллинга.
private void timer1_Tick(object sender, EventArgs e)
{
if (scroller_vert > -1)
{
SendMessage(panel2.Handle.ToInt32(), 277, 1, scroller_vert);
}
if (scroller_hor > -1)
{
SendMessage(panel2.Handle.ToInt32(), 276, 1, scroller_hor);
}
}
А теперь непосредственно о том как отрисовать рамку при выделении, я пошёл вот на такую хитрость которая сработала:
//При загрузке формы (но это не обязательно - это у меня так)
private void Form1_Load(object sender, EventArgs e)
{
//Делаем нашей картинке приёмнику родителем картинку источник.
pic.Parent = pictureBox1;
//Теперь делаем её прозрачной но задаём ей рамку BorderStyle.
pic.BackColor = Color.Transparent;
pic.SizeMode = PictureBoxSizeMode.AutoSize;
pic.BorderStyle = BorderStyle.FixedSingle;
pic.Visible = false;
}
Вуаля!
Осталось только добавить события на MouseDown и MouseUp (для начала выделения при нажатии кнопки мыши и окончания при отпускании) — делаем это:
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
begin_x = e.X;
begin_y = e.Y;
pic.Left = e.X;
pic.Top = e.Y;
pic.Width = 0;
pic.Height = 0;
pic.Visible = true;
timer1.Start();
resize = true;
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
pic.Width = 0;
pic.Height = 0;
pic.Visible = false;
timer1.Stop();
if (resize == true)
{
if ((e.X > begin_x + 10) && (e.Y > begin_y + 10)) //Чтобы совсем уж мелочь не вырезал - и по случайным нажатиям не срабатывал! (можно убрать +10)
{
Rectangle rec = new Rectangle(begin_x, begin_y, e.X - begin_x, e.Y - begin_y);
pictureBox1.Image = Copy(pictureBox1.Image, rec);
}
}
resize = false;
}
Вот собственно и всё.