From 6a0fe3c163803be0eb961fc38551df867e689be8 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 28 Jun 2026 18:29:34 +0200 Subject: [PATCH] fix: try all 3 EXIF date tags + raw bytes scan in _read_cr2_exif --- organize.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/organize.py b/organize.py index c301877..d62fdc0 100644 --- a/organize.py +++ b/organize.py @@ -176,18 +176,24 @@ def _read_other_exif_pil(path: Path) -> str | None: def _read_cr2_exif(path: Path) -> str | None: - """CR2/CR3 (Canon Raw): try piexif first, then PIL embedded JPEG.""" - # Tier 1: piexif on CR2 (TIFF-based EXIF) + """CR2/CR3 (Canon Raw): try piexif, then PIL, then raw bytes scan.""" + # ── Tier 1: piexif (TIFF-based EXIF) ────────────────────── if HAS_PIEXIF: try: exif_dict = piexif.load(str(path)) - raw_val = exif_dict.get('Exif', {}).get(piexif.ExifIFD.DateTimeOriginal) - if raw_val: - return raw_val.decode('utf-8') + # All possible date tag locations in EXIF + for ifd_name, tag_id in ( + ('Exif', piexif.ExifIFD.DateTimeOriginal), # 36867 + ('Exif', piexif.ExifIFD.DateTimeDigitized), # 36868 + ('Image', piexif.ImageIFD.DateTime), # 306 + ): + raw_val = exif_dict.get(ifd_name, {}).get(tag_id) + if raw_val: + return raw_val.decode('utf-8') except Exception: pass - # Tier 2: PIL can read EXIF from CR2's embedded JPEG preview + # ── Tier 2: PIL (embedded JPEG preview) ─────────────────── try: from PIL import Image from PIL.ExifTags import TAGS @@ -195,11 +201,21 @@ def _read_cr2_exif(path: Path) -> str | None: raw = img._getexif() img.close() if raw: - tag_map = {v: k for k, v in TAGS.items()} - for tag_name in ('DateTimeOriginal', 'DateTime'): - tag_code = tag_map.get(tag_name) - if tag_code and tag_code in raw: - return raw[tag_code] + for tag_code in (36867, 36868, 306): # DateTimeOriginal, Digitized, DateTime + val = raw.get(tag_code) + if val: + return val + except Exception: + pass + + # ── Tier 3: raw bytes scan (last resort) ────────────────── + try: + data = path.read_bytes() + # CR2 stores dates as ASCII 'YYYY:MM:DD HH:MM:SS' + import re + m = re.search(rb'(\d{4}:\d{2}:\d{2} \d{2}:\d{2}:\d{2})', data) + if m: + return m.group(1).decode('ascii') except Exception: pass return None