わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

iPhoneの写真とMicrosoft Pixとで,ExifのDateTime情報が異なる?

日常風景の写真撮影に,コンパクトデジタルカメラから,Android端末やiPhoneに切り替わって,何年になるでしょうか.
いずれにせよ,撮った写真は,1台のPCのハードディスクに集約しています.ファイル名に日本語があればASCII文字のみとなるよう変換し,撮影年月日でフォルダに振り分けます.撮影年月日は,ファイル名ではなく,Exif情報の中のDateTimeタグを参照します.
なのですが,先月から,その振り分けでエラーが発生していました.振り分けは自作のRubyスクリプトで,都合によりそのソースコードは非公開とします.ともあれエラーの発生状況を再現してみます.
2つのファイルがあります.もともとは長いファイル名ですが,簡単のため1.jpg,2.jpgとします.Rubyでは,gem install exifrのコマンドで,exifrライブラリをインストール済みです.
irbコマンドを使って,日時情報を見てみます.まずは1.jpgのほう.

$ irb
irb(main):001:0> require "exifr"
=> true
irb(main):002:0> ex = EXIFR::JPEG.new("1.jpg"); nil
=> nil
irb(main):003:0> ex.date_time
=> 2017-04-03 06:29:45 +0900
irb(main):004:0> ex.date_time.class
=> Time
irb(main):005:0> exit

途中の「; nil」について,書かなかったら,exに代入されるオブジェクトの内容が表示されます.バイナリデータもあり,膨大な出力となります.
次に,2.jpgのほうですが,こちらは自作の振り分けスクリプトでエラーが発生するものです.

$ irb
irb(main):001:0> require "exifr"
=> true
irb(main):002:0> ex = EXIFR::JPEG.new("2.jpg"); nil
=> nil
irb(main):003:0> ex.date_time
=> "2017:04:03 06:30:00.284"
irb(main):004:0> ex.date_time.class
=> String
irb(main):005:0> exit

エラーになったという2.jpgでは,日時情報は「.284」(秒未満の値?)がついた文字列です.それに対し1.jpgでは,日時情報がTimeのインスタンスとなっています.
Exifの仕様に,RubyのTimeクラスが入っているというのは,おかしな話なので,ここはおそらくexifrライブラリがお節介をしているのでしょう.DateTimeタグの値はあくまでバイト列であり,その値を,容易な操作でTimeに変換できるのであれば,そのインスタンスに,そうでなければStringのインスタンスにしている,と解釈すればすっきりします.
年月日を獲得する処理は,これまで,次のように記述していました.

dt = ex.date_time
ymd = dt.strftime("%Y%m%d")

これを以下のように書き換えました.

dt = ex.date_time
case dt
when Time
  ymd = dt.strftime("%Y%m%d")
when String
  ymd = dt.gsub(/\D/,"")[0,8]
else
  raise
end

ちなみに1.jpgはiPhoneのカメラ(標準アプリ)で,2.jpgはMicrosoft Pixで撮影したものです.標準アプリだと,GPS関連の情報も,Exifとして入っています.上で「; nil」を書いて中身を見ませんでしたが,中身を見てみると,終わりのほうに「@exif=」から始まって詳細を知ることができ,1.jpgと2.jpgとで,gps関連の有無も確認できました.
Microsoft Pixは,無音で撮影したいときや,詳細なメタ情報が不要なときに,活用することとし,家族写真など,日常の風景は,標準アプリのカメラのほうが良さそうです.