commit ebd20dc936498f7763fab128c94542d6512e4ba9 Author: silaender Date: Tue Mar 4 18:59:05 2025 +0100 Dateien nach „/“ hochladen diff --git a/exif-collage-creator.py b/exif-collage-creator.py new file mode 100644 index 0000000..39f9f86 --- /dev/null +++ b/exif-collage-creator.py @@ -0,0 +1,158 @@ +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()