Android 端末で ファイル のコピー・移動時に、 タイムスタンプ が 上書き されてしまうことがあります(特にストレージを跨ぐ操作において)。ギャラリー系 アプリ で、時系列に並んでいたはずの画像 ファイル の並びが崩れてしまうのは、これがその大きな原因です。これを解決するために使っていた自作のスクリプトと、今後それに代わってくれることを期待する アプリ を紹介します。
ファイル名から日付時刻を復元
スマートフォンで撮影した画像や動画は、そのファイル名に日付時刻を表す文字列を含んでいることから、パターンマッチングで生成時の日付時刻を取得し、
touch
コマンドによりファイルのタイムスタンプを修正する、自作のスクリプトを使っていました。
あくまで自分の使う特定の機器で使えるようにしただけなので、以下のように対象フォルダ、対象ファイル名、
touch
コマンドを内包しているBusyBoxのパスなど、全て決め打ちになっているので、移植の際はその環境に適宜合わせる必要があります。
#!/system/bin/sh # Correct File Timestamp by Filename # IMG_YYYYMMDD_HHMMSS.jpg / YYYYMMDD_HHMMSS.jpg wpaths=("/sdcard/_TRANS/" "/storage/####-####/_TRANS/") patterns=("IMG*.*g" "VID*.*" "2*.*g") touch_by_patterns () { for p in ${patterns[@]}; do y=4; h=13; s=17 if [ ${p:0:1} == 2 ]; then y=0; h=9; s=13 fi ls ./$p > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "NO FILES: $wpath$p" else TZ=UTC-8 /data/busybox/busybox touch -t ${p:$y:8}${p:$h:4}.${p:$s:2} $p (( n++ )); fi done if [ $n -ne 0 ]; then echo "$n FILES CORRECTED: $wpath" #stat -c "%y %n" ./* | sed -e 's/\/.*\///' -e 's/\.000000000//' stat -c "%y %n" * | sed -e 's/\.000000000//' fi } for wpath in ${wpaths[@]}; do if [ -e $wpath ]; then n=0 cd $wpath touch_by_patterns else echo "NO DIR: $wpath" fi done
このスクリプトは、特にAndroidスマートフォンで生成される、exifメタデータを持たない動画ファイルのタイムスタンプを修正するのに重宝しました。
尚、連写時に同じ日付時刻で複数画像が生成されることになる為、例えば
IMG_20201120_112233_2.jpg
のように後ろに添え番がついてしまっても、問題なく日付と時刻を取り出して
touch
することが可能です。
exifメタデータを無理やり読んで復元
デジカメの画像をWiFi連携アプリを通じてAndroid端末内へ取り込んだ場合、その画像ファイル名は連番であることからオリジナルの日付時刻を得るにはexifメタデータを参照するしかありません。
Linuxではexiftoolを導入することでexifの内容を容易に参照することが可能ですが、Androidでは導入へのハードルも高いことから、こうした画像ファイル向けに、exifデータの収められたバイナリデータの先頭部分を力技で読み込むスクリプトも作ってみました。
head
コマンドにより一行抜き出して読み取りを試行するのですが、撮影デバイスによって撮影日時の収納位置が微妙に異なるため、「撮影日時がありそうな行」を一つずつ抜き出しては、日付時刻のパターンマッチングにかけるという、かなり強引なことをしています。
#!/system/bin/sh # Correct File Timestamp by Exif Date patterns=".jpg .JPG" wpaths=("/sdcard/_TRANS/" "/storage/####-####/_TRANS/") regex="[A-Z]" for wpath in ${wpaths[@]}; do if [ -e $wpath ]; then cd $wpath echo "[$wpath]" n=0 for i in `find ./ -type f | grep -e ${patterns/ / -e }`; do # Conv File Extension Upper Case to Lower # Linux Ver. #rename 's/\.([^.]*$)/.\L$1/' $i # Android Ver. fext="${i##*.}" if expr $fext : "[A-Z]" > /dev/null; then fext=`echo $fext | tr A-Z a-z` mv $i "${i%.*}" && mv "${i%.*}" "${i%.*}".$fext fi #echo $i "${i%.*}".$fext done for i in `find ./ -type f | grep -e ${patterns/ / -e }`; do # File Head Read # Android Cam: dp=2 # Sony DSC : dp=4 # Xiaomi Cam : dp=6 for dp in 2 4 6; do dt=`head -n $dp $i | grep -o '[0-9][0-9][0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' --text` if [ -n "$dt" ]; then break fi done # Touch File Timestamp if [ -n "$dt" ]; then dt=${dt//[: ]/} TZ=UTC-8 /data/busybox/busybox touch -t ${dt:0:12}.${dt:12:2} $i (( n++ )); else dt="NIL_NIL_NIL_NI" fi #echo $dt `stat -c "%y %n" ${i/'./'/} | sed -e 's/\.000000000//'` echo $dt `stat -c "%y %n" ${i/'./'/} | sed -e 's/\.[0-9]* / /g'` done echo "Total $n Files Corrected" else echo "[$wpath] Non Existent" fi done
上記中のコメントにもありますが、自分が使う以下の機器が撮影する画像ファイルで動作確認をしています。
- Android カメラ (Samsung, Huawei)
- Sony NEX-5R
- Xiaomi Yi Action Camera
Image & Video Date Fixer アプリなら簡単
これらの自作スクリプトはrootedデバイスであるなどの制約がありましたが、今では同じことをしてくれる優れたアプリがいくつもあります。その中でもシンプルにして明快なのがこちらのImage and Video Date Fixerというアプリ。XDA Developersでも紹介されていて、概ね好評です。
Image and Video Date Fixer reads the EXIF metadata entries of images and videos to identify the original timestamp and sets it as the modification date. Image and Video Date Fixer restores the proper dates to your media files – xda-developers |
インストールしてみると、アプリが必要とする権限は以下の通りで、その中で少し気になる、
「電話:デバイス情報とIDの読み取り」
は非許可としたままでも問題なく使うことができました。
アプリを立ち上げ、まずフォルダアイコンから対象フォルダを選択して、スキャンを実行。スキャン結果はプレビュー画面に一覧表示されるので確認の上、右下の「開始」をタップすると、「不適切な日付」に対して修正が加えられます。
この時無料版では、一度に修正することの出来るファイル数が50個までという制限がありますが、再実行すれば良いだけの話なのであまり意地悪な仕様にはなっていません。
メディアファイルのタイムスタンプ保持は、自分にとって優先度の高いライフテーマです。その分野で待ち望んだ秀悦なアプリとの出会いに、開発支援の意味でも課金してプレミアムバージョンにしてみるつもりです。
投稿 Androidで画像ファイル操作時に上書きされたタイムスタンプを復元 は Fun Scripting 2.0 に最初に表示されました。