Dateien nach „/“ hochladen
This commit is contained in:
commit
ebd20dc936
1 changed files with 158 additions and 0 deletions
158
exif-collage-creator.py
Normal file
158
exif-collage-creator.py
Normal file
|
@ -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()
|
Loading…
Reference in a new issue