概要
画像のExif情報を取得するサンプル。
コード
例1. タグID一覧
JPEG画像のExifタグIDを取得する。
例1
Add-Type -AssemblyName System.Drawing
# 画像読み込み
$img = New-Object Drawing.Bitmap("C:\Work\hoge.jpg") # フルパスで指定
# ExifタグID一覧を表示
$img.PropertyItems | Select-Object Id | Sort-Object {[int]$_.Id}
# 以下、実行結果
Id
--
1
2
3
4
271
272
274
282
283
296
305
531
20545
:
# 後始末
$img.Dispose()
$img = $null
例2. 撮影日
JPEG画像のExif情報から撮影日を取得する。
例2
Add-Type -AssemblyName System.Drawing
# 画像読み込み
$img = New-Object Drawing.Bitmap("C:\Work\hoge.jpg")
# オリジナル画像データの生成日時を取得
$byteAry = ($img.PropertyItems | Where-Object{$_.Id -eq 36867}).Value
# 取得した日時を表示
[System.Text.Encoding]::ASCII.GetString($byteAry) # バイト配列を文字列に変換
# 実行結果
2016:06:04 09:34:44
# 後始末
$img.Dispose()
$img = $null
例3. 実用サンプル
画像ファイルと動画ファイルを一括で日付つきのファイル名にリネームする。
JPEG画像の場合はExif情報から撮影日を取得する。
デジカメ・スマホ等で撮った画像・動画の整理に。
例3
Add-Type -AssemblyName System.Drawing
if ((Test-Path Variable:\Exif_DateTimeOriginal) -eq $false)
{
# Exifタグ:オリジナル画像データの生成日時
New-Variable -Name Exif_DateTimeOriginal -Value 36867 -Option ReadOnly
}
<#
.SYNOPSIS
指定フォルダに存在しないファイル名を取得
.PARAMETER filePath
ファイルのパス
.PARAMETER baseFileName
ファイル名先頭部分
.PARAMETER ext
拡張子(ピリオド付き)
.OUTPUTS
指定フォルダにまだ存在しないファイル名を返す。
ファイル名取得失敗時はnullを返す。
#>
function GetUnusedFileName(
[Parameter(Mandatory)][string]$filePath,
[Parameter(Mandatory)][string]$baseFileName,
[Parameter(Mandatory)][string]$ext)
{
# ファイル名の先頭部分組み立て
[string]$pathHead = Join-Path -Path $filePath -ChildPath ($baseFileName + "_")
# 「ファイル名_連番.拡張子」の形式で連番を1~999までで未使用のものを探す
for ([int]$i = 1; $i -le 999; $i++)
{
# 完全なファイルパス組み立て
[string]$fullFilePath = $pathHead + $i.ToString("000") + $ext
# ファイル存在チェック
if ((Test-Path $fullFilePath) -eq $false)
{
# 見つからなかったのでこのファイル名を使用する
return Split-Path $fullFilePath -Leaf
}
}
# 取得失敗
return $null
}
<#
.SYNOPSIS
JPEG画像ファイルをリネーム
.PARAMETER fileItem
ファイルオブジェクト
.PARAMETER ext
リネーム後の拡張子(デフォルト ".jpg")
#>
function RenameJpegFile(
[Parameter(Mandatory)]$fileItem,
[string]$ext = ".jpg")
{
# ファイル更新日を取得
$fileDate = $fileItem.LastWriteTime
$img = New-Object Drawing.Bitmap($fileItem.FullName)
# Exif情報取得
[byte[]]$byteAry = ($img.PropertyItems | Where-Object{$_.Id -eq $Exif_DateTimeOriginal}).Value
# 取得成功?
if ($byteAry -ne $null)
{
# 「yyyy:MM:dd HH:mm:ss」 →
# 「yyyy/MM/dd HH:mm:ss」になるよう年月日の区切りを「/」で上書き
$byteAry[4] = 47
$byteAry[7] = 47
# バイト配列を文字列に変換
[string]$dateStr = [System.Text.Encoding]::ASCII.GetString($byteAry)
# Exif情報の日付を設定
$fileDate = [datetime]$dateStr
}
$img.Dispose()
$img = $null
# 新しいファイル名の先頭部分組み立て
[string]$fileNameHeader = "img" + $fileDate.ToString("yyMMdd_HHmmss")
# 新しいファイル名取得
[string]$newFileName = GetUnusedFileName $fileItem.DirectoryName $fileNameHeader $ext
if ($newFileName -ne $null)
{
# リネーム
Write-Host ($fileItem.Name + " -> " + $newFileName) -ForegroundColor DarkGray
Rename-Item -LiteralPath $fileItem.FullName -NewName $newFileName
}
}
<#
.SYNOPSIS
MOV動画ファイルをリネーム
.PARAMETER fileItem
ファイルオブジェクト
.PARAMETER ext
リネーム後の拡張子(デフォルト ".mov")
#>
function RenameMovFile(
[Parameter(Mandatory)]$fileItem,
[string]$ext = ".mov")
{
# ファイル更新日を取得
$fileDate = $fileItem.LastWriteTime
# 新しいファイル名の先頭部分組み立て
[string]$fileNameHeader = "mov" + $fileDate.ToString("yyMMdd_HHmmss")
# 新しいファイル名取得
[string]$newFileName = GetUnusedFileName $fileItem.DirectoryName $fileNameHeader $ext
if ($newFileName -ne $null)
{
# リネーム
Write-Host ($fileItem.Name + " -> " + $newFileName) -ForegroundColor DarkGray
Rename-Item -LiteralPath $fileItem.FullName -NewName $newFileName
}
}
<#
.SYNOPSIS
画像・動画ファイルをリネーム
.DESCRIPTION
【概要】
引数のファイルパス(ワイルドカード指定可)から
特定の画像と動画ファイル(*.jpg, *.jpeg, *.mov)をリネームする。
下層のフォルダは見ない。
【説明詳細】
jpg画像(*.jpg, *.jpeg)の場合、
Exifタグから日付を取得し、ファイル名に使用する。
取得できない場合はファイルの更新日を使用し、以下のフォーマットでリネームする。
"img" + yyMMdd_HHmmss_ + 連番3桁 + ".jpg"
例)
img161122_134055_001.jpg
動画(*.mov)の場合、
ファイルの更新日を使用し、以下のフォーマットでリネームする。
"mov" + yyMMdd_HHmmss_ + 連番3桁 + ".jpg"
例)
mov161122_134055_001.mov
その他のファイルの場合、
何もしない。
.PARAMETER wildcardFilePath
対象ファイルパス(ワイルドカード指定可)
.EXAMPLE
RenameMediaFiles .\*.mov
カレントディレクトリの拡張子movのファイルを処理する
.EXAMPLE
RenameMediaFiles C:\Work\IMGFILE*.*
C:\WorkにあるIMGFILEで始まる全てのファイルを処理する
#>
function RenameMediaFiles([Parameter(Mandatory)][string]$wildcardFilePath)
{
# ディレクトリは除外してファイルだけを処理する
Get-ChildItem -Path $wildcardFilePath |
Where-Object { -not $_.PsIsContainer } |
ForEach-Object {
$fileItem = $_
[string]$ext = $fileItem.Extension.ToLower()
switch ($ext)
{
".jpg" { RenameJpegFile $fileItem; break }
".jpeg" { RenameJpegFile $fileItem; break }
".mov" { RenameMovFile $fileItem; break }
}
}
Write-Host "処理完了" -ForegroundColor Green
}
例3の実行方法
# (1) 例3の関数群を読み込む
# (2) カレントディレクトリを対象ファイルのある場所に移動。(3)でフルパス指定でも可
cd C:\Work\RenameTmp
# (3) リネーム実行
RenameMediaFiles .\MEDIAFILE*.*
動作確認した環境
- PowerShell V4 (Windows 8.1)
- PowerShell V5 (Windows 10)