Lightroom は「写真の編集」ソフトとして知られていますが、写真を管理するソフトとしても優秀です。

今年の正月からの写真を、撮影したものの Lightroom に取り込んで整理しようと思ったのですが、「数が多い」「日付が複数」となると この作業が、なかなか面倒なのです。

作業としては

1.  カメラの SD カードに保存されている写真ファイルの撮影日付を確認する
2.  Lightroom で 「写真ファイルの撮影日付」のフォルダが存在しない場合は、フォルダを作る。
3.  1 のファイルを 2 のフォルダ以下にコピーする

この作業を一枚一枚繰り返します。

枚数が多くなると時間も掛かりますし、人間なので間違えることもあります。

ということで、この作業を単純作業が得意なプログラムにやらせようというのが、今回のお話です。

普通に書くのも面白くないので、実際の システム開発ぽく、「現状の課題」を解決するための 「要件」を定義(要件定義)し、「設計」して「実装」する(プログラムを書く)、「実行」する(要件の実現) という構成で書いてみたいと思います。

要件定義というのは、今回のシステムの目的と必要とする機能を洗い出し 顧客(システムを必要とする人)と、システムで実装する内容の合意を取るための資料です。

今回は、「開発者」「顧客」共に私です。

補足)フォルダ構成の話

撮影フォルダ

日付を意識せず同じ階層に並んでいます。

100CANON 以下に連番で撮影したファイルがずらっと並びます。

DCIM > 100CANON > IMG_DDDD.CR3

例)DCIM > 100CANON > IMG_7220.CR3

画像1

Lightroom

Lightroom では、四半期ごとにフォルダを作り、その下に日付フォルダを作って管理しています。

四半期ごとのディレクトリー(例: 2021 年1月〜3月)  > 日付(YYYYMMDD)_機種名_(イベント名 ) > IMG_DDDD.CR3

例)2021 年1月〜3月/20210115_EOS_X10_自宅/IMG_8911.CR3

画像5

※ DNGも拡張子は違いますが、RAW ファイルです。

要件定義

要件

・撮影フォルダの写真ファイル を撮影日付を見て   Lightroom の該当のフォルダにコピーする。

例)IMG_9398.CR3 撮影日付 2021 年2月 14 日の場合は、

IMG_9398.CR3 のファイルを  2021 年1月〜3月/20210115_EOS_X10/IMG_9398.CR3 のようにコピーをする。

1. コピー先の Lightroom の対象フォルダを 「 2021 年1月〜3月」とする。
2.  1 以下のフォルダに 撮影日付のフォルダが存在しない時は、撮影日付(YYYYMMDD)_機種名のフォルダを作成する
3.  2 のフォルダに 撮影ファイルをコピーする。

・Lightroom CC に取り込むファイルは、可逆可能(編集前の状態に情報の欠損なく戻すことが出来る)な「RAW ファイル」のみとする。

・既に Lightroom CC に取り込んだ(同期した)ファイルは取り込まない。但し、今回はプログラムでは判定せず、2021 年 1 月 2 日〜の撮影日付のファイルについて処理を行うこととする。

・撮影された写真ファイルは、そのまま残す

非対応(非機能要件)

・既存の Lightroom のフォルダは機種名に加えて、イベントあるいは場所名が追加されているが、手作業で追加とし、システムでは対応しない。

スクリーンキャプチャーを見て同じ名前で拡張子が違うものがあることが不思議に思われる人がいるかもしれませんが、 私は 必ず 「RAW」と 「JPG」の両方を保存するようにしています。この二つは同じものではありません。

RAW ファイルは、ほぼ現像データを全て含んでいるので、編集が自由に出来ます。ですので、Lightroom などで取り込んで編集することに向いています。

一方、「JPG」は取って出しで「非可逆」なので、編集することには向きません。だから、取り込む対象を「RAW」ファイルのみとしています。

ちなみに、スマフォでも 「RAW」と 「JPG」の両方の形式を保存するようにしています。

一つの写真で2枚保存すると、ストレージを圧迫します。気をつけましょう。その結果、画像ファイルを整理したことは以前記事にも書きました。(↓)

実装

実際のプログラム(ソースコード)は、こんな感じです。

require 'fileutils'
#
src_raw_files = Dir.glob("/Volumes/Untitled/DCIM/100CANON/*\.CR3")
from_date = Time.new(2021, 1, 2, 0, 0, 0)
lightroom_parent_dir = "/Volumes/MyPictures/macmini_all/Storage/2021年1月〜3月".freeze
model_name = "EOS_X10".freeze
# from_date(2021年元旦)以降のrawファイルを取得
importing_files = src_raw_files.filter_map do | file_path |
   stat = File::Stat.new(file_path)
   {file: file_path, created_at: stat.birthtime} if stat.birthtime >= from_date
end
# 撮影ファイルをlightroomの該当フォルダーにコピーする
importing_files.each do | file_info |
   photographing_date = file_info[:created_at].strftime('%Y%m%d')
   # lightroom_dir 以下に 「YYYYMMDD_機種名」のフォルダを作成する。
   # => ["20210115_EOS_X10", "20210202_EOS_X10", "20210211_EOS_X10", "20210212_EOS_X10", "20210213_EOS_X10", "20210214_EOS_X10"]
   dest_dir = "#{lightroom_parent_dir}/#{photographing_date}_#{model_name}"
   #
   FileUtils.mkdir(dest_dir) unless Dir.exist?(dest_dir)
   FileUtils.cp(file_info[:file], dest_dir)
end

暗号のように思えますが、要件を、ソースコードに変換(翻訳)しただけです。

今回は、実際にプログラムを実行しておかしなところを修正しましたが、

ちなみに、業務だと、要件(の各項目)に対するテストを先に書いて、その後でプログラムを書いたりします。

全ての要件を満たしていたら、テストは満点で 要件に漏れがないということです。

テストが落ちた箇所を修正し、またテストを実行します。満点になるまで、テストの実行とプログラムの修正を繰り返します。

人間だと、「何度同じ操作をしたとしても同じ結果を得られる」という冪等性の実現が難しいですが、システムでテストを行うと、冪等性が担保できるからです。

自動化するのは、時間を短縮する意味もありますが、必ず同じ結果を出すということも重要なポイントです。

実行結果

プログラムを実行します。 出来ました!。👏👏👏👏👏

画像4

Lightroom に同期

最後に、Lightroom に同期をします。新しい写真が 570 枚もありました。

画像4

lightroom との同期が完了するとこんな感じになります。場所名は手作業で追加しています。ここに関しては写真を確認して手作業で付けたほうが間違いが少ないと考えて、そうしました。

画像5

どうでしょうか?

普通の文章より分かりにくかったですか?分かりにくかったですか?

仕事を下さい(笑)。では、また〜。