亀の甲羅2

今日もまた朝とく起きて励まなん窓に明るきありあけの月

MS Bing にpowershellのスクリプトを作らせてみた

Bing がなかなかできるやつだと聞いたので、ちょっとお試ししてみた。

powershellで画像のExif情報を削除するスクリプトを作成して下さい。」

で、Bingちゃんがくれた回答が下記の通り。まだ動作確認してないけど、直感でこれはイケてるって思えるコード。

param(
    [string]$Path
)

Add-Type -AssemblyName System.Drawing

$image = [System.Drawing.Image]::FromFile($Path)
$propertyItems = $image.PropertyItems

foreach ($item in $propertyItems) {
    $image.RemovePropertyItem($item.Id)
}

$image.Save($Path)
$image.Dispose()

質問の内容によっては、単純なキーワード検索と同じになってしまうこともあるが、
生成させるような問いかけにはなかなか強い感じがする。
知識の集積とその知識の使い方を理解していて、問いかけの意図も理解した上で回答をくれる。
調べる必要がない(英語圏の資料まで読んで知識を集める・・・みたいなこと)ので、楽と言えば楽だが、
考える楽しみまで奪われてしまっているような気持ちになるな。


ちょっと続き。

powershellで画像のExif情報を削除するスクリプトを作成して下さい。Exif情報を削除する処理は関数化して、指定のディレクトリ配下のjpgファイルを再帰的に検索して、その関数でExif情報を削除する形にして下さい。」

で、Bingちゃんがくれた回答が下記の通り。

function Remove-Exif {
    param(
        [string]$Path
    )

    Add-Type -AssemblyName System.Drawing

    $image = [System.Drawing.Image]::FromFile($Path)
    $propertyItems = $image.PropertyItems

    foreach ($item in $propertyItems) {
        $image.RemovePropertyItem($item.Id)
    }

    $image.Save($Path)
    $image.Dispose()
}

$directory = "C:\Images"
Get-ChildItem -Path $directory -Filter *.jpg -Recurse | ForEach-Object {
    Remove-Exif -Path $_.FullName
}

そこら辺の新人よりもまともな回答をよこしやがる。。。


で、動作検証した結果、うまくいかない。

"1" 個の引数を指定して "Save" を呼び出し中に例外が発生しました: "GDI+ で汎用エラーが発生しました。"
発生場所 \Desktop\Exif削除.ps1:18 文字:5
+     $image.Save($Path)
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ExternalException

というエラーが出る。どうやら、Saveが同名上書きができないようだ。

さて、別名を作成してSaveしてみたが、RemovePropertyItem の挙動がおかしい。Exifが削除されない。

以下の方もそのことに気づいており、2014年にブログ化されている。ここでは、下記の方の手法をまねさせていただいた。

[C#] 画像ファイルからExif情報を削除するには – 端くれプログラマの備忘録

自分が手直しした版は下記の通り。
なんかファイルサイズが半分くらいになるので冗長なデータが削除されている?かもしれない。
画像サイズや見た目には影響がないが、Exif以外の部分がバイナリレベルで元ファイルと同一かは保証しかねる。

$directory = "C:\image"

function Remove-Exif {
    param(
        [string]$Path
    )

    Add-Type -AssemblyName System.Drawing

<#
    $image = [System.Drawing.Image]::FromFile($Path)
    $propertyItems = $image.PropertyItems

    $propertyItems = $image.PropertyItems

    foreach ($item in $propertyItems) {
        $image.RemovePropertyItem($item.Id)
    }
#>

    # Bitmapで複製
    $image = New-Object System.Drawing.Bitmap ($path)
    $image2 = New-Object System.Drawing.Bitmap ($image)

    # 複製後のファイル名を作成($pathはStringなのでItemオブジェクトに変換して利用)
    $a = (Get-Item -LiteralPath $Path)
    $path2 = JOIN-PATH $a.DirectoryName ($a.BaseName + "_noExif.jpg")

    # 複製した方を保存(Jpeg指定しないとPNG形式で保存された)
    $image2.Save(($Path2), [System.Drawing.Imaging.ImageFormat]::Jpeg )
    $image.Dispose()
    $image2.Dispose()
}

#--- main ---

Get-ChildItem -Path $directory -Filter *.jpg -Recurse | ForEach-Object {
    Remove-Exif -Path $_.FullName
}