■ JPEG更新日時一括変更ツールを作る #5

JPEGファイルのファイル名先頭に "日時" を付加し、その日時でJPEGファイルの更新日時を変更させるツールを作成したい。
#4 からの続き

本文中の "$" は半角で読み替えること。


Googleフォトにアップした際、時刻が-9時間される問題、とりあえずの回避策としてExif情報の撮影日時を付加するように、前回作成したスクリプトに機能を追加する。
変更点としては、
・第2引数に出力先パスを追加
・第1引数で指定したパス内のJPEGファイルにEXIF情報(撮影日時)を付加し、第2引数のパスに出力。
・これまで通り更新日時の更新も行うが、この更新は第2引数で指定したファイルに対して行う。

PeopertyItemオブジェクトの取得

参考:PowerShellでExif情報を書き込むには? #1
上記サンプルでは、PropertyItemを追加するため、既存のPropertyItemの先頭項目を取得していた。
しかし、追加しようとするIdが既にPeopertyItemsに存在する場合はどうするか?を考えると、
・登録したいIdを指定しProperyItemを取得
・見つからなければ先頭のPropertyItemを取得
とした方が良いのかもしれない。
→ と思ったが、この方法だと、取得したPropertyItemに値をセットしSetPropertyItemを行う時に、既にIdが存在しているのに、そのIdでSetPropertyItemを行ってしまいダメな気がする。
ということで、以下の方法に変更
・登録したいIdを指定しProperyItemを取得
・取得できたら RemovePropertyItem でアイテムを削除
・先頭のPropertyItemを取得
これらを踏まえ以下の関数を作成する。引数$imageは対象画像ファイルのBitmapオブジェクトである。
        function GetPropertyItem($image, $id)
        {
          $item = $image.PropertyItems | Where-Object { $_.Id -eq $id }
          if($item -ne $null) {
            $image.RemovePropertyItem($id)
          }
          return $image.PropertyItems | Select-Object -First 1
        }
        

PropertyItemオブジェクトの登録

ExifVersionや撮影日時などのPropertyItemを登録する汎用的な関数を作成。
引数として$image(Bitmapオブジェクト)、設定するId,Len,Type,Valueは引数より取得する。
ベースとなるPropertyItemオブジェクトは、先ほど作成したGetPropertyItem関数を使用。
        function SetPropertyItem($image, $id, $len, $type, $value)
        {
          $item = GetPropertyItem -image $image -id $id
          $item.Id = $id
          $item.Len = $len
          $item.Type = $type
          $item.Value = $value
          $image.SetPropertyItem($item)
        }
        

ExifVersionの登録

作成したSetPropertyItem関数を使いExifVersion(Id:9000)を登録する。
登録するバージョンは"0210"固定(ASCIIコードでは 48,50,49,48)とする。
        function SetExifVersion($image)
        {
          SetPropertyItem -image $image -id 0x9000 -len 4 -type 7 -value @(48,50,49,48)
        }
        

撮影日時データの取得

前回のスクリプトで、ファイル名より取得した日時は、日付型変数 $fileDate にセットしていた。
この変数値よりExif情報用の撮影日時(書式は "yyyy:MM:dd HH:mm:ss")を取得しASCII文字配列へ変換する。
この処理を行う関数 getDateTimeValue を追加する。
        function getDateTimeValue($dateTime)
        {
          $chars = $dateTime.ToString("yyyy:MM:dd HH:mm:ss").ToCharArray()
          $ascii = @()
          foreach($char in $chars)
          {
            $ascii += [Byte][Char]$char
          }
          $ascii += 0
          return $ascii
        }
        

撮影日時の登録

getDateTimeValue関数で撮影日時のASCIIコードデータを作成、その値を Id:9003とId:90004 に登録する。
        function SetDateTime($image, $dateTime)
        {
          $value = getDateTimeValue -dateTime $dateTime
          SetPropertyItem -image $image -id 0x9003 -len 20 -type 2 -value $value
          SetPropertyItem -image $image -id 0x9004 -len 20 -type 2 -value $value
        }
        

画像ファイルにExif情報を設定し別ファイルとして保存

(2020.09.17改版) 変数名ルール:"~Path"でなく"~Dir"へ統一 → $outputPath → $outputDirとする
(2020.09.17改版) バグ修正:関数1行目の"$inputFile"だけの行を削除
$inputFileで指定した画像ファイルをオープン、$dateTimeで指定した撮影日時を設定し、設定した画像ファイルを$outpubDirで指定したディレクトリ保存する関数を作成する。
関数戻り値として、出力した画像ファイルのフルパスを返す。
        function SetExifInfo($inputFile, $outputDir, $dateTime)
        {
          $image = New-Object System.Drawing.Bitmap($inputFile)
          SetExifVersion -image $image
          SetDateTime -image $image -dateTime $dateTime
        
          $outputFile = Join-Path $outputDir (Split-Path $inputFile -Leaf)
          $image.Save($outputFile)
        
          $image.Dispose()
        
          return $outputFile
        }
        

メイン処理の修正

(2020.09.17改版) 拡張子は "jpeg" または "jpg" どちらでも可能とするように修正
引数で取得したパス内の画像ファイルを取得し、SetExifInfo関数を呼び出しExif情報を付加する。
SetExifInfo関数は設定した画像ファイルのフルパスを戻り値として返すので、このファイルに対して更新日時の設定を行う。
        $files = Get-ChildItem -Path $inputDir | Where-Object {$_.Name -Match "^\d{8}_\d{4}_[^.]*\.(jpeg|jpg)"}
        
        foreach ($file in $files)
        {
          try {
            $fileDate = [DateTime]::ParseExact($file.Name.Substring(0, 13), "yyyyMMdd_HHmm", $null)
            $outputFile = SetExifInfo -inputFile $file.FullName -outputDir $outputDir -dateTime $fileDate
            Set-ItemProperty $outputFile -Name LastWriteTime -Value $fileDate
            Write-Host( "[OK] " + $file.Name)
          } catch {
            Write-Host( "[ER] " + $file.Name + "`r`n" + $_)
          }
        }
        

#6 へ続く




自作プログラム, PowerShell, Exif
2020.09.17改版

0 件のコメント:

その他の記事