# Explorer context-menu helper: resize images (single file, multiple files, or folder tree) via media-img.exe # Multi-select: Explorer uses MultiSelectModel Player + %* — this script receives all paths in one invocation. # Uses Start-Process -WindowStyle Hidden so no console window (VIPS stderr is redirected to a temp file). param( [Parameter(Mandatory)][string]$MediaImg, [Parameter(Mandatory)][int]$MaxWidth, [Parameter(Mandatory)][ValidateSet('InPlace', 'Copy')][string]$Mode, [Parameter(Mandatory, ValueFromRemainingArguments = $true)][string[]]$InputPaths ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $InputPaths = @($InputPaths | Where-Object { $_ -and $_.Trim() -ne '' }) if ($InputPaths.Length -eq 0) { exit 1 } # Canonical list — keep in sync with register_explorer.cpp (k_canonical_ext + case-insensitive match) $imageExt = @( '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.tiff', '.tif', '.jpe', '.jfif', '.avif', '.arw' ) function Test-ImageExt([string]$ext) { $e = $ext.ToLowerInvariant() return $script:imageExt -contains $e } function Invoke-MediaImgResize([string[]]$ArgList) { $outF = [System.IO.Path]::GetTempFileName() $errF = [System.IO.Path]::GetTempFileName() try { $p = Start-Process -FilePath $MediaImg -ArgumentList $ArgList -Wait -PassThru ` -WindowStyle Hidden -RedirectStandardOutput $outF -RedirectStandardError $errF if ($p.ExitCode -ne 0) { $e = if (Test-Path -LiteralPath $errF) { Get-Content -Raw -LiteralPath $errF } else { '' } throw "media-img failed (exit $($p.ExitCode)): $e" } } finally { Remove-Item -LiteralPath $outF, $errF -ErrorAction SilentlyContinue } } function Resize-SingleFile([string]$File) { $w = $MaxWidth if ($Mode -eq 'Copy') { $dst = '${SRC_DIR}/${SRC_NAME}_' + $w + '${SRC_FILE_EXT}' Invoke-MediaImgResize @('resize', '--src', $File, '--dst', $dst, '--max-width', "$w", '--fit', 'inside', '--no-cache') } else { $ext = [System.IO.Path]::GetExtension($File) $tmp = Join-Path $env:TEMP ('media-img-' + [Guid]::NewGuid().ToString('n') + $ext) try { Invoke-MediaImgResize @('resize', '--src', $File, '--dst', $tmp, '--max-width', "$w", '--fit', 'inside', '--no-cache') Move-Item -LiteralPath $tmp -Destination $File -Force } finally { if (Test-Path -LiteralPath $tmp) { Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue } } } } function Process-OnePath([string]$Path) { if (-not (Test-Path -LiteralPath $Path)) { exit 1 } $item = Get-Item -LiteralPath $Path if ($item.PSIsContainer) { $files = Get-ChildItem -LiteralPath $Path -Recurse -File -ErrorAction Stop | Where-Object { Test-ImageExt $_.Extension } if (-not $files) { exit 0 } foreach ($f in $files) { Resize-SingleFile $f.FullName } } else { if (-not (Test-ImageExt $item.Extension)) { exit 0 } Resize-SingleFile $item.FullName } } if ($InputPaths.Length -gt 1) { foreach ($p in $InputPaths) { Process-OnePath $p } exit 0 } Process-OnePath $InputPaths[0] exit 0