Advertisement
Unavi

Fix camera metadata

Jun 28th, 2025
404
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.74 KB | None | 0 0
  1. import os
  2. import re
  3. import shutil
  4. from datetime import datetime
  5. from PIL import Image
  6. import piexif
  7.  
  8. def set_image_date_taken(image_path, target_date=None):
  9.     """
  10.    Sets the 'DateTimeOriginal' EXIF attribute of a JPG image.
  11.    If target_date is provided, uses that date. Otherwise, uses the file's modified date.
  12.    """
  13.     try:
  14.         if target_date is None:
  15.             # Get the file's modified date
  16.             mtime = os.path.getmtime(image_path)
  17.             target_date = datetime.fromtimestamp(mtime)
  18.        
  19.         with Image.open(image_path) as img:
  20.             # Create a new exif dictionary
  21.             exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "Interop": {}, "1st": {}, "thumbnail": None}
  22.            
  23.             # Convert datetime object to EXIF format: YYYY:MM:DD HH:MM:SS
  24.             exif_datetime_str = target_date.strftime("%Y:%m:%d %H:%M:%S")
  25.            
  26.             # Set the EXIF tags that Windows Explorer expects for "Date taken"
  27.             # Using direct tag IDs:
  28.             # 36867 = DateTimeOriginal
  29.             # 36868 = DateTimeDigitized
  30.             # 306 = DateTime
  31.             exif_dict["Exif"][36867] = exif_datetime_str.encode("utf-8")
  32.             exif_dict["Exif"][36868] = exif_datetime_str.encode("utf-8")
  33.             exif_dict["0th"][306] = exif_datetime_str.encode("utf-8")
  34.  
  35.             # Dump the exif_dict to bytes
  36.             exif_bytes = piexif.dump(exif_dict)
  37.            
  38.             # Save the image with the new EXIF data
  39.             img.save(image_path, exif=exif_bytes)
  40.             return True
  41.  
  42.     except Exception as e:
  43.         print(f"Error processing {image_path}: {str(e)}")
  44.         # Try alternative method if the first one fails
  45.         try:
  46.             with Image.open(image_path) as img:
  47.                 # Create a new exif dictionary with minimal required fields
  48.                 exif_dict = {"0th": {}, "Exif": {}, "GPS": {}, "Interop": {}, "1st": {}, "thumbnail": None}
  49.                 exif_datetime_str = target_date.strftime("%Y:%m:%d %H:%M:%S")
  50.                
  51.                 # Set only the essential DateTimeOriginal tag using direct ID
  52.                 exif_dict["Exif"][36867] = exif_datetime_str.encode("utf-8")
  53.                
  54.                 exif_bytes = piexif.dump(exif_dict)
  55.                 img.save(image_path, exif=exif_bytes)
  56.                 return True
  57.         except Exception as e2:
  58.             print(f"Failed to process {image_path} with alternative method: {str(e2)}")
  59.             return False
  60.  
  61. def process_image_file(image_path, script_dir):
  62.     """
  63.    Process a single image file: copy to fixed folder with date-based naming and set EXIF data.
  64.    """
  65.     filename = os.path.basename(image_path)
  66.     original_folder = os.path.basename(os.path.dirname(image_path))
  67.    
  68.     # Get the file's modified date
  69.     mtime = os.path.getmtime(image_path)
  70.     file_date = datetime.fromtimestamp(mtime)
  71.    
  72.     # Correct the year if it's 2026 (wrong camera configuration)
  73.     if file_date.year == 2026:
  74.         file_date = file_date.replace(year=2025)
  75.    
  76.     # Create the date-based filename: yyyy.mm.dd hh:mm.[extension]
  77.     date_filename = file_date.strftime("%Y.%m.%d %H.%M")
  78.    
  79.     # Get the file extension
  80.     _, extension = os.path.splitext(filename)
  81.    
  82.     # Create the fixed directory
  83.     fixed_dir = os.path.join(script_dir, "fixed")
  84.     os.makedirs(fixed_dir, exist_ok=True)
  85.    
  86.     # Handle duplicate filenames by adding a counter
  87.     counter = 1
  88.     new_file_path = os.path.join(fixed_dir, f"{date_filename}_{counter}_{original_folder}{extension}")
  89.     while os.path.exists(new_file_path):
  90.         counter += 1
  91.         new_file_path = os.path.join(fixed_dir, f"{date_filename}_{counter}_{original_folder}{extension}")
  92.    
  93.     try:
  94.         # Copy the file to the new location
  95.         shutil.copy2(image_path, new_file_path)
  96.        
  97.         # Set the EXIF date using the corrected file date
  98.         if set_image_date_taken(new_file_path, file_date):
  99.             print(f"Successfully processed: {filename} -> {os.path.basename(new_file_path)}")
  100.         else:
  101.             print(f"Failed to set EXIF data for: {filename}")
  102.             # Move to error folder if EXIF setting fails
  103.             error_dir = os.path.join(script_dir, "fixed", "error")
  104.             os.makedirs(error_dir, exist_ok=True)
  105.             error_path = os.path.join(error_dir, filename)
  106.             shutil.move(new_file_path, error_path)
  107.             print(f"Moved {filename} to error folder due to EXIF failure")
  108.            
  109.     except Exception as e:
  110.         print(f"Error processing {filename}: {str(e)}")
  111.         # Move to error folder if any error occurs
  112.         try:
  113.             error_dir = os.path.join(script_dir, "fixed", "error")
  114.             os.makedirs(error_dir, exist_ok=True)
  115.             error_path = os.path.join(error_dir, filename)
  116.             shutil.copy2(image_path, error_path)
  117.             print(f"Copied {filename} to error folder due to processing error")
  118.         except Exception as copy_error:
  119.             print(f"Failed to copy {filename} to error folder: {str(copy_error)}")
  120.  
  121. def main():
  122.     script_dir = os.path.dirname(os.path.abspath(__file__))
  123.    
  124.     print(f"Searching for JPG files in subfolders of: {script_dir}")
  125.    
  126.     # Walk through all subdirectories
  127.     for root, dirs, files in os.walk(script_dir):
  128.         # Skip the 'fixed' directory to avoid processing already processed files
  129.         if 'fixed' in root:
  130.             continue
  131.         if 'good' in root:
  132.             continue
  133.            
  134.         for filename in files:
  135.             if filename.lower().endswith(".jpg"):
  136.                 image_path = os.path.join(root, filename)
  137.                 process_image_file(image_path, script_dir)
  138.  
  139. if __name__ == "__main__":
  140.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement