collage/exif-collage-creator.py

158 lines
6.4 KiB
Python

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()