Skip to content

Instantly share code, notes, and snippets.

@J0s3f
Created October 22, 2025 20:43
Show Gist options
  • Select an option

  • Save J0s3f/5d09838d54b9752b149a30aab269f525 to your computer and use it in GitHub Desktop.

Select an option

Save J0s3f/5d09838d54b9752b149a30aab269f525 to your computer and use it in GitHub Desktop.
Collagen erstellen aus Fotos im Ordner
import os
import pillow_heif
from PIL import Image, ImageChops
pillow_heif.register_heif_opener()
directory = 'D:\\fotos\\klein'
output_dir = 'D:\\fotos\\collagen'
canvas_size = 5000
os.makedirs(output_dir, exist_ok=True)
aspect_threshold = 1.3
square_images = []
wide_images = []
def rotate_and_trim(img, angle=90, bg_color=(255, 255, 255)):
# Bild drehen (expand=True verhindert Abschneiden)
rotated = img.rotate(angle, expand=True)
# Wenn das Bild Transparenz hat → einfacher Fall
if 'A' in rotated.getbands():
bbox = rotated.getbbox()
return rotated.crop(bbox)
# Wenn kein Alphakanal → über Hintergrundfarbe Differenz berechnen
if bg_color is None:
# Versuchen, Hintergrundfarbe automatisch zu erraten (oben links)
bg_color = rotated.getpixel((0, 0))
bg = Image.new(rotated.mode, rotated.size, bg_color)
diff = ImageChops.difference(rotated, bg)
bbox = diff.getbbox()
return rotated.crop(bbox) if bbox else rotated
for filename in sorted(os.listdir(directory)):
if not filename.lower().endswith((".jpg", ".jpeg", ".png", ".heic")):
continue
try:
path = os.path.join(directory, filename)
img = Image.open(path)
w, h = img.size
if w < h:
ratio = h / w
else:
ratio = w / h
if ratio > aspect_threshold:
wide_images.append(path)
else:
square_images.append(path)
except Exception as e:
print(f'Fehler bei {filename}: {e}')
print("Es wurden " + str(len(wide_images) + len(square_images)) + " Bilder gefunden")
def resize_with_aspect(img, target_w, target_h):
# Maximale Seite auf target setzen, andere proportional skalieren
w, h = img.size
scale_w = target_w / w
scale_h = target_h / h
if scale_w < scale_h:
# Breite anpassen, Höhe proportional kleiner
new_w = target_w
new_h = int(h * scale_w)
else:
# Höhe anpassen, Breite proportional kleiner
new_w = int(w * scale_h)
new_h = target_h
resized_img = img.resize((new_w, new_h), Image.LANCZOS)
# Weißes Bild erstellen mit Zieldimensionen
background = Image.new('RGB', (target_w, target_h), (255, 255, 255))
offset = ((target_w - new_w) // 2, (target_h - new_h) // 2)
background.paste(resized_img, offset)
return background
def create_collage(layout, index):
collage = Image.new('RGB', (canvas_size, canvas_size), (255, 255, 255))
for item in layout:
img = Image.open(item['path'])
w, h = img.size
if w < h:
img = rotate_and_trim(img)
img = resize_with_aspect(img, item['w'], item['h'])
collage.paste(img, (item['x'], item['y']))
collage.save(os.path.join(output_dir, f'collage_{index:03}.jpg'))
collage_index = 1
while square_images or wide_images:
layout = []
if len(wide_images) >= 2:
slot_h = canvas_size // 2
for y in range(2):
path = wide_images.pop(0)
layout.append({'path': path, 'x': 0, 'y': y * slot_h, 'w': canvas_size, 'h': slot_h})
create_collage(layout, collage_index)
elif len(wide_images) >= 1 and len(square_images) >= 2:
wide_path = wide_images.pop(0)
layout.append({'path': wide_path, 'x': 0, 'y': 0, 'w': canvas_size, 'h': canvas_size // 2})
w_sq = canvas_size // 2
h_sq = canvas_size // 2
for i in range(2):
sq = square_images.pop(0)
layout.append({'path': sq, 'x': i * w_sq, 'y': canvas_size // 2, 'w': w_sq, 'h': h_sq})
create_collage(layout, collage_index)
elif len(square_images) >= 4:
w_sq = canvas_size // 2
h_sq = canvas_size // 2
for i in range(4):
path = square_images.pop(0)
layout.append({'path': path, 'x': (i % 2) * w_sq, 'y': (i // 2) * h_sq, 'w': w_sq, 'h': h_sq})
create_collage(layout, collage_index)
else:
rest = square_images + wide_images
w_sq = canvas_size // 2
h_sq = canvas_size // 2
for i, p in enumerate(rest[:4]):
layout.append({'path': p, 'x': (i % 2) * w_sq, 'y': (i // 2) * h_sq, 'w': w_sq, 'h': h_sq})
create_collage(layout, collage_index)
break
collage_index += 1
print(f'Erstellt {collage_index - 1} Collagen im Ordner {output_dir}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment