четверг, 27 августа 2009 г.

C# - Захват содержимого экрана (.net 2.0)


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

В этой статье мы рассмотрим как сделать снимок экрана, отобразить его, а так же сохранить на диск.



В далекие времена .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);
}
}
}

Вот и все.

Скачать исходный код примера.

4 комментария:

  1. Спасибо за пример, я ещё добавил чтобы окно при снятии сворачивалось.

    ОтветитьУдалить
  2. Сергей, напишите статью, как сделать скриншот с приложений использующих directx(на c#).
    Поскольку этим методом, я так понимаю, сохранится, лишь черный экран.
    если можете, оповестите меня в случае написания данной статьи. dan-ver@ukr.net

    ОтветитьУдалить
  3. Наверно не
    captured = new Bitmap(bounds.Width, bounds.Height, format);
    а
    Bitmap captured = new Bitmap(bounds.Width, bounds.Height, format);

    ОтветитьУдалить
  4. Hello it is not example file. give me please example file

    ОтветитьУдалить