DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

Googleフォトから写真をダウンロードして保存日を元のデータに修正した話 備忘録

ある日、スマホの写真を見ようとしたら・・・「あれ?SDカードが読めない??なんで?」

「え!SDカードデータ消えてるやんっ!!!」ということがありました。

 

一応、Googleフォトでバックアップしているのでデータは復元できるのですが、Amazonフォトにアップロードしようと思っている写真が手元に無いのは困ります。

(個人的に、Googleフォトは何でもかんでもバックアップ&不要なものはガンガン消す。Amazonフォトは家族もFireTVで見れるので家族写真をメインで保存というスタンスで使っています。)

 

で、Googleフォトから試しにファイルをダウンロードしたわけですが・・・、

Googleフォトからファイルをダウンロードした場合、ファイルの作成日がダウンロードした日付になっちゃうんですよね。

 

このままアップロードしたら全てダウンロードした日付で登録されちゃいます。

 

かといって、pythonコードを書いてGoogleフォトで日付を確認しながら1つづつ手動で変更するなんてのは面倒くさすぎ!

(400枚ほど変更する必要が・・・)

 

そこで、どうにかならないものかと調べるとGoogleのバックアップ機能を使えば年間の写真が写真用のデータと共に一気にダウンロードできるということが判明しました。

 

Googleフォトから、「Googleアカウントを管理」を選択します。

 

「データとプライバシー」を選択

 

下の方にある「データをダウンロード」を選択

 

ダウンロード対象のサービスを一度全て解除します。

 

 

目当てのGoogleフォトは下の方にあるので、チェックを入れ、「すべてのフォトアルバムが含まれます」の項目を選択

 

すると、バックアップ対象となる年が選べます。

 

チェックを入れたら、下の方で「次のステップ」へ

 

エクスポート方法などを選択します。この辺はお好みで。

圧縮ファイルの種類や分割サイズも選択出来ますが、たくさんのファイルをダウンロードするのにあまり小さいサイズを選択すると、後で出てくるjsonファイルと写真ファイルがバラバラにダウンロードされる可能性があるので(僕は2Gで失敗したので)4GBを選択しました。

 

エクスポートを作成を選択すると、必要なファイルが圧縮されてダウンロードできるようになります。

僕の場合はメールでのお知らせを選択したので、メール通知が届きました。

2つファイルがありますが、1つはメインの写真データ、もう一つは「アーカイブ概要」という何らかの説明ファイルでした(詳しく見ていません)。

 

 

 

残念ながらダウンロードしたファイルは、やはりGoogleフォトでダウンロードしたファイルと同じで作成日は今日の日付になってしまっています。同じファイル名で.jsonファイルが写真のいろいろなデータを保存したファイルです。

 

jsonファイルの中身

要するに、このjsonファイルに記録されている日時を利用してデータを保存し直したら良いんです。

 

ということで、pythonコードを作りました。というか、今回はChatGPT先生にサクッと作っていただきました。

コードを実行する前にpiexifをpipでインストールする必要があります。

pip install piexif

piexif は、Exif 情報を JPEG 画像に読み書きするための Python ライブラリだそうです。よくわかりませんが、GPT先生が使えということです。

 

### pythonファイル ####

import os

import json

import piexif

from datetime import datetime

 

def write_exif_datetime(image_path, datetime_str):

    try:

        exif_dict = piexif.load(image_path)

    except Exception:

        exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "1st": {}, "thumbnail": None}

 

    # 不正なExif値を削除(型が不正なものを除外)

    for ifd in exif_dict:

        if isinstance(exif_dict[ifd], dict):

            tags_to_remove = []

            for tag, value in exif_dict[ifd].items():

                try:

                    piexif._dump_value(tag, value, ifd)

                except Exception:

                    tags_to_remove.append(tag)

            for tag in tags_to_remove:

                del exif_dict[ifd][tag]

 

    dt_bytes = datetime_str.encode('utf-8')

    exif_dict["Exif"][piexif.ExifIFD.DateTimeOriginal] = dt_bytes

    exif_dict["Exif"][piexif.ExifIFD.DateTimeDigitized] = dt_bytes

    exif_dict["0th"][piexif.ImageIFD.DateTime] = dt_bytes

 

    exif_bytes = piexif.dump(exif_dict)

    piexif.insert(exif_bytes, image_path)

 

def update_file_timestamp(image_path, timestamp):

    os.utime(image_path, (timestamp, timestamp))

 

def process_folder_recursively(root_folder):

    processed = 0

    skipped = 0

 

    for current_dir, _, files in os.walk(root_folder):

        for file in files:

            if not file.endswith(".json"):

                continue

 

            json_path = os.path.join(current_dir, file)

 

            try:

                with open(json_path, "r", encoding="utf-8") as f:

                    data = json.load(f)

            except Exception as e:

                print(f"⚠️ JSON読込失敗: {file} - {e}")

                continue

 

            title = data.get("title")

            if not title:

                print(f"⏸️ titleフィールドがない: {file}")

                skipped += 1

                continue

 

            image_path = None

            for ext in ["", ".jpg", ".jpeg", ".JPG", ".JPEG"]:

                candidate = os.path.join(current_dir, title + ext)

                if os.path.exists(candidate):

                    image_path = candidate

                    break

 

            if not image_path:

                candidate = os.path.join(current_dir, title)

                if os.path.exists(candidate):

                    image_path = candidate

 

            if image_path:

                try:

                    timestamp = None

                    if "photoTakenTime" in data and "timestamp" in data["photoTakenTime"]:

                        timestamp = int(data["photoTakenTime"]["timestamp"])

                    elif "creationTime" in data and "timestamp" in data["creationTime"]:

                        timestamp = int(data["creationTime"]["timestamp"])

                    else:

                        print(f"⏸️ タイムスタンプが存在しません: {file}")

                        skipped += 1

                        continue

 

                    dt = datetime.fromtimestamp(timestamp)

                    formatted = dt.strftime("%Y:%m:%d %H:%M:%S")

 

                    write_exif_datetime(image_path, formatted)

                    update_file_timestamp(image_path, timestamp)

 

                    os.remove(json_path)

 

                    print(f"✅ {os.path.basename(image_path)} にExifとファイル日時を設定しJSON削除")

                    processed += 1

                except Exception as e:

                    print(f"⚠️ 書き込み失敗: {file} - {e}")

            else:

                print(f"⏸️ 画像が存在しません: {title}")

                skipped += 1

 

    print(" 📦 完了レポート")

    print(f"✅ Exifと日時反映&JSON削除: {processed} 件")

    print(f"📂 JSONのみ残した(画像なしまたはエラー): {skipped} 件")

 

if __name__ == "__main__":

    target_dir = "/Users/[YourDir]/Downloads/Takeout/"  # 処理対象のフォルダに変更

    process_folder_recursively(target_dir)

タイムスタンプの判別か2種類あるのは、保存されているデータに2種類の記録方式があったためです。

スマホを変えたからなのか、Googleの仕様かは不明です。

はい、これを実行します。

成功したファイルはjsonを削除し、読み込めないファイル(jpeg以外)はそのまま残されます。

今回の用途では動画はあまり必要ないのでOKです。

 

ということで、Googleフォトから写真データをダウンロードして、元の保存日時にサクッと戻すことができました。

すごいぞChatGPT!!

 

あとはAmazonフォトにアップロードして、本日の作業は完了です。

 

AmazonフォトはGoogleフォトと違い、元の写真のファイルのまま(googleでは写真は圧縮される)容量無制限で保存されます。

これだけでもプライム会員の値打ちありますね。

Amazon Photos

Amazon Photos

  • Amazon.com
Amazon

kampa.me