LoginSignup
7
6

More than 5 years have passed since last update.

RAWやJPGファイルを撮影日時に応じたフォルダに移動するRubyスクリプト

Last updated at Posted at 2016-01-21

なんだかんだで8年近くカメラをやっている私ですが、昔と今で異なる現像ソフトを使っています。そして取り込み時のフォルダ名のルールを変えてしまったため、フォルダ名が滅茶苦茶になってきました。具体的には、Nikon ViewNX で取り込んでいた頃は3桁の連番(001/, 002/, ...)に保存していたのですが、Adobe Lightroom を使うようになってからは YYYYMMDD (20160101/, 20160102/, ...) という規則で取り込んでいます。

いい加減気持ち悪くなってきたので、日付毎に写真をフォルダ分けする Ruby スクリプトを書きました。これを使うと、写真の Exif 情報から日時を取得し、その日時に対応したフォルダに写真を移動できます。例えば2016年1月21日に撮影された写真なら 20160121 というフォルダに移動します。

以下、スクリプトと使い方です。

検証環境

  • Windows 10 64bit (Build 10240)
  • ruby 2.2.3p173 (2015-08-18 revision 51636)

導入手順

  1. 何はともあれ Ruby を実行できるようにしておく。
  2. gem install thor で Thor gem をインストール。
  3. 後述のスクリプトを適当な名前 (仮に organize_photos.rb とする) で保存する。
  4. スクリプトと同じディレクトリに Exiv2 - Image metadata library and tools からダウンロードした "Windows executable" のバイナリを保存する。
    • RAW や JPEG 画像の Exif データから撮影日時を抽出するために利用。
    • exifr という gem の方が手軽ですが、これは JPEG と TIFF しか扱えないので NG でした。
  5. ruby organize_photos.rb mv {移動元フォルダ} {移動先フォルダ} で移動を実行。

ここまででファイル構成が以下のようになっていれば OK です。

$ ls .
exiv2.exe          libexpat.dll        organize_photos.rb

スクリプト

require 'date'
require 'fileutils'
require 'thor'

class OrgnizePhoto < Thor
  desc 'move SRC_DIR dest_DIR', 'Move files in SRC_DIR to dest_DIR'
  option :extensions, default: 'nef,dng,jpg,jpeg'
  option :date_format, default: '%Y%m%d'
  option :force, type: :boolean, default: true
  option :noop, type: :boolean, default: false
  def mv(src_dir, dest_dir)
    get_files(src_dir, options[:extensions]).each do |src|
      date = extract_date(src, options[:date_format])
      dest = "#{dest_dir}/#{date}/" + src.sub(src_dir, '')

      opts = { force: options[:force], noop: options[:noop] }
      move src, dest, opts
    end
  end

  private

  def get_files(dir, extensions)
    Dir.glob("#{dir}/*.{#{extensions}}")
  end

  def extract_date(file, date_format)
    exif = `exiv2.exe -q -Pnv #{file}`
    if /DateTimeOriginal\s+(\d{4}:\d{2}:\d{2})\s+(\d{2}:\d{2}:\d{2})/ =~ exif
      DateTime.parse("#{$1.tr(':', '-')} #{$2}").strftime(date_format)
    else
      false
    end
  end

  def move(src, dest, options)
    dest_dir = File.dirname(dest)
    begin
      unless Dir.exist?(dest_dir)
        FileUtils.mkdir_p dest_dir
        puts "Created #{dest_dir}"
      end

      FileUtils.move(src, dest, options)
      puts "#{src} -> #{dest}"
    rescue Exception => e
      p "#{src} -> #{dest} ... #{e.inspect}"
    end
  end
end

OrgnizePhoto.start(ARGV)

実行例

$ ruby -Eutf-8 organize_photos.rb mv --noop f:/Pictures/001/ f:/Pictures/

f:/Pictures/001/RIMG0408.jpg -> f:/Pictures/20080707/RIMG0408.jpg
f:/Pictures/001/RIMG1817.jpg -> f:/Pictures/20080907/RIMG1817.jpg
f:/Pictures/001/RIMG1828.jpg -> f:/Pictures/20080908/RIMG1828.jpg
f:/Pictures/001/RIMG1840.jpg -> f:/Pictures/20080909/RIMG1840.jpg

補足

  • 私が Nikon および Ricoh ユーザーなので、拡張子は .nef, .dng, .jpg, .jpeg ぐらいしか対応してません。
    • 他のメーカーのカメラをお使いの方は、拡張子を実行時のオプション --extensions に追加してください。
    • スクリプト内の option :extensions, default: 'nef,dng,jpg,jpeg' の中に直接追加しても OK。
  • オプション --noop を付けた場合は、ファイルの移動先が表示されるだけで実際に移動は発生しません。
  • かなり急いで書いたので、変なバグがあるかもしれません。気づいた方はコメントか編集リクエストをください。
  • 誰か僕に D5D500 を買ってください。

参考にした記事

7
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6