image-metadata-tool / metadata_randomizer.py
Mansi Maheshwari
Initial commit: image metadata web app
7142f88
#!/usr/bin/env python3
"""
Realistic Image Metadata Randomizer
-----------------------------------
This tool simulates realistic camera metadata for batches of images.
It uses metadata_pipeline.py as the engine to embed the data.
You can customize the lists below to change the 'reality' of the generated data.
"""
import os
import random
import argparse
from datetime import datetime, timedelta
from pathlib import Path
from metadata_pipeline import write_metadata
# ── Configuration Tables (Edit these to change the random pools) ─────────────
# Real-world device profiles
DEVICES = [
{"make": "Apple", "model": "iPhone 15 Pro Max", "software": "iOS 17.5.1", "lens_make": "Apple", "lens_model": "iPhone 15 Pro Max back triple camera 6.86mm f/1.78"},
{"make": "Apple", "model": "iPhone 14", "software": "iOS 16.2", "lens_make": "Apple", "lens_model": "iPhone 14 back dual camera 5.7mm f/1.5"},
{"make": "Samsung", "model": "SM-S928B", "software": "One UI 6.1", "lens_make": "Samsung", "lens_model": "S24 Ultra Main Camera"},
{"make": "Samsung", "model": "Galaxy S23 Ultra", "software": "Android 14", "lens_make": "Samsung", "lens_model": "S23 Ultra Main Camera"},
{"make": "Google", "model": "Pixel 8 Pro", "software": "Android 14.1","lens_make": "Google", "lens_model": "Pixel 8 Pro Main Camera"},
{"make": "Sony", "model": "ILCE-7M4", "software": "v2.01", "lens_make": "Sony", "lens_model": "FE 24-70mm F2.8 GM II"},
{"make": "Canon", "model": "EOS R6 Mark II", "software": "v1.2.0", "lens_make": "Canon", "lens_model": "RF 24-105mm F4 L IS USM"},
{"make": "Fujifilm", "model": "X-T5", "software": "v2.03", "lens_make": "Fujifilm", "lens_model": "XF 18-55mm F2.8-4 R LM OIS"},
]
# Global Locations (Latitude, Longitude, Alt)
LOCATIONS = [
{"name": "Marina Beach, Chennai", "lat": 13.0489, "lon": 80.2811, "alt": 5.0},
{"name": "Eiffel Tower, Paris", "lat": 48.8584, "lon": 2.2945, "alt": 35.0},
{"name": "Central Park, NYC", "lat": 40.7851, "lon": -73.9683, "alt": 10.0},
{"name": "Tokyo Tower, Japan", "lat": 35.6586, "lon": 139.7454, "alt": 42.0},
{"name": "Gateway of India", "lat": 18.9220, "lon": 72.8347, "alt": 2.0},
{"name": "Grand Canyon, USA", "lat": 36.0544, "lon": -112.1401, "alt": 2100.0},
{"name": "Table Mountain", "lat": -33.9628, "lon": 18.4098, "alt": 1086.0},
{"name": "Sydney Opera House", "lat": -33.8568, "lon": 151.2153, "alt": 4.0},
]
# Creative writing pools
AUTHORS = ["Arjun V.", "Priya Sharma", "Michael Scott", "Elena R.", "Sarah Chen", "David K."]
TITLES = [
"Summer Vacation", "Sunday Morning", "City Lights", "Nature Walk",
"Working from home", "Golden Hour", "Weekend Trip", "Random Capture"
]
DESCRIPTIONS = [
"A beautiful sunny day with clear skies.",
"Captured while exploring the city streets.",
"Testing out the new camera settings.",
"Breathtaking view from the top.",
"Moments captured during our annual trip.",
"Low light performance test.",
]
# ── Randomization Logic ───────────────────────────────────────────────────────
def get_random_date():
"""Generate a random date within the last 5 years."""
now = datetime.now()
# Randomly pick a day between 0 and 5 years ago (approx 1825 days)
random_days = random.randint(0, 1825)
random_seconds = random.randint(0, 86400)
dt = now - timedelta(days=random_days, seconds=random_seconds)
return dt.strftime("%Y:%m:%d %H:%M:%S")
def process_file(file_path: str, output_dir: str = None):
"""Generate and apply random metadata to a single file."""
device = random.choice(DEVICES)
location = random.choice(LOCATIONS)
author = random.choice(AUTHORS)
title = random.choice(TITLES)
desc = random.choice(DESCRIPTIONS)
date = get_random_date()
rating = random.randint(3, 5) # Mostly good photos!
# Construct arguments for the pipeline
class MockArgs:
def __init__(self):
self.title = title
self.author = author
self.description = desc
self.copyright = f"Β© {datetime.now().year} {author}"
self.software = device["software"]
self.make = device["make"]
self.model = device["model"]
self.lens_make = device.get("lens_make")
self.lens_model = device.get("lens_model")
self.keywords = "random,metadata,test"
self.date = date
self.rating = rating
self.lat = location["lat"]
self.lon = location["lon"]
self.alt = location["alt"]
self.output = None # Handled below
args = MockArgs()
file_name = os.path.basename(file_path)
if output_dir:
out_path = os.path.join(output_dir, file_name)
else:
out_path = file_path # Overwrite
try:
write_metadata(file_path, out_path, args)
print(f" \033[32m[RANDOMIZED]\033[0m {file_name} -> {device['model']} | {device.get('lens_model', 'No Lens')} | {location['name']}")
except Exception as e:
print(f" \033[31m[FAILED]\033[0m {file_name}: {e}")
def main():
parser = argparse.ArgumentParser(description="Realistic Metadata Randomizer")
parser.add_argument("path", help="Folder or specific image file to randomize")
parser.add_argument("--output", "-o", help="Output directory (optional)")
args = parser.parse_args()
target = Path(args.path)
if not target.exists():
print(f"Path not found: {args.path}")
return
exts = {".jpg", ".jpeg", ".png", ".webp"}
if target.is_file():
if target.suffix.lower() in exts:
process_file(str(target), args.output)
else:
print(f"Unsupported file type: {target.suffix}")
else:
files = [f for f in target.iterdir() if f.suffix.lower() in exts]
if not files:
print("No supported images found in folder.")
return
print(f"\n\033[1mStarting randomization for {len(files)} files...\033[0m\n")
if args.output:
os.makedirs(args.output, exist_ok=True)
for f in files:
process_file(str(f), args.output)
print(f"\n\033[1;32mDONE!\033[0m Processed {len(files)} files.")
if __name__ == "__main__":
main()