Contents of this directory is archived and no longer updated.

Сегодня пришло письмо, где человек спрашивал о том, можно ли сделать скриншот средствами PowerShell. Я вообще не очень понял зачем это, но это уже не моё дело. Если я пишу этот пост, значит можно :-)

Для этого существует класс Drawing.Graphics у которого есть замечательный метод CopyFromScreen(). Данный метод принимает в качестве аргументов различные параметры, которые определяют координаты области, которую нужно сфоткать. В принципе можно забивать фиксированные значения (см. конструкторы с Int, как этот — CopyFromScreen(Int32, Int32, Int32, Int32, Size)), а можно эти размеры выставлять динамически, в зависимости от размеров экрана. Для этого лучше воспользоваться самым первым методом: CopyFromScreen(Point, Point, Size).

Как получить размеры экрана? Очень просто, достаточно воспользоваться статическим свойством VirtualScreen класса Windows.Forms.SystemInformation:

[Windows.Forms.SystemInformation]::VirtualScreen
[↓] [vPodans] [Windows.Forms.SystemInformation]::VirtualScreen


Location : {X=0,Y=0}
Size     : {Width=1280, Height=800}
X        : 0
Y        : 0
Width    : 1280
Height   : 800
Left     : 0
Top      : 0
Right    : 1280
Bottom   : 800
IsEmpty  : False



[↓] [vPodans]

Вот размеры экрана на моём нотебуке. Готично. Теперь нужно создать объект Drawing.Graphics. Однако, этот объект нельзя создать через New-Object, поскольку для этого нет ни одного конструктора. Следовательно объект нужно создавать используя статические методы. Статические методы можно посмотреть на странице Drawing.Graphics Members. И там мы можем найти красивый метод — FromImage. В качестве аргумента этого метода нужно указать картинку — http://msdn.microsoft.com/en-us/library/system.drawing.image.aspx. Это может быть файл или объект класса Drawing.Bitmap. Давайте создадим объект класса Drawing.Bitmap с использованием следующего конструктора — Bitmap Constructor (Int32, Int32):

[↓] [vPodans] [void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[↓] [vPodans] $size = [Windows.Forms.SystemInformation]::VirtualScreen
[↓] [vPodans] $bitmap = new-object Drawing.Bitmap $size.width, $size.height
[↓] [vPodans] $bitmap


Tag                  :
PhysicalDimension    : {Width=1280, Height=800}
Size                 : {Width=1280, Height=800}
Width                : 1280
Height               : 800
HorizontalResolution : 96
VerticalResolution   : 96
Flags                : 2
RawFormat            : [ImageFormat: b96b3caa-0728-11d3-9d7b-0000f81ef32e]
PixelFormat          : Format32bppArgb
Palette              : System.Drawing.Imaging.ColorPalette
FrameDimensionsList  : {7462dc86-6180-4c7e-8e3f-ee7333a7a483}
PropertyIdList       : {}
PropertyItems        : {}



[↓] [vPodans]

Примечание: WinForms по умолчанию не загружаются вместе с PowerShell, поэтому мы их подгружаем в консоль в ходе работы. Мы создали Bitmap и теперь его можем использовать для создания объекта Drawing.Graphics:

$graphics = [Drawing.Graphics]::FromImage($bitmap)

А дальше уже вызывать метод CopyFromScreen(). При этом указываем первым аргументом начало координат (верхний левый угол или 0,0) и в аргумент правый нижний угол. Т.е. максимум точек по ширине и высоте. Их мы можем получить из свойств Width и Height класса Windows.Forms.SystemInformation. Средний аргумент опускаем и делаем его пустым:

[↓] [vPodans] $graphics = [Drawing.Graphics]::FromImage($bitmap)
[↓] [vPodans] $graphics.CopyFromScreen($size.Location,[Drawing.Point]::Empty, $size.size)

Всё, мы сфоткали наш экран и загнали картинку обратно в Bitmap. Теперь нужно выгрузить картинку куда-то в файл. Для этого у Bitmap есть метод Save(), в котором достаточно указать путь к файлу:

[↓] [vPodans] $bitmap.save(".\screenshot.jpg")
[↓] [vPodans] gi .\screenshot.jpg


    Directory: C:\Users\vPodans


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        22.04.2010     22:37     286319 screenshot.jpg


[↓] [vPodans]

Всё :-)

Примечание: после сохранения картинка остаётся в памяти, поэтому после работы следует освобождать оперативную память от ненужных пруфпиков используя метод Dispose() без аргументов.

И код:

[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$size = [Windows.Forms.SystemInformation]::VirtualScreen
$bitmap = new-object Drawing.Bitmap $size.width, $size.height
$graphics = [Drawing.Graphics]::FromImage($bitmap)
$graphics.CopyFromScreen($size.location,[Drawing.Point]::Empty, $size.size)
$graphics.Dispose()
$bitmap.Save(".\screenshot.jpg")
$bitmap.Dispose()

Share this article:

Comments:

Vasily Gusev

Пользуясь тем что начал снова понимать твой код, несколько мелких придирочек: :) >достаточно воспользоваться статическим методом VirtualScreen класса Windows.Forms.SystemInformation Это статическое свойство скорее. >WinForms по умолчанию не загружаются вместе с PowerShell Зависит от. Точно загружаются в ISE, да вроде и в простом v2.0 всегда есть в наличии при старте. >после сохранения картинка остаётся в памяти, поэтому после работы следует освобождать оперативную память от ненужных пруфпиков используя метод Dispose() без аргументов Если совсем придираться к словам - Dispose() помечает объект для удаления из памяти. А память освободится тогда когда кто нибудь будет поджимать, при следующем регулярном вызове Garbage Collector'а, или если вызвать его вручную: [gc]::Collect() >Домашния страница В форме отправки комментария опечатка :)

Vadims Podāns

> Это статическое свойство скорее. угу. Там же скобок нету. > Зависит от. Точно загружаются в ISE, да вроде и в простом v2.0 всегда есть в наличии при старте. а этот код работает и в 1.0 тоже, где WinForms нет по дефолту. >Если совсем придираться к словам - Dispose() помечает объект для удаления из памяти. ну на MSDN написано, что этот метод освобождает ресурсы. Я не в курсе, как там точно происходит. > В форме отправки комментария опечатка :) знаю. И с этим ничего поделать не могу. Разве что убрать русску локализацию интерфейса, что я, наверное, и сделаю.

shs

Приветы. Я бы заменил название переменной $size на, например, $Screen или $ScreenArea. А то, $size.size выглядит как-то не совсем православно и режет глаз ;)

Vadims Podāns

Я не думаю, что это уж очень критично :)

Comments are closed.