import os import sys from PIL import Image, ImageDraw, ImageFont, ExifTags import math import argparse from datetime import datetime def get_exif_data(image_path): """Extrahiert EXIF-Daten aus einem Bild.""" try: img = Image.open(image_path) exif_data = {} if hasattr(img, '_getexif') and img._getexif(): for tag, value in img._getexif().items(): if tag in ExifTags.TAGS: tag_name = ExifTags.TAGS[tag] # Konvertiere spezielle EXIF-Daten in lesbare Formate if tag_name == 'DateTimeOriginal': try: value = datetime.strptime(value, '%Y:%m:%d %H:%M:%S').strftime('%d.%m.%Y, %H:%M:%S') except: pass exif_data[tag_name] = value # Sammle wichtige EXIF-Daten important_exif = { "Dateiname": os.path.basename(image_path), "Kamera": exif_data.get('Make', 'Unbekannt') + ' ' + exif_data.get('Model', ''), "Aufnahmedatum": exif_data.get('DateTimeOriginal', 'Unbekannt'), "Belichtungszeit": str(exif_data.get('ExposureTime', 'Unbekannt')), # Direkt als String übernehmen "Blende": f"f/{exif_data.get('FNumber', 'Unbekannt')}" if 'FNumber' in exif_data else 'Unbekannt', "ISO": exif_data.get('ISOSpeedRatings', 'Unbekannt'), "Brennweite": f"{exif_data.get('FocalLength', 'Unbekannt')}mm" if 'FocalLength' in exif_data else 'Unbekannt', "Auflösung": f"{img.width} x {img.height} px" } return important_exif, img except Exception as e: print(f"Fehler beim Lesen von {image_path}: {e}") return None, None def create_exif_overlay(img, exif_data, font_path=None, font_size=20, margin=10): """Erstellt eine Überlagerung mit EXIF-Daten für ein Bild.""" overlay = Image.new('RGBA', img.size, (0, 0, 0, 0)) draw = ImageDraw.Draw(overlay) # Versuche, den angegebenen Font zu laden oder verwende den Standardfont try: if font_path and os.path.exists(font_path): font = ImageFont.truetype(font_path, font_size) else: # Versuche einen Standardfont zu laden try: font = ImageFont.truetype("arial.ttf", font_size) except: font = ImageFont.load_default() except: font = ImageFont.load_default() # Erstelle einen halbdurchsichtigen Hintergrund für die Textbox text_bg_height = len(exif_data) * (font_size + 5) + margin * 2 draw.rectangle([(margin, margin), (img.width - margin, text_bg_height)], fill=(0, 0, 0, 160)) # Füge den Text hinzu y = margin + 5 for key, value in exif_data.items(): text = f"{key}: {value}" draw.text((margin + 5, y), text, font=font, fill=(255, 255, 255, 255)) y += font_size + 5 return overlay def create_collage(image_paths, output_path, font_path=None, font_size=20, margin=10, max_width=2000, padding=10): """Erstellt eine Collage aus mehreren Bildern mit EXIF-Daten-Überlagerungen.""" images_with_exif = [] max_height = 0 total_width = 0 # Sammle alle Bilder und ihre EXIF-Daten for path in image_paths: exif_data, img = get_exif_data(path) if exif_data and img: # Berechne die neue Größe, um die maximale Breite einzuhalten width_ratio = max_width / len(image_paths) new_width = min(img.width, width_ratio - padding * 2) ratio = new_width / img.width new_height = int(img.height * ratio) # Konvertiere zu RGB, falls das Bild einen Alpha-Kanal hat if img.mode == 'RGBA': img = img.convert('RGB') # Größe ändern - mit int für die Breite resized_img = img.resize((int(new_width), new_height), Image.Resampling.LANCZOS) overlay = create_exif_overlay(resized_img, exif_data, font_path, font_size, margin) # Kombiniere Bild und Überlagerung combined = Image.new('RGB', resized_img.size, (0, 0, 0)) combined.paste(resized_img, (0, 0)) combined.paste(overlay, (0, 0), overlay) images_with_exif.append(combined) max_height = max(max_height, new_height) total_width += int(new_width) + padding * 2 # Schließe das ursprüngliche Bild img.close() if not images_with_exif: print("Keine gültigen Bilder gefunden.") return # Berechne die Größe der Collage - mit expliziter Konvertierung zu int collage_width = int(min(total_width, max_width)) collage_height = int(max_height + padding * 2) # Erstelle die Collage collage = Image.new('RGB', (collage_width, collage_height), (255, 255, 255)) # Füge die Bilder zur Collage hinzu x = padding for img in images_with_exif: collage.paste(img, (x, padding)) x += img.width + padding * 2 # Speichere die Collage collage.save(output_path, quality=95, dpi=(300, 300)) print(f"Collage erstellt und gespeichert als: {output_path}") # Aufräumen collage.close() for img in images_with_exif: img.close() def main(): parser = argparse.ArgumentParser(description="Erstellt eine Collage aus Bildern mit EXIF-Daten.") parser.add_argument("images", nargs="+", help="Pfad(e) zu den Bildern") parser.add_argument("--output", "-o", default="collage.jpg", help="Ausgabedatei (Standard: collage.jpg)") parser.add_argument("--font", "-f", help="Pfad zur Schriftartdatei (TTF)") parser.add_argument("--fontsize", "-s", type=int, default=20, help="Schriftgröße (Standard: 20)") parser.add_argument("--margin", "-m", type=int, default=10, help="Randabstand für Text (Standard: 10)") parser.add_argument("--maxwidth", "-w", type=int, default=2000, help="Maximale Breite der Collage (Standard: 2000)") parser.add_argument("--padding", "-p", type=int, default=10, help="Abstand zwischen Bildern (Standard: 10)") args = parser.parse_args() create_collage( args.images, args.output, args.font, args.fontsize, args.margin, args.maxwidth, args.padding ) if __name__ == "__main__": main()