Бывает много ситуаций, когда необходимо сделать снимок экрана, на пример при поддержке установленного программного обеспечения снимок экрана может очень сильно помочь в описании проблемы.
В этой статье мы рассмотрим как сделать снимок экрана, отобразить его, а так же сохранить на диск.
В далекие времена .NET Framework 1.0, что бы сделать снимок экрана приходилось прибегать к вызову Windows API. В .NET Framework 2.0 в пространстве имен System.Drawing и System.Drawing.Imaging появляются новые классы, которые, благодаря GDI+, позволяют работать с графикой, используя только .NET.
Для демонстрации создадим простую Windows Forms программу, которая будет получать снимок экрана, отображать его на форме, а так же при необходимости сохранять его в виде графического файла.
Разместим на форме 4-е кнопки с именами btnCapture, btnSaveJpg, btnSavePng, btnClose, один PictureBox с именем img, а так же SaveFileDialog с именем dlg.
Перейдем к коду, нам потребуется подключить пространства имен System.Drawing и System.Drawing.Imaging.
using System.Drawing;
using System.Drawing.Imaging;
Теперь нам понадобится объект Bitmap (растровое изображение), который будет использоваться для хранения снимка экрана, но т.к. он будет нужен как при самом получении изображения, так и при сохранении изображения, то лучше его сделать частью класса frmMain.
public partial class frmMain : Form
{
private Bitmap captured;
public frmMain()
{
InitializeComponent();
}
...
Далее создадим процедуру получения снимка экрана по нажатию на кнопку btnCapture. Во первых необходимо определить размер создаваемого изображения, а так же глубину цвета. Эти данные можно получить из свойств объекта Screen. В примере будет использоваться основной экран, что для варианта с одним монитором вполне годится, а в случае с несколькими мониторами необходимо использовать массив Screen.AllScreens[].
Размер изображения:
Rectangle bounds = Screen.PrimaryScreen.Bounds;
Глубина цвета – это количество бит, выделяемых на каждую точку на экране, что в свою очередь определяет количество цветов, которое может принимать эта точка. Для минимизировать использование памяти будем использовать полученное значение для создания растрового изображения:
int colourDepth = Screen.PrimaryScreen.BitsPerPixel;
Что бы использовать полученное значение глубины цвета, необходимо создать объект RixelFormat, который представляет из себя перечисление и присвоить ему соответствующее значение. Существует некоторое ограничение для значения в 8-мь бит, по этому для таких снимков экрана будет создаваться 16-и битное изображение.
PixelFormat format;
switch (colourDepth)
{
case 8:
case 16:
format = PixelFormat.Format16bppRgb565;
break;
case 24:
format = PixelFormat.Format24bppRgb;
break;
case 32:
format = PixelFormat.Format32bppArgb;
break;
default:
format = PixelFormat.Format32bppArgb;
break;
}
Теперь, зная значение глубины цвета и размера изображения, можно инициализировать объект bitmap, которому ранее было присвоено имя captured:
captured = new Bitmap(bounds.Width, bounds.Height, format);
Переходим к использованию GDI+, создадим поверхность для рисования, которая будет связана с нашим растровым изображением.
Graphics gdi = Graphics.FromImage(captured);
Ну и наконец сделаем снимок экрана, в этом нам поможет метод CopyFromScreen, в него передаются 5-ть параметров, первые два это координаты левого верхнего пикселя копируемого изображения, следующие два это координаты места вставки изображения в “холст” GDI+, последний параметр это размер копируемой области.
gdi.CopyFromScreen(bounds.Left, bounds.Top, 0, 0, bounds.Size);
Ну а теперь можно вывести полученное изображение в PictureBox на нашей форме:
img.BackgroundImageLayout = ImageLayout.Zoom;
img.BackgroundImage = captured;
Вся процедура обработки нажатия на кнопку btnCapture:
private void btnCapture_Click(object sender, EventArgs e)
{
Rectangle bounds = Screen.PrimaryScreen.Bounds;
int colourDepth = Screen.PrimaryScreen.BitsPerPixel;
PixelFormat format;
switch (colourDepth)
{
case 8:
case 16:
format = PixelFormat.Format16bppRgb565;
break;
case 24:
format = PixelFormat.Format24bppRgb;
break;
case 32:
format = PixelFormat.Format32bppArgb;
break;
default:
format = PixelFormat.Format32bppArgb;
break;
}
captured = new Bitmap(bounds.Width, bounds.Height, format);
Graphics gdi = Graphics.FromImage(captured);
gdi.CopyFromScreen(bounds.Left, bounds.Top, 0, 0, bounds.Size);
img.BackgroundImageLayout = ImageLayout.Zoom;
img.BackgroundImage = captured;
}
Теперь создадим процедуры сохранения полученного изображения в файл. Сохранение в формате jpeg при нажатии на кнопке btnSaveJpg. Проверяем инициализирован ли объект bitmap, если да, то открываем диалоговое окно сохранения файла в котором настроен фильтр на отображение только изображений в формате jpeg, если файл выбран, то сохраняем, используя метод Save объекта Bitmap.
private void btnSaveJpg_Click(object sender, EventArgs e)
{
if (captured != null)
{
dlg.Filter = "Jpeg image|*.jpg|All files|*.*";
dlg.Title = "Save captured screen as jpeg";
if (dlg.ShowDialog() == DialogResult.OK)
{
captured.Save(dlg.FileName, ImageFormat.Jpeg);
}
}
}
Сохранение в формате png при нажатии на кнопке btnSavePng.
private void btnSavePng_Click(object sender, EventArgs e)
{
if (captured != null)
{
dlg.Filter = "PNG image|*.png|All files|*.*";
dlg.Title = "Save captured screen as png";
if (dlg.ShowDialog() == DialogResult.OK)
{
captured.Save(dlg.FileName, ImageFormat.Png);
}
}
}
Вот и все.
Архив комментариев.
arxont says: October 3, 2010 at 16:13 Спасибо за пример, я ещё добавил чтобы окно при снятии сворачивалось. Анонимный says: March 22, 2011 at 16:13 Сергей, напишите статью, как сделать скриншот с приложений использующих directx(на c#). Поскольку этим методом, я так понимаю, сохранится, лишь черный экран. если можете, оповестите меня в случае написания данной статьи. dan-ver@ukr.net Юрий says: February 5, 2017 at 16:14 Наверно не captured = new Bitmap(bounds.Width, bounds.Height, format); а Bitmap captured = new Bitmap(bounds.Width, bounds.Height, format);