mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-02-28 00:22:41 -08:00
164 lines
4.8 KiB
PowerShell
164 lines
4.8 KiB
PowerShell
param(
|
|
[string]$Path,
|
|
[ValidateSet("default", "temp")][string]$Mode = "default",
|
|
[string]$Format = "png",
|
|
[string]$Region,
|
|
[switch]$ActiveWindow,
|
|
[int]$WindowHandle
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Get-Timestamp {
|
|
Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
|
}
|
|
|
|
function Get-DefaultDirectory {
|
|
$home = [Environment]::GetFolderPath("UserProfile")
|
|
$pictures = Join-Path $home "Pictures"
|
|
$screenshots = Join-Path $pictures "Screenshots"
|
|
if (Test-Path $screenshots) { return $screenshots }
|
|
if (Test-Path $pictures) { return $pictures }
|
|
return $home
|
|
}
|
|
|
|
function New-DefaultFilename {
|
|
param([string]$Prefix)
|
|
if (-not $Prefix) { $Prefix = "screenshot" }
|
|
"$Prefix-$(Get-Timestamp).$Format"
|
|
}
|
|
|
|
function Resolve-OutputPath {
|
|
if ($Path) {
|
|
$expanded = [Environment]::ExpandEnvironmentVariables($Path)
|
|
$homeDir = [Environment]::GetFolderPath("UserProfile")
|
|
if ($expanded -eq "~") {
|
|
$expanded = $homeDir
|
|
} elseif ($expanded.StartsWith("~/") -or $expanded.StartsWith("~\\")) {
|
|
$expanded = Join-Path $homeDir $expanded.Substring(2)
|
|
}
|
|
$full = [System.IO.Path]::GetFullPath($expanded)
|
|
if ((Test-Path $full) -and (Get-Item $full).PSIsContainer) {
|
|
$full = Join-Path $full (New-DefaultFilename "")
|
|
} elseif (($expanded.EndsWith("\") -or $expanded.EndsWith("/")) -and -not (Test-Path $full)) {
|
|
New-Item -ItemType Directory -Path $full -Force | Out-Null
|
|
$full = Join-Path $full (New-DefaultFilename "")
|
|
} elseif ([System.IO.Path]::GetExtension($full) -eq "") {
|
|
$full = "$full.$Format"
|
|
}
|
|
$parent = Split-Path -Parent $full
|
|
if ($parent) {
|
|
New-Item -ItemType Directory -Path $parent -Force | Out-Null
|
|
}
|
|
return $full
|
|
}
|
|
|
|
if ($Mode -eq "temp") {
|
|
$tmp = [System.IO.Path]::GetTempPath()
|
|
return Join-Path $tmp (New-DefaultFilename "codex-shot")
|
|
}
|
|
|
|
$dest = Get-DefaultDirectory
|
|
return Join-Path $dest (New-DefaultFilename "")
|
|
}
|
|
|
|
function Parse-Region {
|
|
if (-not $Region) { return $null }
|
|
$parts = $Region.Split(",") | ForEach-Object { $_.Trim() }
|
|
if ($parts.Length -ne 4) {
|
|
throw "Region must be x,y,w,h"
|
|
}
|
|
$values = $parts | ForEach-Object {
|
|
$out = 0
|
|
if (-not [int]::TryParse($_, [ref]$out)) {
|
|
throw "Region values must be integers"
|
|
}
|
|
$out
|
|
}
|
|
if ($values[2] -le 0 -or $values[3] -le 0) {
|
|
throw "Region width and height must be positive"
|
|
}
|
|
return $values
|
|
}
|
|
|
|
if ($Region -and $ActiveWindow) {
|
|
throw "Choose either -Region or -ActiveWindow"
|
|
}
|
|
if ($Region -and $WindowHandle) {
|
|
throw "Choose either -Region or -WindowHandle"
|
|
}
|
|
if ($ActiveWindow -and $WindowHandle) {
|
|
throw "Choose either -ActiveWindow or -WindowHandle"
|
|
}
|
|
|
|
$regionValues = Parse-Region
|
|
$outputPath = Resolve-OutputPath
|
|
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|
Add-Type -AssemblyName System.Drawing
|
|
|
|
$imageFormat = switch ($Format.ToLowerInvariant()) {
|
|
"png" { [System.Drawing.Imaging.ImageFormat]::Png }
|
|
"jpg" { [System.Drawing.Imaging.ImageFormat]::Jpeg }
|
|
"jpeg" { [System.Drawing.Imaging.ImageFormat]::Jpeg }
|
|
"bmp" { [System.Drawing.Imaging.ImageFormat]::Bmp }
|
|
default { throw "Unsupported format: $Format" }
|
|
}
|
|
|
|
Add-Type @"
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
public static class NativeMethods {
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct RECT {
|
|
public int Left;
|
|
public int Top;
|
|
public int Right;
|
|
public int Bottom;
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
public static extern IntPtr GetForegroundWindow();
|
|
|
|
[DllImport("user32.dll")]
|
|
public static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
|
|
}
|
|
"@
|
|
|
|
if ($regionValues) {
|
|
$x = $regionValues[0]
|
|
$y = $regionValues[1]
|
|
$w = $regionValues[2]
|
|
$h = $regionValues[3]
|
|
$bounds = New-Object System.Drawing.Rectangle($x, $y, $w, $h)
|
|
} elseif ($ActiveWindow -or $WindowHandle) {
|
|
$handle = if ($WindowHandle) { [IntPtr]$WindowHandle } else { [NativeMethods]::GetForegroundWindow() }
|
|
$rect = New-Object NativeMethods+RECT
|
|
if (-not [NativeMethods]::GetWindowRect($handle, [ref]$rect)) {
|
|
throw "Failed to get window bounds"
|
|
}
|
|
$width = $rect.Right - $rect.Left
|
|
$height = $rect.Bottom - $rect.Top
|
|
$bounds = New-Object System.Drawing.Rectangle($rect.Left, $rect.Top, $width, $height)
|
|
} else {
|
|
$vs = [System.Windows.Forms.SystemInformation]::VirtualScreen
|
|
$bounds = New-Object System.Drawing.Rectangle($vs.Left, $vs.Top, $vs.Width, $vs.Height)
|
|
}
|
|
|
|
$bitmap = New-Object System.Drawing.Bitmap($bounds.Width, $bounds.Height)
|
|
$graphics = [System.Drawing.Graphics]::FromImage($bitmap)
|
|
|
|
try {
|
|
$source = New-Object System.Drawing.Point($bounds.Left, $bounds.Top)
|
|
$target = [System.Drawing.Point]::Empty
|
|
$size = New-Object System.Drawing.Size($bounds.Width, $bounds.Height)
|
|
$graphics.CopyFromScreen($source, $target, $size)
|
|
$bitmap.Save($outputPath, $imageFormat)
|
|
} finally {
|
|
$graphics.Dispose()
|
|
$bitmap.Dispose()
|
|
}
|
|
|
|
Write-Output $outputPath
|