画像ファイルのサイズを変更するスクリプト

エロ画像コレクションをサムネイル付きで一覧表示するHTMLを生成するスクリプトを作るために、画像からサムネイル画像を作るスクリプトを作ってみた。

Resize-Image.ps1

param([string[]]$fileNames, [int]$width=150)

if($args[0] -eq "-?") {
$commandName = [IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
    Write-Host @"

名前
    $commandName

概要
    指定した画像ファイルのサイズを変更します。

構文
    $commandName [-fileNames] <string[]> [-width] <int>
    
"@ -foregroundColor Yellow
    exit 1
}
$fileNames += @($input)

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

$fileNames | % {
    $srcFile = New-Object IO.FileInfo($_)
    $destFile = (Join-Path $srcFile.DirectoryName ([IO.Path]::GetFileNameWithoutExtension($srcFile.Name) + "_small" + $srcFile.Extension))
    $img = [Drawing.Image]::FromFile($srcFile)
    $thumImg = $img.GetThumbnailImage($width, ($img.Height / ($img.Width / $width)), $null, [IntPtr]::Zero)
    $thumImg.Save($destFile)
    
    $img.Dispose()
    $thumImg.Dispose()

    New-Object IO.FileInfo($destFile)
}

画像のいじり方がさっぱりわからなかったけど、Imageクラスを適当に見ていたらGetThumbnailImageなんていうそのものずばりのメソッドがあったので、それを使う事にした。
引数とパイプラインの両方を受け付ける。戻り値としてサムネイル画像のFileInfoオブジェクトを返す。

いままでパイプラインと引数のどちらを処理するかの条件分岐のうまい書き方が思いつかなかったけど単に

$fileNames += @($input)

とすればいいだけという事にいまさらながら気づいた。
パイプラインオブジェクト($input)はSZArrayEnumeratorとかいうイテレータなので、これを配列にラップして+=演算子でfileNames引数に追加してしまえば、パイプラインか引数かを区別することなく扱うことができる。

しかし、こんな風にパイプでつないでやった場合

PS > dir *.jpg | Resize-Image

パイプラインを流れるオブジェクトはFileInfoオブジェクトなわけで、これではキャストできないように思える。でも実際にはstring配列に対する+=演算子の時点で自動的に文字列に変換されているみたい。よくできている。

このへんは便利ではあるけど、意識せずにやっているとその内、どつぼにはまりそうな気がしないでもない。「ご利用は計画的に」ってか。