40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

iPhotoの写真→Evernoteスクリプトを修正した

iPhotoの複数の写真を(ほぼ自動で)まとめてEvernoteに取り込むスクリプト完成のPVは、絶対数こそ少ないけど、毎日一定数あるのを見ていると、画像データを一括でまとめてEvernoteに登録したいというニーズはあるというのを知って少し自分の中のモチベーションが上がったのとこの後のことを考えて少し修正しました。

修正しようと思った背景(スクリプトの中身が気になる人はこの部分読み飛ばしてください)

そんなスクリプトを自分で書いといてなんだけど、あのスクリプト処理があんまり綺麗じゃなくって気持ち悪いんですよね・・

気持ち悪いと感じているのは

  • iPhotoからアルバム情報をHTMLとして生成しているけど、アルバム情報を書き出すときのオプション指定によって、

HTMLファイル内に記載されている写真の撮影日の位置がかわる

  • Nokogiri使った処理しているけど、これ使わなくっても良いやり方ありそう

というあたり。
できる事ならば、Mac OS X10.5 以上で、追加のgemなんかを、可能な限り利用しないような形で実行できたほうが、実際に試す人にとっては敷居がさがりそうかなと思っています。

あとは折角なので、Windows版のスクリプト(WSH+JScript)も書きたいなーと思っていて、その場合にNokogiriのようなパーサー使った処理をしているものをWSH+JScript向けに移植する(*)となると、考えただけでも嫌になるからなるべくシンプルな形の処理にしておいたほうが後々良いかなと思っていたりします。

修正したスクリプト

気持ち悪い状態を少しでも解消するために、こんな形で書き換えました。erbで利用するテンプレートはiPhotoの複数の写真を(ほぼ自動で)まとめてEvernoteに取り込むスクリプト完成で書いたものから全く変更ありません。

## iphoto2evernote.rb
require 'rubygems'require 'base64'
require 'digest/md5'
require 'erb'
require 'extexif'


class Images2Enex
  def initialize()
    @exif ={};
    if ARGV[0].nil?
      exit!
    else
      @base_directory = ARGV[0]
    end
  end
  attr_accessor :evernote_created_date, :evernote_note_title,:evernote_hash, :imgdata


  def convert
    Dir::glob(@base_directory + "*.jpg").each{|f|
      _exif = ExtractExit(f)
      # JPEGのファイル名をEvernoteのノートタイトルに活用しつつ
      # enexファイルの書き出すときのファイル名にも活用
      jpeg_filename = File.basename(f).split(".")
      output_filename = jpeg_filename[0]


      @imgdata = base64_encode(f)
      @evernote_note_title = output_filename
      @evernote_hash = make_hash(f)
      @evernote_created_date = convert_date_format(_exif["Date"])
      template = File.open("evernote_enex01.tmpl") { |tmpl| tmpl.read }
      @result = ERB.new(template, nil, '-')
      begin
        make_enex(output_filename)
      rescue OpenURI::HTTPError => e
        e.io.close
      end
    }
  end
 
  private
  # Evernote指定の日付フォーマットであるyyyymmddThhmmssZに変換
  def convert_date_format(str)
    separete_str = str.split(" ")
    each_date_element    = separete_str[0].split(":")
    each_minutes_element = separete_str[1].split(":")
    return each_date_element[0] + each_date_element[1] + each_date_element[2]  + "T" + each_minutes_element[0] + each_minutes_element[1] + each_minutes_element[2] + "Z"
  end
 
  def make_hash(file)
    return Digest::MD5.hexdigest(File.open(file,'rb').read)
  end


  def make_enex(file)
    f = File.open(@base_directory + file + ".enex","w")
    f.puts @result.result(binding)
    f.close
  end


  def base64_encode(jpeg)
    return Base64.encode64 File.open(jpeg).read
  end


  def ExtractExit(file)
    image = ExtExif.new(file)
    @exif = {
      "Maker"    => image["Make"],
      "Width"    => image["PixelXDimension"],
      "Height"   => image["PixelYDimension"],
      "Aperture" => image["ApertureValue"],
      "Date"     => image["DateTimeOriginal"],
      "FNum"     => image["FNumber"]
    }
    return @exif
  end
 
end

i2e = Images2Enex.new()
i2e.convert()

使い方

  1. iPhotoで管理している写真を、適当なフォルダ(仮にデスクトップ上の”photo”というフォルダ)に書き出す
  2. ターミナル上でこんな感じで実行すると、写真を書き出したフォルダ内に、順番にenexファイルが生成されるのであとはこれをEvernoteにインポートすればOK
ruby ./iphoto2evernote.rb ~/Desktop/photo/

今回修正する中で、気づいたのは、Dir::globを使った処理をしているわけなので、ディレクトリ配下のファイル名取得なんかも本来簡単に出来ると思っていたけどそのあたりも気になっていたのでRuby でファイル一覧の取得というサイトを参考にしてそこもスッキリしました。

(*)JavaScriptでBase64エンコードする。 - ブックマクロ開発にというエントリを最近見つけたから、これを参考にすればBase64エンコード出来そうだしMD5を計算するライブラリなんっていうのもある。
一番やっかいなJPEGのExif情報の読取は、ADODB.Streamオブジェクトを使って処理するしかなさそうでこちらのlzhファイルの中にあったVBScriptファイルが参考になりそうだけど、読み取ったバイナリデータの処理大変そう・・とか思っていたらJavaScript だけで EXIF を読むというエントリでEXIF のタグ定義テーブルを取得っていう辺りのコメント欄の情報が参考になりそう。