5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GooglePhotoから一括ダウンロードしたらExif情報(日付)がなくなってた件について

Posted at

#はじめに
GooglePhotoが容量うんぬんで困ったことになったのでAmazonPhotoに移行を思い立ちました!
えいやっと,一括ダウンロード&アップロードして終わるかと思いきや,日付不明の画像がちらほら...
確認するとExifの中でも日付がなくなっていました.
GooglePhotoから一括ダウンロードした際に,JSONとして別ファイルに日付情報が分けられてしまったようです.

今回は,分けられてしまったExifの日付情報をPythonを使って復旧させたいと思います.

#環境

  • OS:Windows10
  • Python 2.7.17

#GooglePhotoからのダウンロード

Google データ エクスポートから行うことができます.
詳細は,ググってもらったらたくさんサイトが出てくると思います.
(GooglePhotoの容量制限を受けて,移行したい人はいっぱいいるようですね...)

#ダウンロード結果
Zipを解凍すると

hogehoge.jpg
hogehoge.jpg.json

というように,画像とJSONファイルがセットで保存されていました.

JSONの中身は,だいたいこんな感じです.(本来のファイルからいじっています)

hogehoge.jpg.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で同じ画像を閲覧した際の情報を確認すると,どうやらphotoTakenTimeformattedの部分を撮影時刻としているようなので,ここを読み取り,画像のExifに挿入してあげたらよいというわけです.

#PythonでExifを読み取る
いろいろ調べましたが,piexifがよさそうでした.
このサイトの「その他答え #1」の部分からサンプルコードをお借りしました.

表示するだけのサンプルを載せておきます.
一覧で表示の部分は,こちらからお借りしました.

piexif_test.py
# -*- 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 読み込みを参考にしました.

読み取るだけのサンプルもおいておきます.
読み取る対象はphotoTakenTimeformattedの部分です.

json_read.py
# -*- 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の読み取りにタイムゾーンの変更を加えたコードは以下のようになっています.

json_read.py
# -*- 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を使っています.

change_exif_with_copy.py
# -*- 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を使って全ファイル参照と日付あるなしによる分類をします.

change_exif_with_copy.py
# -*- 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 ではない場合があったり,ファイル名に日本語混ざってたりと苦労したんですが,そのあたりは環境によりますし割愛で
お疲れ様でした~

5
3
0

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
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?