Как сделать скриншот всего экрана из консольного приложения .NET 6 с помощью GDI+?

Рейтинг: 1Ответов: 1Опубликовано: 28.01.2023

Мне нужно делать скриншот экрана в некоторый момент выполнения программы, я находил несколько ответов как это делать, но они не работают. Я включал System.Windows.Forms и System.Drawing в проект, скачивал через nuget System.Drawing.Common который решает ошибки при компиляции, но при попытке сделать скриншот выдает ошибку о GDI+, пытался добавить ссылки на эти же библиотеки в COM, но всё тщетно.

Текущий код:

Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(Point.Empty, Point.Empty, bitmap.Size);

bitmap.Save("C:\\img.png");

Ответы

▲ 2Принят

Windows Forms не нужно, это лишнее.

1. Создаю пустое .NET 6 приложение.

2. Устанавливаю NuGet пакет System.Drawing.Common

3. Правлю TargetFramework проекта на net6.0-windows, чтобы IDE не ругалась о несовместимости приложения с другими платформами.

В результате .csproj файл выглядит вот так

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Drawing.Common" Version="7.0.0" />
  </ItemGroup>

</Project>

4. Разрешение моего монитора 3840x2400, то есть потребуется поддержка мониторов с высоким DPI. Чтобы она появилась, просто вызову метод WinAPI SetProcessDPIAware, и тогда система будет знать, что мое приложение умеет работать с физическими мониторами с DPI, отличным от 96.

Получается такой код:

using System.Diagnostics;
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;

namespace ScreenshotGdi;

class Program 
{
    [DllImport("user32.dll")]
    static extern bool SetProcessDPIAware();

    static Size GetMonitorSize()
    {
        IntPtr hwnd = Process.GetCurrentProcess().MainWindowHandle;
        using Graphics g = Graphics.FromHwnd(hwnd);
        return new Size((int)g.VisibleClipBounds.Width, (int)g.VisibleClipBounds.Height);
    }

    static Bitmap TakeScreenshot(Size size)
    {
        Bitmap bmp = new Bitmap(size.Width, size.Height);
        using Graphics graphics = Graphics.FromImage(bmp);
        graphics.CopyFromScreen(Point.Empty, Point.Empty, bmp.Size);
        return bmp;
    }

    static void Main(string[] args)
    {
        SetProcessDPIAware();
        Size monitorSize = GetMonitorSize();
        using Bitmap bitmap = TakeScreenshot(monitorSize);
        bitmap.Save("img.png", ImageFormat.Png);
    }
}

И вот такой скриншот

введите сюда описание изображения

Делать скриншоты можно еще с помощью DirectX

Вместо вызова WinAPI SetProcessDPIAware, можно прописать поддержку DPI в манифест.