#はじめに
GooglePhotoが容量うんぬんで困ったことになったのでAmazonPhotoに移行を思い立ちました!
えいやっと,一括ダウンロード&アップロードして終わるかと思いきや,日付不明の画像がちらほら...
確認するとExifの中でも日付がなくなっていました.
GooglePhotoから一括ダウンロードした際に,JSONとして別ファイルに日付情報が分けられてしまったようです.
今回は,分けられてしまったExifの日付情報をPythonを使って復旧させたいと思います.
#環境
- OS:Windows10
- Python 2.7.17
#GooglePhotoからのダウンロード
Google データ エクスポートから行うことができます.
詳細は,ググってもらったらたくさんサイトが出てくると思います.
(GooglePhotoの容量制限を受けて,移行したい人はいっぱいいるようですね...)
#ダウンロード結果
Zipを解凍すると
hogehoge.jpg
hogehoge.jpg.json
というように,画像とJSONファイルがセットで保存されていました.
JSONの中身は,だいたいこんな感じです.(本来のファイルからいじっています)
{
"title": "hogehoge.jpg",
"description": "",
"imageViews": "0",
"creationTime": {
"timestamp": "1111111111",
"formatted": "2019/05/05 3:46:06 UTC"
},
"modificationTime": {
"timestamp": "1111111111",
"formatted": "2020/12/06 17:27:33 UTC"
},
"photoTakenTime": {
"timestamp": "1111111111",
"formatted": "2019/04/07 9:38:14 UTC"
},
"geoData": {
"省略"
},
"geoDataExif": {
"省略"
},
"googlePhotosOrigin": {
"省略"
}
}
GooglePhotoで同じ画像を閲覧した際の情報を確認すると,どうやらphotoTakenTime
のformatted
の部分を撮影時刻としているようなので,ここを読み取り,画像のExifに挿入してあげたらよいというわけです.
#PythonでExifを読み取る
いろいろ調べましたが,piexifがよさそうでした.
このサイトの「その他答え #1」の部分からサンプルコードをお借りしました.
表示するだけのサンプルを載せておきます.
一覧で表示の部分は,こちらからお借りしました.
# -*- coding: utf-8 -*-
import piexif
#画像ファイルのパス
filename = 'hogehoge.jpg'
#EXIF情報を得る
exif_dict = piexif.load(filename)
#一覧で表示
for ifd in ("0th", "Exif", "GPS", "1st"):
for tag in exif_dict[ifd]:
print(tag,piexif.TAGS[ifd][tag]["name"], exif_dict[ifd][tag])
#PythonでJSONを読み取る
読み取りは,PythonでJSON 読み込みを参考にしました.
読み取るだけのサンプルもおいておきます.
読み取る対象はphotoTakenTime
のformatted
の部分です.
# -*- coding: utf-8 -*-
import json
#読み取り
json_open = open('hogehoge.jpg.json', 'r')
json_load = json.load(json_open)
#対象部分の保存
#この後必要な形に成形
takenTime = json_load['photoTakenTime']['formatted'].split(' ')
date = takenTime[0].split('/') #日付
time = takenTime[1].split(':') #時間
zone = takenTime[2] #タイムゾーン
#出力
print(json_load['photoTakenTime']['formatted'])
print(date)
print(time)
print(zone)
#タイムゾーンの変更
JSON見たらわかると思うんですけど,タイムゾーンがUTCになってます.
日本(JST)との時差は9時間なので,datetimeを使って修正します.
JSONの読み取りにタイムゾーンの変更を加えたコードは以下のようになっています.
# -*- coding: utf-8 -*-
import json
import datetime
#読み取り
json_open = open('hogehoge.jpg.json', 'r')
json_load = json.load(json_open)
#対象部分の保存
#datetimeに投げられるように成形
takenTime = json_load['photoTakenTime']['formatted'].split(' ')
date = takenTime[0].split('/') #日付
time = takenTime[1].split(':') #時間
zone = takenTime[2] タイムゾーン
#datetimeに投げる
basetime = datetime.time(int(time[0]), int(time[1]), int(time[2]))
basedate = datetime.date(int(date[0]), int(date[1]), int(date[2]))
if zone == 'UTC':
#時差修正
jst_date = datetime.datetime.combine(basedate, basetime) + datetime.timedelta(hours=9)
else:
print("UTC以外のタイムゾーンです")
#Exif用に型変更
time_jp = jst_date.strftime("%H:%M:%S")
date_jp = jst_date.strftime('%Y:%m:%d')
#今までのを組み合わせる
以上を組み合わせたら,以下のようになりました.
個人的に,元ファイルをいきなり直接編集は嫌だったので,コピーしつつ編集してます.
コピーにはshutilを使っています.
# -*- coding: utf-8 -*-
import shutil
import datetime
import piexif
import json
#画像読み取り(パスは適当)
filename = '../../temp/hogehoge.jpg'
new_file = 'hogehoge2.jpg'
#画像のコピーとExifを確認
shutil.copy2(filename, new_file)
exif_dict = piexif.load(new_file)
#JSON読み取り
json_open = open(filename + '.json', 'r')
json_load = json.load(json_open)
#日時部分の保存
#この後必要な形に成形
takenTime = json_load['photoTakenTime']['formatted'].split(' ')
date = takenTime[0].split('/') #日付
time = takenTime[1].split(':') #時間
zone = takenTime[2] #タイムゾーン
#datetimeに投げる
basetime = datetime.time(int(time[0]), int(time[1]), int(time[2]))
basedate = datetime.date(int(date[0]), int(date[1]), int(date[2]))
if zone == 'UTC':
#時差修正
jst_date = datetime.datetime.combine(basedate, basetime) + datetime.timedelta(hours=9)
else:
print("UTC以外のタイムゾーンです")
#Exif用に型変更
time_jp = jst_date.strftime("%H:%M:%S")
date_jp = jst_date.strftime('%Y:%m:%d')
#Exif情報の変更
exif_dict['0th'][piexif.ImageIFD.DateTime] = date_jp + " " + time_jp
exif_dict['Exif'][piexif.ExifIFD.DateTimeOriginal] = date_jp + " " + time_jp
exif_dict['Exif'][piexif.ExifIFD.DateTimeDigitized] = date_jp + " " + time_jp
exif_bytes = piexif.dump(exif_dict)
#Exifの変更反映
piexif.insert(exif_bytes, filename)
たぶんこれでいけると思います.
#さらに改善
ここまで書いて気付いたんですが,画像は何百何千とあるしExifが欠落してないものもあるやん...
というわけで,globを使って全ファイル参照と日付あるなしによる分類をします.
# -*- coding: utf-8 -*-
import glob
import shutil
import datetime
import piexif
import json
#パスは適当
path = '../../temp/'
new_path = 'photo_add_exif/'
#jpgの探索
for f in glob.glob(path + '*.jpg'):
#画像読み取り(パスは適当)
exif_dict = piexif.load(f)
#Exifに日付があるか確認
#なかったら処理開始
if exif_dict['0th'].get(piexif.ImageIFD.DateTime) == None \
and exif_dict['Exif'].get(piexif.ExifIFD.DateTimeOriginal) == None \
and exif_dict['Exif'].get(piexif.ExifIFD.DateTimeDigitized) == None:
#globでフルの相対パスが帰ってくるのでファイル名のみ取り出す
all_path = f.split('/')
filename = all_path[len(all_path) - 1]
#画像のコピーとExifを再読取り(再読取りはいらないかもしれない)
shutil.copy2(path + filename, new_path + filename)
exif_dict = piexif.load(new_path + filename)
#以下,1つ前と同じ
#JSON読み取り
json_open = open(path + filename + '.json', 'r')
json_load = json.load(json_open)
#日時部分の保存
#この後必要な形に成形
takenTime = json_load['photoTakenTime']['formatted'].split(' ')
date = takenTime[0].split('/') #日付
time = takenTime[1].split(':') #時間
zone = takenTime[2] #タイムゾーン
#datetimeに投げる
basetime = datetime.time(int(time[0]), int(time[1]), int(time[2]))
basedate = datetime.date(int(date[0]), int(date[1]), int(date[2]))
if zone == 'UTC':
#時差修正
jst_date = datetime.datetime.combine(basedate, basetime) + datetime.timedelta(hours=9)
else:
print("UTC以外のタイムゾーンです")
#Exif用に型変更
time_jp = jst_date.strftime("%H:%M:%S")
date_jp = jst_date.strftime('%Y:%m:%d')
#Exif情報の変更
exif_dict['0th'][piexif.ImageIFD.DateTime] = date_jp + " " + time_jp
exif_dict['Exif'][piexif.ExifIFD.DateTimeOriginal] = date_jp + " " + time_jp
exif_dict['Exif'][piexif.ExifIFD.DateTimeDigitized] = date_jp + " " + time_jp
exif_bytes = piexif.dump(exif_dict)
#Exifの変更反映
piexif.insert(exif_bytes, new_path + filename)
print("mod exif : " + filename)
以上です.
本当は,ここからJSONの名前がhogehoge.jpg + .json ではない場合があったり,ファイル名に日本語混ざってたりと苦労したんですが,そのあたりは環境によりますし割愛で
お疲れ様でした~