2018年1月14日日曜日

NASに保存した写真のタイムスタンプを撮影時刻に書き換える

スマホやデジカメが手軽に使えるようになり、写真を撮影することが多くなった。
メモリカードの大容量化も進み、今では膨大な枚数が記録できる。

とはいえ、メモリカードの容量も寿命も無限ではない。いつかは飽和するし、いつかは壊れる。
思い出の写真を失ってしまう事を防ぐには、Backupするのが良い。

というわけで、写真をNAS上に保存している人も多いだろう。
諸行無常であることを考慮すればNASもいつかは壊れるのだが、RAID1でミラーリングしておけば、どちらか1方のHDDが壊れた時にもう一方のHDDからデータを救出できる。
すなわち、ミラーリングにより「どうにもならない状態」を回避できる可能性がある。

最近のTVはNASをアクセスすることもできるので、TVで写真を見るためにもNASへ保存したほうが良い。

ところがここで問題が生じる。
NASへファイルをコピーすると、写真のタイムスタンプがコピーした時刻になってしまうのだ(Linuxだからかな?)。
デジカメとスマホというように、複数のソースがある場合、それぞれのソース毎に連続的なタイムスタンプになり、撮影した順序にならない。
TVでの表示は撮影順ではなく、NASへ保存した順になり、写真の探索が困難になる。(うちのTVだけ?)

できれば、デジカメもスマホも合わせて、撮影した順序になってほしい。
実は多くのデジカメやスマホで撮影された写真の撮影日時情報は、tag情報として写真の中に記録されている。

というわけで、私は自分で書いたshell-scriptを使って、NASへ写真をコピー後、タイムスタンプを写真の撮影時刻に書き換えている。
以下に示す:
#!/bin/bash
# it depend imagemagick package. Install it as:
#   sudo apt-get install imagemagick
#
scriptName=$(basename $0);

if [ -z "$*" ]; then
    echo "JPEG撮影時刻を、ファイルのタイムスタンプにする。"
    echo "Usage: $scriptName <jpeg_file> [<jpeg_file> ...]> "
    echo ""
    echo "tag情報が入っていないといけない。"
    echo "デジカメ写真をNASへコピーすると、タイムスタンプがコピーした時刻になってしまう。"
    echo "撮影時刻をタイムスタンプにすることで、撮影時刻順に並べやすくなる。"
    exit 0
fi

while [ -n "$1" ]; do 
    n="$1"; shift

    DATETIME=$(identify -verbose "$n" |\
        grep "exif:DateTime:" |\
        sed -e "s%^.*exif:DateTime: *\([0-9]*\):\([0-9]*\):\([0-9]*\) \+\([0-9]*\):\([0-9]*\):\([0-9]*\) *$%\1\2\3\4\5\.\6%g")

    if [ $? != 0 ]; then
        echo "ERROR: some error occured. \"$n\"."
#        exit 1
        continue
    fi

    if [ -z "$DATETIME" ]; then
        echo "ERROR: \"exif:DateTime:\" is not found in \"$n\". ignore it."
#        exit 1
        continue
    fi

#   Change Timestamp.
    echo $n $DATETIME
    touch -t "$DATETIME" "$n"
done
上記を適当な名前(ウチでは"pictureTime.sh"としている)で保存し、パスの通ったディレクトリに保存する。
また、内部でimagemagicを使っているので、パッケージimagemagicをインストールしておかなければならない

使用方法は、シェルスクリプトの名前に続けて、写真のファイル名を指定すればいい。
たとえば、スクリプトの名前="pictureTime.sh"、NAS上の保存フォルダへのパス="/mnt/nas/Pictures/2018-newYear"、写真の拡張子="*.JPG"なら、
$ pictureTime.sh /mnt/nas/Pictures/2018-newYear/*.JPG
とすれば、2018-newYear直下の、拡張子が.JPGであるすべてのファイルのタイムスタンプを、撮影日に変更する。

/mnt/nas/Pictures以下、サブディレクトリ内も含めて、すべての.JPGおよび.jpgファイルを対象としたいなら、たとえば find を使って、
$ find /mnt/nas/Pictures -type f -iname "*.JPG" -print0 | xargs -0 pictureTime.sh
とすれば良いだろう。

うちのTVはフォルダ無関係にタイムスタンプ順で写真を表示するので、これによりTVでの写真の探索が楽になる。


撮影日情報が見つからないファイルはエラーとなり無視するため、すべてのファイルに対して適用しても動かなくはないのだが、すべてのファイル全体を舐めることになり、時間がかかる。特に動画ファイルは静止画よりもかなり大きいので、驚くほど時間がかかる。そのため、拡張子などで絞り込むことを強く奨める。
また、上記を読めば薄々わかると思うが、動画ファイルには対応していない。

ところで、Windowsを使っている人は、どうしているんだろう?
2018年1月14日 更新: スクリプトのヘルプメッセージ内の "<" や ">" をそのままで書いていたため、ヘルプメッセージの一部が表示されていなかった。"&lt;", "&gt;"で書きなおした。
2018年1月15日 更新: 余計なshiftが入っていた。削除した。
2019年7月6日 更新: スクリプトを色付き表示にした。

0 件のコメント:

コメントを投稿