Automatyzowanie zrzutów ekranu

Obecnie prezentowane rozwiązanie w pewnym sensie znów nawiązuje do przetwarzania grafiki z poziomu konsoli PowerShella. Mianowicie tym razem postaram się zaprezentować metodę przechwytywania obrazu jaki widzimy na ekranie monitora.

Całą przygodę będziemy wykonywali przy wykorzystaniu klas .NET’a. Do tego celu najpierw musimy załadować odpowiednie biblioteki:

[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [Reflection.Assembly]::LoadWithPartialName("System.Drawing")

Drugim krokiem jest zdobycie wymiarów ekranu/ów czyli po prostu rozdzielczości w jakiej pracujemy. By tego dokonać posługujemy się pierwszym zbiorem klas czyli System.Windows.Forms, a konkretnie klasą System.Windows.Forms.Screen, wraz z metodą AllScreens:

$Screens = [System.Windows.Forms.Screen]::AllScreens

PSScreenShot1

Następnie musimy zdecydować jaki obszar chcemy przechwycić. W przypadku jednego ekranu nie ma większych problemów, po prostu sczytujemy wartości:

$Screens.Bounds.Width
$Screens.Bounds.Height

Natomiast dla wielu ekranów, obiekt $Screens będzie stanowił tablicę zawierającą informację o każdym z nich, np. dla dwóch monitorów konieczne będzie zsumowanie szerokości obu ekranów z jednoczesnym wybraniem maksymalnej wartości dla wysokości ekranów.

ForEach ($Screen in $Screens)
{
	$MaxWidth  += $Screen.Bounds.Width
	if($MaxHeight -lt $Screen.Bounds.Height)
	{
		$MaxHeight  = $Screen.Bounds.Height
	}

	$ScreensSize = New-Object PSObject -Property @{
		X = 0
		Y = 0
		Width = $MaxWidth
		Height = $MaxHeight
	}
}

Sprawa zaczyna się odrobinę komplikować, gdy chcemy pobrać obraz tylko z konkretnego ekranu, a szczególnie gdy nie jest to podstawowy ekran.
Tutaj musimy postawić odpowiedni warunek, który z ekranów chcemy pobrać. Następnie podajemy sumę szerokości poprzednich ekranów jako wartość początkową X – zazwyczaj będzie to jeden poprzedni ekran, ale równie dobrze możemy obsługiwać więcej, aniżeli 2.

if($ScreenNumber -ge 2)
{
	$sn = $ScreenNumber
	while($sn-2 -ge 0)
	{
		$X += $Screens[$sn-2].Bounds.Width
		$sn--
	}
	$Y = 0
}
else
{
	$X = 0
	$Y = 0
}

$ScreensSize = New-Object PSObject -Property @{
	X = $X
	Y = $Y
	Width = $Screens[$ScreenNumber-1].Bounds.Width
	Height = $Screens[$ScreenNumber-1].Bounds.Height
}

Ostatecznie przystępujemy do przechwytywania obrazu, czyli definiujemy obszar obrazu oraz obiekt bitmapy:

$Size = New-Object System.Drawing.Size $ScreensSize.Width, $ScreensSize.Height
$Bitmap = New-Object System.Drawing.Bitmap $ScreensSize.Width, $ScreensSize.Height

Tworzymy powierzchnię rysunku dla w/w bitmapy i kopiujemy do niej zawartość ekranu z odpowiednich współrzędnych zdefiniowanych wcześniej:

$Screenshot = [System.Drawing.Graphics]::FromImage($Bitmap)
$Screenshot.CopyFromScreen($ScreensSize.X, $ScreensSize.Y, 0, 0, $Size)

Ostatecznie zapisujemy obraz do pliku i zwalniamy pamięć obiektów graficznych:

$Bitmap.Save($FullPath)
$Screenshot.Dispose()
$Bitmap.Dispose()

Całość możemy przedstawić w formie następującej funkcji:

Function Get-Screen
{
	Param
	(
		[String]$Path = (Get-Location).Path,
		[String]$FileName = "Screenshot",
		[Int]$ScreenNumber = 0
	)

	[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
	[void] [Reflection.Assembly]::LoadWithPartialName("System.Drawing")

	$Screens = [System.Windows.Forms.Screen]::AllScreens
	If($ScreenNumber -eq 0)
	{
		#Wszystkie ekrany
		ForEach ($Screen in $Screens)
		{
			$MaxWidth  += $Screen.Bounds.Width
			if($MaxHeight -lt $Screen.Bounds.Height)
			{
				$MaxHeight  = $Screen.Bounds.Height
			}

			$ScreensSize = New-Object PSObject -Property @{
				X = 0
				Y = 0
				Width = $MaxWidth
				Height = $MaxHeight
			}
		}
	}
	elseif($ScreenNumber -le $Screens.Count)
	{
		#Tylko konkretny ekran
		if($ScreenNumber -ge 2)
		{
			$sn = $ScreenNumber
			while($sn-2 -ge 0)
			{
				$X += $Screens[$sn-2].Bounds.Width
				$sn--
			}
			$Y = 0
		}
		else
		{
			$X = 0
			$Y = 0
		}

		$ScreensSize = New-Object PSObject -Property @{
			X = $X
			Y = $Y
			Width = $Screens[$ScreenNumber-1].Bounds.Width
			Height = $Screens[$ScreenNumber-1].Bounds.Height
		}
	}
	else
	{
		Write-Warning "Wrong screen"
	}

	$i = 1
	Do
	{
		$Name = $FileName

		if($i -gt 1)
		{
			$Name += "-$i"
		}

		$FullPath = Join-Path -Path $Path -ChildPath "$Name.png"
		$i++
	}
	while(Test-Path -Path $FullPath)

	$Size = New-Object System.Drawing.Size $ScreensSize.Width, $ScreensSize.Height
	$Bitmap = New-Object System.Drawing.Bitmap $ScreensSize.Width, $ScreensSize.Height
	$Screenshot = [Drawing.Graphics]::FromImage($Bitmap)
	$Screenshot.CopyFromScreen($ScreensSize.X, $ScreensSize.Y, 0, 0, $Size)
	$Bitmap.Save($FullPath)
	$Screenshot.Dispose()
	$Bitmap.Dispose()
}

PSScreenShot2

Źródła:
http://msdn.microsoft.com/en-us/library/system.windows.forms.screen.aspx
http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.aspx
http://msdn.microsoft.com/en-us/library/system.drawing.graphics.aspx

Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Zdjęcie na Google+

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s