📸
PowerShell で raw データの撮影日時を読み取る力業
撮り溜めた Canon の raw データを整理するにあたり、各写真の撮影日時を取得してみようと思います。
raw データの中身を見る
有志による CR2ファイルの仕様解析 によると、ファイル先頭部分に各種のメタ情報が記述されているようです。
PowerShell では Format-Hex
コマンドレットでファイルを16進数ダンプ表示できます。とりあえず先頭の512バイトを見てみると……
所々に見覚えのある文字列が出現します。
手元のファイルをひと通り見たところ、どれも先頭から324バイト行ったところから yyyy:MM:dd hh:mm:ss
形式でタイムスタンプが保存されているようです。ということで、この部分を機械的に取り出してみましょう。
コード
function Get-CR2Timestamp {
param (
[parameter(ValueFromPipeline = $true)]$inputObj
)
begin {}
process {
$fileObj = Get-Item $inputObj
if ($fileObj.Extension -ne ".CR2") {
return [PSCustomObject]@{
Name = $fileObj.Name
Timestamp = ""
}
}
$bytes = Get-Content $fileObj.FullName -AsByteStream -TotalCount (324 + 19) | Select-Object -Last 19
$decoded = [System.Text.Encoding]::ASCII.GetString($bytes)
$date = [Datetime]::ParseExact($decoded, "yyyy:MM:dd HH:mm:ss", $null)
$timestamp = $date.ToString("yyyy_MMdd_HHmmss00")
return [PSCustomObject]@{
Name = $fileObj.Name
Timestamp = $timestamp
}
}
end {}
}
実行イメージ↓
> Get-CR2Timestamp .\IMG_6000.CR2
Name Timestamp
---- ---------
IMG_6000.CR2 2021_0203_23245000
パイプ経由でもファイルを渡すこともできます↓。
> ls "*cr2" | Get-CR2Timestamp
Name Timestamp
---- ---------
IMG_6000.CR2 2021_0203_23245000
リネーム関数
リネーム処理もコマンドレット化してみました。
下記コマンドレットに CR2 ファイルをパイプで渡すと一括でファイル名の先頭にタイムスタンプを挿入します。
function Rename-CR2Timestamp {
$input | Where-Object Extension -eq ".CR2" | ForEach-Object {
$itemName = $_.Name
$timestamp = ($_ | Get-CR2Timestamp).Timestamp
if ($timestamp) {
$newName = "{0}_{1}" -f $timestamp, $itemName
try {
"RENAMED: '{0}' => '{1}'" -f $itemName, $newName | Write-Host -ForegroundColor Cyan
$_ | Rename-Item -NewName $newName -ErrorAction Stop
}
catch {
"ERROR!: failed to rename '{0}'!" -f $itemName | Write-Error
}
}
}
}
各ファイルの最終更新日時(LastWriteTime)をみるという方法もありますが、微妙に違う値に書き換わっていることがあったのでこの方法を採用しました。
Discussion