はじめに
パソコン操作の手順書を作るときなど、同じ領域の画面キャプチャを繰り返し取得したいことがあり、そんなときにちょっと便利になりそうな簡易ツールを作ってみました。
この簡易ツールは、特別なソフトのインストール不要で、Windows環境のPowerShellで動作するスクリプトです。
基本的に、自分用ということで、インストーラーなどを用意せず、エラー処理の作り込みは限定的です。
動作環境
- Windows 10
- PowerShell 5.1
使い方
まず、次のリンクからZIPファイルをダウンロードし、適当な場所に展開します。
次に、今回作成した簡易ツールを実行します。
コマンドプロンプトから実行する場合、展開したフォルダの「Windows\ScreenCapture\ScreenCapture.bat」を実行します。
PowerShellのターミナルから実行する場合、展開したフォルダの「Windows\ScreenCapture\ScreenCapture.ps1」を実行します。
以下、展開したフォルダの「Windows\ScreenCapture」にパスを通した前提で、実行例を記述します。
コマンドプロンプトでの実行例です。
rem ヘルプを表示する。
ScreenCapture.bat
rem 画面全体をキャプチャする。
ScreenCapture.bat All D:\tmp\capture.png
rem 指定領域を、3秒間隔で10回、キャプチャする。
ScreenCapture.bat 0,0,800,600 D:\tmp\capture.png -Interval 3 -Repetition 10
PowerShellのターミナルでの実行例です。
# ヘルプを表示する。
ScreenCapture.ps1
# 画面全体をキャプチャする。
ScreenCapture.ps1 "All" D:\tmp\capture.png
# 指定領域を、3秒間隔で10回、キャプチャする。
ScreenCapture.ps1 "0,0,800,600" D:\tmp\capture.png -Interval 3 -Repetition 10
実装のポイント
この簡易ツールをPowerShellで実装するうえで、主要な処理となった部分をメモしておきます。
今後、同じような処理を使いたい場面が出てきたときに、思い返せるようにしたいと思います。
画面キャプチャ
.NetのSystem.Drawing.Graphicsを使って、画面キャプチャすることができました。
Add-Type -AssemblyName System.Drawing
function CaptureToFile($rect, $outPath) {
# Save時に、相対パスだとエラーになることがあるので、絶対パスに変更。
# パスが存在しないことも考慮して.Netで実装。Resolve-Pathだとエラーになる。
$outPath = GetFullPath $outPath
# キャプチャ
$bitmap = New-Object System.Drawing.Bitmap($rect.Width, $rect.Height)
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
$graphics.CopyFromScreen($rect.Left, $rect.Top, 0, 0, $bitmap.Size)
$bitmap.Save($outPath)
$graphics.Dispose()
$bitmap.Dispose()
Write-Host "キャプチャしました。 $($rect.Location) $($rect.Size) $outPath"
}
function GetFullPath($path) {
[System.IO.Directory]::SetCurrentDirectory((Get-Location))
return [System.IO.Path]::GetFullPath($path)
}
# 上記関数の呼び出し例
$rect = New-Object System.Drawing.Rectangle(0, 0, 500, 500)
CaptureToFile $rect "work\capture.png"
マルチモニターを考慮して画面キャプチャするためには、次の処理が必要でした。
# マルチモニター考慮
# 全モニターを1つの画像ファイルに保存
$screens = [System.Windows.Forms.Screen]::AllScreens
$top = ($screens.Bounds.Top | Measure-Object -Minimum).Minimum
$left = ($screens.Bounds.Left | Measure-Object -Minimum).Minimum
$right = ($screens.Bounds.Right | Measure-Object -Maximum).Maximum
$bottom = ($screens.Bounds.Bottom | Measure-Object -Maximum).Maximum
$rect = [System.Drawing.Rectangle]::FromLTRB($left, $top, $right, $bottom)
CaptureToFile $rect "work\capture.png"
# プライマリモニターのみ
$rect = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
CaptureToFile $rect "work\capture.png"
# アクティブモニターのみ →C#/.NET関数を自作する必要がありそうなので省略。
画像をクリップボードへコピー
次のようにして、キャプチャした画像を、クリップボードに保存することができました。
2つの実装方法を試し、どちらでも動作しました。
# 画像をクリップボードにコピー
$bitmap = New-Object System.Drawing.Bitmap($outPath)
# 案1
$data = New-Object System.Windows.Forms.DataObject
$data.SetImage($bitmap)
[Windows.Forms.Clipboard]::SetDataObject($data, $true)
# 案2
[Windows.Forms.Clipboard]::SetImage($bitmap)
# 後片付け
$bitmap.Dispose()
マウス位置・ボタンの参照
キャプチャの取得範囲を指定するのに、マウスをドラッグして指定できると便利かと思い、マウスで矩形選択する処理も書いてみました。
function GetDragRect() {
Write-Host "マウスをドラッグして矩形領域を選択してください。"
while ([System.Windows.Forms.Control]::MouseButtons -eq 'None') { Start-Sleep 0.5 }
$p1 = [System.Windows.Forms.Control]::MousePosition
Write-Host "Pressed"
while ([System.Windows.Forms.Control]::MouseButtons -ne 'None') { Start-Sleep 0.5 }
$p2 = [System.Windows.Forms.Control]::MousePosition
Write-Host "Released"
$rect = [System.Drawing.Rectangle]::FromLTRB(
[Math]::Min($p1.X, $p2.X), [Math]::Min($p1.Y, $p2.Y),
[Math]::Max($p1.X, $p2.X), [Math]::Max($p1.Y, $p2.Y))
Write-Host $rect
return $rect
}
$rect = GetDragRect
参考サイト
実装するのに以下のサイトを参考にさせていただきました。ありがとうございます!