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

telegram канал для общения

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

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

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