Spaces:
Sleeping
Sleeping
| #!/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() | |