【PowerShell】画像ファイルを一括リネームして、Exif情報も反映する

Code

はじまり

リサちゃん
リサちゃん

なんか最近使ってたリネームアプリが、

ダウンロードできなくなっちゃたよお。

135ml
135ml

あらまあ

リサちゃん
リサちゃん

もうこの写真たちのファイル名はこのままなのかしら・・・

135ml
135ml

じゃあリネーム出来るようにしよう。

重宝していたアプリが消えた・・・

つい最近までこんなリネームアプリを使っていたのですが、機種変更してOSバージョンが上がったら使えなくなってしまいました・・・

なので、そろそろこのりネーム機能を作りますか・・・

ファイルのリネームの基本

PowerShellでファイルをリネームする基本コマンドは Rename-Item です。このコマンドは -Path パラメータで指定されたファイルの名前を -NewName パラメータで指定された新しい名前に変更します。

画像ファイルを一括でリネームする

画像ファイルの一括リネームは、デジタルアセットの整理、アップロード前の準備、またはバックアッププロセスの一環として非常に便利です。

基本コマンド

Get-ChildItem -Path "C:\Images\" -Filter *.jpg | Rename-Item -NewName { $_.Name -replace '旧文字列','新文字列' }

このコマンドは、指定したディレクトリ(この例では C:\Images\)内のすべてのjpgファイルを対象に、ファイル名内の「旧文字列」を「新文字列」に置換します。

このコマンドの詳細

少し噛み砕きます。

ファイルの選択

Get-ChildItem -Path "対象ディレクトリ" -Filter *対象ファイル形式*

このコマンドは、指定したディレクトリ内の特定のファイル形式(例:.jpg、.png)を検索します。

リネームの実行

リネームプロセスでは、新しいファイル名の形式を定義する必要があります。これは、ファイルの作成日、撮影日、またはシーケンス番号を含むことができます。

| Rename-Item -NewName { 新しいファイル名の定義 }

このパイプライン (|) コマンドは、直前のコマンドレットで選択したファイルを次のコマンドレットに渡します。

今回はRename-Itemに渡してリネーム操作を適用します。

ファイルの最終更新日からリネームする

この例では、ファイルの最終書き込み時刻を使用して、画像ファイルを「年月日時分秒.jpg」の形式でリネームします。$_.Extensionを忘れないようにですね。

Get-ChildItem -Path "C:\Images\" -Filter *.jpg | Rename-Item -NewName { $_.LastWriteTime.ToString('yyyyMMddHHmmss') + $_.Extension }

で、ここまで書いたのですが、「ファイルの最終更新日」でリネームしてしまうと、スマホから撮った写真をPCに「コピーした時の日時」でリネームてしまいます。

なので、ここからはもう少し深い部分に入ります。

Exif情報からリネームする

そこで、別の情報からファイルのリネームを掛けていきたいと思います。

画像ファイルは、「Exif」という情報を持っています。(Exchangeable image file formatというらしいです。)

カメラのISOだったり、F値だったりその時に撮影したカメラの情報とかが画像ファイルの中に色々と入っているわけです。

そして、そのExifの情報の中には「ファイルの作成日時」が存在します。PowerShell標準の「CreationTime」でも出来そうなもんですが、今回はそのカメラの情報も欲しいので、Exifという角度から切り込みます。

Exif取得に使うツール

今回、Exif取得に使うツールは、Phil Harveyさんが開発している「ExifTool」というものです。この方面では一般的なツールみたいですね。

このサイトからexeをダウンロードしていきましょう。

ExifTool by Phil Harvey
A command-line application and Perl library for reading and writing EXIF, GPS, IPTC, XMP, makernotes and other meta info...

ExifToolを使って、ファイル作成日時からリネームする

使っていきます。以下のコマンドを実行する際には、実行ディレクトリに「exiftool.exe」を配置して使っていきます。

詳しい使い方・仕様は、ダウンロードサイトにありますが、実際に実行してみたいコマンドを以下で紹介します。

ファイルのCreateDateからリネームする

まずは、ファイルの作成日時からリネームしていきましょう。

流れとしては、

  • Start-Processで実行する処理のプロセスを設定。(-PassThruを入れないとプロセスの戻り値を取れません。-waitでプロセス終了まで待ちます。)
  • "${folderDir}\exiftool"でディレクトリ内にある「exiftool.exe」を指定します。
  • exiftoolに使う引数は、-ArgumentListの引数の中に配置します。
  • -ArgumentListの引数の中には、"-FileName<CreateDate"を指定して、ファイルの作成日時からファイル名を変えるようにします。フォーマットは、"%Y%m%d%H%M%S.%%e"として名付けます。
$username = (Get-ChildItem Env:\USERNAME).Value;
$folderDir = "C:\Users\${username}\Downloads\picture_backup";
cd $folderDir;
$proc = Start-Process -FilePath "${folderDir}\exiftool" -ArgumentList "-FileName<CreateDate","-d","%Y%m%d%H%M%S.%%e",$folderDir -NoNewWindow -PassThru -wait;
Write-Host $proc.ExitCode;

CreateDateフィールドを作る(画像ファイル版)

しかし、ファイルによっては、「CreateDate」のフィールドがない画像ファイルがあったりもします。

その場合に、CreateDateフィールドを作ってあげましょう。

次は、"-CreateDate<FileCreateDate"と引数に指定して、

cd 1-2_create_date_setting;
$username = (Get-ChildItem Env:\USERNAME).Value;
$toCreateDateDir = "1-2_create_date_setting";
$folderDir = "C:\Users\${username}\Downloads\picture_backup\${toCreateDateDir}";
$proc = Start-Process -FilePath "${folderDir}\exiftool" -ArgumentList "-CreateDate<FileCreateDate","-d","%Y:%m:%d:%H:%M:%S",$folderDir -NoNewWindow -PassThru -wait;
Write-Host $proc.ExitCode;

CreateDateフィールドを作る(動画ファイル版)

しかしながら、画像ファイルと違って、僕が撮影した動画ファイルの「CreateDate」には、実際に撮影した日時とは別の情報が入っていました。

そこで次は、"-CreateDate<FileModifyDate"と引数に指定して、Exif内にある更新日時から「CreateDate」の情報を作成します。

cd 1-1_movie_escaping;
$username = (Get-ChildItem Env:\USERNAME).Value;
$toCreateDateDir = "1-1_movie_escaping";
$folderDir = "C:\Users\${username}\Downloads\picture_backup\${toCreateDateDir}";
$proc = Start-Process -FilePath "${folderDir}\exiftool" -ArgumentList "-CreateDate<FileModifyDate","-d","%Y:%m:%d:%H:%M:%S",$folderDir -NoNewWindow -PassThru -wait;
Write-Host $proc.ExitCode;

しかし、もうファイル作成日時の情報が一切無い場合もある。

しかしながら、もう作成日時の情報がファイルの中に一切無い場合もあります。(LINEからダウンロードする時とか。)

なので、そういうイレギュラー画像ファイルには、もう自分が日時を指定してリネームしてあげるしかありません!

PowerShell上でプロンプトしてリネームしましょう。

**$number = 1
$date_formatted = Get-Date -Format "yyyyMMddHH"
$date_formatted = Get-Date -Format "yyyyMMddH"
$year_this = Get-Date -UFormat "%Y"
$year_last = Get-Date (Get-Date).AddYears(-1) -UFormat "%Y"
$iscorrect = $false
while($iscorrect -eq $false){
  $date_formatted = Read-Host "Input prefix of pictures (yyyyMMddHH)"
	if($date_formatted.length -eq 10 -and $date_formatted -like "${year_this}*" -or $date_formatted -like "${year_last}*"){
		$iscorrect = $true
	}
}
Get-ChildItem -Path . -File | ForEach-Object {
  if($_ -notlike "${year_this}*" -and $_ -notlike "${year_last}*" -and $_ -notlike "*.exe" -and $_ -isnot [System.IO.DirectoryInfo]){
		Write-Host $_.GetType() "true" $_.Name
		$number_zeropadded = "{0:0000}" -f $number
		$ext = [System.IO.Path]::GetExtension($_)
		$newName = "${date_formatted}${number_zeropadded}${ext}"
		Write-Host $newName
		Rename-Item -Path ".\${_}" -NewName $newName
		$number++
  }else{
		Write-Host $_.GetType() "false" $_.Name
	}
}**

そして、加工した画像ファイルに、Exif情報を与える

しかし、ここまででは筆者は終わりたくありません。

最近のフラッグシップスマホのカメラで撮る画像ファイルって、容量がデカくありませんか? 5MBなんて優に超えますよね。

なので、僕は画像ファイルをjpg→webpに変換して容量を下げて、そのwebpに対してExif情報を付与し直すこともしてみました。

Exif情報を元JPGファイルから与える

デカすぎる画像ファイルをwebpに加工した後、その元jpgファイルが立ち並ぶディレクトリの中にwebpファイルを格納します。

そうしたら、このコマンドでwebpにExif情報を与えます。

Get-ChildItem *.webp | ForEach-Object {
  $jpg = $_.BaseName + ".jpg";
  if (Test-Path $jpg) {
    $webpFilePath = $_.FullName;
    Start-Process -FilePath exiftool.exe -ArgumentList "-tagsFromFile",$jpg,"-exif:all",$webpFilePath -NoNewWindow -Wait;
  }
}

Exif情報を元JPGファイルから与える(DOS版)

僕は当初、DOSから全てのコマンドを実行したかったので、このコマンドのDOS実行バージョンもあります。

  • STARTでプロセスを実行、/WAITオプションでPowerShellの処理終了までPowerShellを開きっぱなしにします。
  • -Commandの中に、PowerShellで実行するコマンドを書きます。
  • そのコマンドの中の、ダブルクォーテーションはバックスラッシュ(円マーク)でエスケープしてあげましょう。
START /WAIT powershell -Command "Get-ChildItem *.webp | ForEach-Object {$jpg = $_.BaseName + \".jpg\"; if (Test-Path $jpg) {$webpFilePath = $_.FullName; Start-Process -FilePath exiftool.exe -ArgumentList \"-tagsFromFile\",$jpg,\"-exif:all\",$webpFilePath -NoNewWindow -Wait}}"

こうすると、Googleフォトにて・・・

上記の処理をしてあげることで、Googleフォトにアップロードすると、
①容量が減ったwebpの状態で、②撮影日時を保持した状態で、③カメラの情報も保持した、写真が出来上がります!

まとめ

本記事のまとめです。

  • PowerShellから、ファイルのLastWriteTimeを見てファイルをリネーム出来る。
  • しかし、もう少しちゃんとリネームしたかったら、「ExifTool」を使うのがオススメ。
  • 「ExifTool」では、CreateDateフィールドを使って撮影日時でリネーム出来る。
  • CreateDateフィールドが無い場合は、画像では「FileCreateDate」、動画では「FileModifyDate」フィールドから編集できる。
  • ファイルのExif情報に全く情報がない場合は、自動採番したり、別の画像ファイルからExif情報を引っ張れる。

PowerShellは最近使ってなかったので、改めて便利だなと感じました。

おしまい

リサちゃん
リサちゃん

なんかExifでリネームするはずが、カメラの情報まで出てくるとは・・・

135ml
135ml

ファイルの情報量って、思った以上に深かったな。

以上になります!

コメント

タイトルとURLをコピーしました