EXIF情報を一括更新するPythonコード

自分は旅行などの写真を自前のシステムで管理しているのですが、その際に管理キーとなる時刻情報をEXIFから抽出しています。またこの時刻情報を元に、写真を時系列に並べているので、重要な情報となります。

通常は撮影機器の時刻情報が正しく設定されていれば困らないのですが、海外旅行では困ることがあります。そう、時差による問題です。常に日本の時刻に固定できれば特に問題は発生しませんが、スマホは自動で現地時刻に補正されます。これ自体はとても便利な機能ですが、スマホで撮影した写真のEXIF情報もこれに引きずられるので、前述の写真管理のシステムとしては困ってしまうわけです。

上記がモチベーションとなり、EXIF情報の一括更新ツールを作成しました。大昔に写真管理システムを作った際には、自前でEXIFのパーサーまで作っていましたが、今は便利なライブラリがありますので、そちらを活用します。

言語環境は最近利用することが多いPythonを使い、EXIF編集のライブラリはpyexiv2を利用しました。EXIFを参照できるライブラリは多く見かけますが、編集できるライブラリとなると数は限られるようです。

そしてコマンドライン実行は手間なので、ドラッグアンドドロップで対象ファイルを指定して実行できるようにしました。最初、.py拡張子がPythonランチャアプリに関連づいていなくて、少しハマりました。

処理内容は、受け取った画像ファイルパスリストからEXIF情報の撮影日時を参照し、datetime型を経由して時差補正演算を行ない、その値でEXIF情報を更新するという単純な内容です。

以下がコードです。50行程度のミニコードになります。自分が使うので例外処理等は入れていません。けれどまったくログ情報が残らないとトラブル時に面倒なので、簡単なテキストログを残すようしました。Pythonはあまり書き慣れていないので、変な書き方になっているかもしれません。

# @note
# ドラッグアンドドロップでpythonスクリプトを起動させるためには、
# .py拡張子がpythonランチャアプリを関連付いている必要があります。
# ファイル右クリックで、プロパティ→全般→プログラム横の変更ボタンから関連付けができます。

import pyexiv2
import re
import datetime
import sys

# PARAMETER SECTION START_______
# !!! This is parameter !!!
# You need to set this parameter properly as you expect.
# This parameter is time difference with Japan. 
# e.g. Hawaii : -19,  Taiwan : -1,  Sydney : +1
TIME_DIFFERENCE = 1
# PARAMETER SECTION END_________

revised_time_difference = TIME_DIFFERENCE * -1

LOG_FILE = 'ExifUpdaterLog.txt'
EXIF_DATETIME_KEY = 'Exif.Photo.DateTimeOriginal'

class LogRecorder:
    def open(self):
        self.f = open(LOG_FILE, 'w', encoding='UTF-8')
    def close(self):
        self.f.close()
    def print(self, log):
        self.f.writelines(log)

def get_converted_datetime(datetime_str):
    date_format = '%Y:%m:%d %H:%M:%S'
    dt = datetime.datetime.strptime(datetime_str, date_format)
    td = datetime.timedelta(hours=revised_time_difference)
    conv_dt = dt + td
    return conv_dt.strftime('%Y:%m:%d %H:%M:%S')

# main routine
logger = LogRecorder()
logger.open()

# ドラッグアンドドロップしたファイル一覧を取得する
# 先頭は実行ファイルパスなので、その後のリストを取得する
img_file_list = sys.argv[1:]

for img_path in img_file_list:
    with pyexiv2.Image(img_path) as img:
        data = img.read_exif()
        datetime_str = data[EXIF_DATETIME_KEY]
        converted_datetime_str = get_converted_datetime(datetime_str)
        img.modify_exif({EXIF_DATETIME_KEY : converted_datetime_str})
        logger.print('file:{0}, original_datetime:{1}, converted_datatime:{2}\n'.format(img_path, datetime_str, converted_datetime_str))

logger.close()

追記:ファイルパスにマルチバイト文字を含んでいると、動作しないようです。ファイルを移動して作業すれば済むことなので、深追いはしません。

さらに追記:Lightroom ClassicにEXIFの時刻情報を一括変更できる機能があったので、結局そちらを使っています。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする