Files
guyg1474andClaude Opus 5.5 a1a1998d1e Start robuster: Problembilder verhindern die Umstellung nicht
- Migration Schritt 2: Lese-/Schreibfehler (z. B. Dateirechte) und kaputte
  Bilder werden protokolliert und übersprungen, statt den Serverstart
  abzubrechen
- bilder.py: alle Pillow-Fehler werden zu einer Eingabe-Fehlermeldung bzw.
  "keine Metadaten" statt zu Fehler 500
- Test mit schreibgeschütztem und kaputtem Bild

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 18:51:42 +02:00

55 lines
2.5 KiB
Python

"""Hochgeladene Bilder ohne Metadaten speichern.
Fotos vom Handy enthalten in den EXIF-Daten oft den Aufnahmeort (GPS), das Gerät und die Uhrzeit.
Die Bilder sind für alle Konten sichtbar, deshalb wird alles außer den Bildpunkten entfernt.
Die Drehung aus den EXIF-Daten wird vorher angewendet, damit Hochkant-Fotos richtig stehen bleiben.
Nur das Farbprofil (ICC) bleibt erhalten, damit sich die Farben nicht verändern.
GIFs bleiben unverändert: Sie haben keine EXIF-/GPS-Daten, und neu speichern würde Animationen verschlechtern.
"""
import io
from PIL import Image, ImageOps
from .common import ValidationError
# Schutz vor "Dekompressionsbomben" (winzige Datei, riesiges Bild)
Image.MAX_IMAGE_PIXELS = 60_000_000
def hat_metadaten(data: bytes) -> bool:
"""Enthält das Bild EXIF-, XMP- oder Text-Angaben (z. B. GPS, Kamera, Kommentar)?"""
try:
with Image.open(io.BytesIO(data)) as img:
return bool(img.getexif()) or any(k in img.info for k in ("xmp", "XML:com.adobe.xmp", "comment", "exif")) \
or bool(getattr(img, "text", None))
except Exception: # kaputte oder exotische Datei: als "ohne Metadaten" behandeln
return False
def ohne_metadaten(data: bytes, ext: str) -> bytes:
"""Bild neu schreiben, ohne EXIF/XMP/Text-Angaben. ext: jpg, png, webp oder gif."""
if ext == "gif":
return data
try:
with Image.open(io.BytesIO(data)) as img:
animated = getattr(img, "is_animated", False)
icc = img.info.get("icc_profile")
out = io.BytesIO()
if ext == "webp" and animated:
# Animierte WebP: alle Bilder übernehmen, Metadaten fallen weg
img.save(out, "WEBP", save_all=True, quality=90, icc_profile=icc, duration=img.info.get("duration"), loop=img.info.get("loop", 0))
return out.getvalue()
img = ImageOps.exif_transpose(img)
if ext == "jpg":
if img.mode not in ("RGB", "L", "CMYK"):
img = img.convert("RGB")
img.save(out, "JPEG", quality=92, optimize=True, icc_profile=icc)
elif ext == "png":
img.save(out, "PNG", optimize=True, icc_profile=icc)
else:
img.save(out, "WEBP", quality=90, icc_profile=icc)
return out.getvalue()
except Exception: # Pillow wirft je nach Format verschiedene Fehler
raise ValidationError("Das Bild konnte nicht gelesen werden oder ist zu groß.")