ぱいそん Exif情報 csv化 | 60歳を迎えて、思うこと。

60歳を迎えて、思うこと。

いつの間にか、「60」という年月が経ちました。
残り少ないか多いか?わかりませんが。
じじぃ~の「ひとりごと」を細々と続けられれば。。。

ぱいそん Exif情報 csv化

にゃあにゃあw

Exif情報を csv化 する
pythonスクリプト
【Gemini】様 に 丸投げ!!!

# ==== 【Gemini】様
データベースやExcel(スプレッドシート)で読み込んで分析するのに最適な形式にまとめています。

### Exif一括抽出&CSV出力スクリプト
以下のコードを、例えば `Exif-To-CSV.py` という名前で保存してご活用ください。
```python



import os
import csv
from PIL import Image, ExifTags

# ==========================================
# ★設定エリア★
# 1. 解析したい画像が入っているフォルダのパス指定
TARGET_DIR = r"D:\_Exif-Rename"

# 2. 出力するCSVファイルの保存先指定
OUTPUT_CSV = r"D:\_Exif-Rename\Exif_Database.csv"

# 対象とする画像の拡張子
IMAGE_EXTENSIONS = ('.jpg', '.jpeg', '.png', '.tiff', '.webp')
# ==========================================
def get_tag_name(tag_id):
    """ExifタグIDから人間が読めるタグ名を取得する"""
    return Image.ExifTags.TAGS.get(tag_id, f"Unknown(0x{tag_id:04x})")

def clean_value(val):
    """CSV出力用にバイナリデータや非表示文字(ヌル文字等)を整形する"""
    if val is None:
        return ""
    if isinstance(val, bytes):
        try:
            val = val.decode('utf-8', errors='ignore')
        except Exception:
            val = repr(val)
    
    # 制御文字(ヌル文字 \x00 等)の除去
    val_str = str(val).replace('\x00', '').strip()
    return val_str

def process_images_to_csv(target_dir, output_csv):
    print("=" * 60)
    print(f"【スキャン開始】対象フォルダ: {target_dir}")
    print("=" * 60)

    if not os.path.exists(target_dir):
        print(f"[ERROR] 指定されたフォルダが存在しません: {target_dir}")
        return

    # 全ファイルから検出されたすべてのExifタグ名を動的に集計(CSVのヘッダーにするため)
    # 共通ヘッダー(ファイル情報)
    base_headers = ["ファイルパス", "ファイル名", "画像幅(px)", "画像高さ(px)"]
    all_exif_tags = set()
    
    # 抽出結果を一時保持するリスト
    records = []
    
    # 1. フォルダ内を再帰的にスキャン
    file_count = 0
    for root, _, files in os.walk(target_dir):
        for file in files:
            if file.lower().endswith(IMAGE_EXTENSIONS):
                file_path = os.path.join(root, file)
                file_count += 1
                
                record = {
                    "ファイルパス": file_path,
                    "ファイル名": file,
                    "画像幅(px)": "",
                    "画像高さ(px)": ""
                }
                
                try:
                    with Image.open(file_path) as img:
                        record["画像幅(px)"] = img.width
                        record["画像高さ(px)"] = img.height
                        
                        exif = img.getexif()
                        if exif:
                            # 1階(メインIFD)の読み込み
                            for tag_id, value in exif.items():
                                tag_name = get_tag_name(tag_id)
                                record[tag_name] = clean_value(value)
                                all_exif_tags.add(tag_name)

                            # 2階(サブIFD: 0x8769)の読み込み
                            sub_exif = exif.get_ifd(0x8769)
                            if sub_exif:
                                for tag_id, value in sub_exif.items():
                                    tag_name = get_tag_name(tag_id)
                                    record[tag_name] = clean_value(value)
                                    all_exif_tags.add(tag_name)

                except Exception as e:
                    print(f"[WARNING] 読み込み失敗 ({file}): {e}")

                records.append(record)

    print(f"\n[INFO] 対象画像ファイル数: {file_count} 件")
    print(f"[INFO] 検出されたExif項目数: {len(all_exif_tags)} 種類")

    # 2. CSVファイルの書き出し
    # タグ名をアルファベット順にソートしてヘッダーを作成
    sorted_exif_tags = sorted(list(all_exif_tags))
    fieldnames = base_headers + sorted_exif_tags

    try:
        # Excelで開いたときに文字化けしないよう utf-8-sig (BOM付きUTF-8) で出力
        with open(output_csv, mode='w', newline='', encoding='utf-8-sig') as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for rec in records:
                writer.writerow(rec)

        print("\n" + "=" * 60)
        print(f"【完了】CSVデータベースを出力しました!")
        print(f"保存先: {output_csv}")
        print("=" * 60)

    except Exception as e:
        print(f"[ERROR] CSVファイルの書き出しに失敗しました: {e}")

if __name__ == "__main__":
    process_images_to_csv(TARGET_DIR, OUTPUT_CSV)



### ✨ このスクリプトの工夫ポイント
1. **2階(サブIFD)も漏らさず取得**
以前のチェッカー同様、F値・焦点距離・シャッタースピードやサブセコンド(マイクロ秒)が眠っている **「2階の隠し部屋 (0x8769)」** も完全走査して取得します。
2. **全画像のタグを動的に自動集計**
画像によって「入っているExif項目」が異なる場合でも、フォルダ内の全画像をチェックして**存在する全てのExifタグを列挙し、自動でCSVの列(ヘッダー)を作成**します。
3. **バイナリゴミ・ヌル文字の自動除去**
以前問題になった `\x00` や末尾の空文字などを自動的にクリア(サニタイズ)してから書き込むため、Excel等で読み込んだときに崩れません。
4. **Excelでの文字化け防止 (`utf-8-sig`)**
出力時のエンコーディングに `utf-8-sig` を採用しているため、生成されたCSVをそのままExcelで開いても文字化けしません。
5. **画像サイズ(幅・高さ)も自動付与**
Exif情報とは別に、実際の画像ピクセルサイズ(幅・高さ)も自動取得してCSVの先頭に追加します。

### 💡 使い方
1. スクリプト冒頭の `TARGET_DIR`(解析したいフォルダ)と `OUTPUT_CSV`(出力先CSVのパス)を環境に合わせて書き換えてください。
2. 実行すると、指定したフォルダ内の画像を全件走査し、CSVが生成されます。
# ==============================