2015 06 06

iPhoneの写真の撮影日

暗い未来

せっかく生えてきたのだが、場所が悪かった。 ここは石垣の上の石の隙間。 きっとそのうち抜かれてしまうだろう。 秋までもって紅葉すれば、まさに 「小さい秋」 だが、小さいままで終わる秋でもあるのだ。

jpeg

数日前までは iPhoneで撮った写真が縦と横で形式が違っていた のだが、先日、iOSをアップデートしたら縦も横も同じになってしまった。 以前は横が従来からの一般的なExif形式、縦がRDF形式(?)だったのだが、今では横もRDF形式となっている。 多分、最初から縦も横もRDF形式にするつもりだったのに、前回のアップデートからは漏れてしまったのだろう。

まあ経緯はどうでもいい。 問題は、iPhoneで撮った写真に対しては、俺が写真整理に使っているスクリプトが使えなくなってしまったこと。 なので、iPhone用に新たに作ることにした。

最初は新フォーマットをちゃんと調べて、設定される可能性のあるいろんな値を取り出せるようにしようと思ったのだが、しかし当面必要なのは撮影日時だけなんだよな。 しかもすぐに必要。 なので、とりあえず撮影日時の取り出しのみに対応することとする。

処理の大まかな流れは、既存のExif解析と同じ。 違うのは、マーカーffe1の処理。

マーカーffe1の内容は、だいたいこんな感じ。

http://ns.adobe.com/xap/1.0/\x00 <?xpacket begin="\xEF\xBB\xBF" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 5.4.0"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/" xmp:CreateDate="2015-02-25T12:07:30" xmp:ModifyDate="2015-02-25T12:07:30" xmp:CreatorTool="8.1.3" photoshop:DateCreated="2015-02-25T12:07:30"/> </rdf:RDF> </x:xmpmeta>

先頭にadobeのURLがあり、撮影日時は、多分CreateDateに設定される。 設定される撮影日時は文字列で、書式は、日付 yyyy-mm-dd と時刻 hh:mm:ss が大文字の "T" を挟んで並ぶ。

撮影日時を取り出すだけなら簡単だな。

ということでコード。

#exif_rdf.rb require 'fileutils' require './jfif' class ExifRDF < JFIF include ByteArray def initialize( filename, filetype = 'EXIF' ) super( filename, filetype ) @tags = {} parseExif end def parseExif raise 'not Exif' unless @app1 = @markers[ 'ffe1' ] raise 'not Exif' unless @app1.start_with? 'http://ns.adobe.com/xap/' parseRDF end private :parseExif def parseRDF # CreateDate="yyyy-mm-ddThh:mm:ss" if md = @app1.match( /CreateDate="(.*?)"/ ) @tags[ :CreateDate ] = md[ 1 ] end end private :parseRDF def get( tag ) @tags[ tag ] end end

JFIFとしては従来通りなので、JFIF解析のクラスを継承している。

取り出したマーカーffe1の先頭にadobeのURLがあることを、この形式であることのチェックとしているが、チェックの必要性は微妙。 無くても多分困らない。

撮影日時はCreateDate=に続くダブルクォーテーション内の文字列として正規表現で抜き出し、tagsというハッシュにCreateDateをキーとして登録している。 取り出した文字列そのままで、ここでは何の加工もしていない。

単純に値を返すのではなく、取り出せた値をハッシュに持ち、必要に応じてそこからgetterで取り出すのは、この先もっといろんな値を扱うことを考えてのことだが、上記のサンプルを見る限りでは、ここから取り出す意味があるのは撮影日時ぐらいなんだよな。 他の値はどうなってるんだろう。

そして、これを使ってiPhoneの画像ファイルから撮影日時を抜き出し、年月のディレクトリに日時をファイル名としてコピーする処理。 パスは決め打ち。

require 'exif_rdf' include FileUtils Dir.glob( "/Users/watanabe/Pictures/photo/*/*.jpg" ).each do | f | begin exif = ExifRDF.new( f ) dateTime = exif.get( :CreateDate ) dirTree = dateTime.split( /T/ )[0].split( /-/ ) dirname = "/Users/watanabe/Pictures/photo2/#{ dirTree[0] }/#{ dirTree[1] }" newFilename = dateTime.gsub( /-/, "" ).gsub( /:/, "" ).gsub( /T/, "_" ) + ".jpg" newPath = "#{ dirname }/#{ newFilename }" FileUtils.mkdir_p dirname p "#{f} -> #{newPath}" FileUtils.cp f, newPath rescue => e p e p "err : #{ f }" end end

久しぶりにrubyを触ったけど、やっぱり書きやすいな。 多分こうと思ったことが、だいたいその通りにできるのが良い。 まあ、忘れてることが多いから 「多分」 なんだけど。 忘れない程度に触っておくのも大事なんだよな。 せっかくだから、リハビリも兼ねていろんな言語で作ってみるかな。