Amazon.co.jp ウィジェット Windows PowerShellのスクリプトだけで画像のサムネイル生成をした話 - PC破壊日記的ブログ

Home > ソフト公開 > Windows PowerShellのスクリプトだけで画像のサムネイル生成をした話

Windows PowerShellのスクリプトだけで画像のサムネイル生成をした話

このエントリーをはてなブックマークに追加

私は最近よくコスプレイヤーを撮影し、その写真を必要な方に御提供していますが、その際に悩むのは写真の提供の仕方でした。

撮影したJPEGファイルやRAWデータから現像したJPEGファイルはサイズが大きく、そのままSNS等にアップロードすると勝手に圧縮されるか、そうでなくても相手の通信容量を大きく消費します。それを防ぐ方法はないものか、と考え、最終的にサムネイル作成とそれを一覧にするHTMLの作成、それをWebにアップロードし、見て頂く形にしました。
これならサムネイルがまず先に表示されるので通信量を抑え、かつ一覧性が高い、さらに必要に応じてご自身で保存頂ける、という良い環境を作成しました。

しかし、このサムネイル作成とHTML作成はどうしても手間がかかります。それを自動化できないか・・・と考えたところ、なんとPowershell(+.NET Framework)のみでできることを知りました。(ずっとImageMagickが無いと出来ないと思っていました。)そしてそれを使って、実質的にPowershellのみで画像のサムネイル作成とHTMLの作成ができるようになりました。
(実際には、Powershellスクリプトを直接起動するのはセキュリティ上禁止されている場合が多いので、バッチファイルから間接的に起動する形ですが)

作成したスクリプトは以下の圧縮ファイルに保存しました。ご自由にお使いください。
aauto_thumb_make.zip 2018/10/16更新 実行許可権限修正、他微修正

さて、ここからは技術的解説です。主要な部分にはコメントを随時記載しましたが、それで補いきれない部分、特に画像生成部分について解説します。長いので「続きを読む」に。

ほんのりと技術解説です。


# アセンブリの読み込み(.NETの機能呼び出し。まあおまじないと思ってください。)
[void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")


これは画像を扱うための.NET Frameworkライブラリの呼び出しです。Add-Typeでの呼び出しもあるようですが、少々不安点があるようですので、ここはこの表記です。
参考:PowerShell の Add-Type と [Reflection.Assembly] - tech.guitarrapc.cóm
http://tech.guitarrapc.com/entry/2014/03/17/042253

#保存形式と保存画質の初期設定
$myEncoder=[System.Drawing.Imaging.Encoder]::Quality
$encoderParams=New-Object System.Drawing.Imaging.EncoderParameters(1)
$encoderParams.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter($myEncoder, $quality)


ここでJPEGの品質を設定しています。まずJPEGエンコーダのQualityクラスを示すGUIDを取得、エンコーダのパラメータを設定/保存するためのオブジェクトを作成、その後そのオブジェクトに品質を設定するためのオブジェクトを作成しています。$qualityが品質になります。0~100で設定し、0が最低、100が最高です。0だと笑えるぐらいひどい画質。90以上なら実用的かと。

#画像保存形式jpgの読み込み
$myImageCodecInfo = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders()|where {$_.MimeType -eq 'image/jpeg'}


ここではエンコーダ(保存形式)の一覧を取得し、その結果からJPEGに一致するMimeTypeを探し、それを変数に保存しています。結果として、ビルトインJPEGエンコーダオブジェクトがこの変数に保存されます。この変数は後の保存時に使用されます。

#サムネイル用のフルパスとファイル名生成(フッタをつける)
$jpgfullpath=Join-Path $scriptPath $jpgfile
$jpgafter2= (Get-ChildItem $jpgfullpath).basename
$jpgafter3= (Get-ChildItem $jpgfullpath).extension
$jpgafter4=$jpgafter2+$thumb_footer+$jpgafter3


元のファイル名にフッタ文字を付けるための処理です。まず元のファイルがあるフルパスからファイル名と拡張子をそれぞれ取得、その後ファイル名にフッタ文字と拡張子を文字列結合しています。

# 画像ファイルの読み込み
$image = New-Object System.Drawing.Bitmap($jpgfullpath)


画像の読み込みはこれだけでOK。ビルトインエンコーダを見ると、BMP,JPG,GIF,PNG,TIFFに対応しているようです

#縦横の大きい方を初期設定$thumb_size_maxにする、アスペクト比保持
#$thumb_size_maxより小さいならサイズを変えずそのまま。つまりサムネイル生成の意味は無い(笑)。
$image_x=$image.Width
$image_y=$image.Height
if(($image_x -gt $thumb_size_max )-or ($image_y -gt $thumb_size_max )){
   if($image_x -gt $image_y){
     $image_y=[int]($image_y*($thumb_size_max/$image_x))
     $image_x=$thumb_size_max
   }else{
     $image_x=[int]($image_x*($thumb_size_max/$image_y))
     $image_y=$thumb_size_max
   }
}


画像の幅と高さのどちらかが指定サイズ$thumb_size_max以上なら、長辺をこのサイズに縮小、短辺をアスペクト比を保持しながら縮小します。整数化のため[int]を付けています。こうでないと縮小処理時にエラーが出たので。
あと、比較演算子に<>は使えません。これらはリダイレクト演算子と扱われるので動作がおかしくなります。
参考:PowerShellの演算子一覧 - しばたテックブログ
https://blog.shibata.tech/entry/2015/12/03/000000

#キャンバスサイズの決定
$canvas = New-Object System.Drawing.Bitmap($image_x,$image_y)
# 縮小先へ描画
$graphics = [System.Drawing.Graphics]::FromImage($canvas)

縮小先を描画するための画像を動的生成しています。

#高品質リサイズに設定変更。速度最優先ならHighQualityBicubic→NearestNeighborかDefaultに。
#いわゆるバーコード/2次元コードはNearestNeighbor推奨。他だとボケて読めない。
$graphics.InterpolationMode=[System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic $graphics.DrawImage($image, (New-Object System.Drawing.Rectangle(0,0,$canvas.Width,$canvas.Height)))

今回のキモ。縮小描画です。
まず、縮小画像を書き込むキャンバスの拡大縮小方式を選択しています。拡大縮小方式はいくつかありますが、ここでは写真等の拡大縮小に適したHighQualityBicubicを選択しています。 その後、そのキャンバスに元の画像を縦横を指定して描き込みます。
結果として、縮小画像がこのキャンバスに描画されます。
拡大縮小形式については以下を参照ください。
InterpolationMode Enum (System.Drawing.Drawing2D) | Microsoft Docs
https://docs.microsoft.com/en-us/dotnet/api/system.drawing.drawing2d.interpolationmode?view=netframework-4.7.2
補間方法を指定して画像を拡大、縮小(スケーリング)表示する - .NET Tips (VB.NET,C#...)
https://dobon.net/vb/dotnet/graphics/interpolationmode.html

# 保存(jpg,品質はこのスクリプトの頭で設定)
$canvas.Save($jpgafterfull, $myImageCodecInfo,$encoderParams)

ここで、サムネイル出力先のファイルに、画像形式(今回はJPEG)と保存品質を指定して保存しています。

# オブジェクトの破棄
$graphics.Dispose()
$canvas.Dispose()
$image.Dispose()

一時的に使用したキャンバスの破棄です。変に残っていると不具合の元ですので。

その他は・・・省略します。HTML生成部分はホスト出力とファイル出力の塊、ヒアドキュメントまで使っています。便利に改造したい方はお好きなように、どんな改造をしたか教えて頂けると嬉しいです。


Comments:0

Comment Form

Trackbacks:0

TrackBack URL for this entry
http://pc-diary.com/movt_direc_post/mt-tb.cgi/1670
Listed below are links to weblogs that reference
Windows PowerShellのスクリプトだけで画像のサムネイル生成をした話 from PC破壊日記的ブログ
  • タグ: .NET Framework, Powershell, サムネイル, サムネイル作成
  • Home > ソフト公開 > Windows PowerShellのスクリプトだけで画像のサムネイル生成をした話

    2進数時計
    ※クリックで読みやすくなります。
    ※この時計の時刻は、閲覧しているパソコンのものであり、必ずしも正確な時間とは限りません
    Search
    Feeds

    Google Adsense
    Tag Cloud

    このページの最初に戻る