Files
Aether/backend/internal/admin/thumbnails_handler.go
T
marcandClaude Opus 5 4bd9a6ca56 fix(thumbnails): EXIF-Drehung auswerten, hochkant blieb quer
Kameras speichern die Bildpunkte fast immer quer und legen die Drehung
als EXIF-Notiz daneben. Browser befolgen sie von selbst - Go nicht.
Deshalb stand dasselbe Foto in der grossen Ansicht aufrecht und lag im
Vorschaubild auf der Seite.

Neues Paket internal/imageutil liest genau ein Feld (0x0112) aus dem
Anfang der Datei und dreht danach. Von Hand statt mit einer Bibliothek:
Der Weg dorthin ist kurz und liegt fest, und gebraucht wird ein Feld.
Gelesen werden nur die ersten 64 KB, damit ein 40-MB-Foto nicht zweimal
im Speicher liegt.

Gedreht wird vor dem Verkleinern - andersherum bekaeme ein hochkantes
Foto den Zuschnitt eines Querformats.

Bestehende Vorschaubilder aendern sich davon nicht. Dafuer neu:
POST /admin/thumbnails/rebuild samt Knopf im Admin-Bereich.

Auch Profilbilder aus OIDC laufen jetzt durch dieselbe Auswertung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 14:08:10 +02:00

72 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package admin
import (
"fmt"
"net/http"
"aether/internal/audit"
"aether/internal/thumbnails"
"aether/pkg/response"
)
/*
POST /api/v1/admin/thumbnails/rebuild – Vorschaubilder neu erzeugen.
Anlass: Bis heute wurde die EXIF-Drehung beim Erzeugen nicht ausgewertet.
Jedes hochkant aufgenommene Foto liegt im bestehenden Bestand deshalb quer,
während dasselbe Bild in der großen Ansicht aufrecht steht – der Browser
befolgt die Notiz von selbst, der Server tat es nicht.
Beim Hochladen entstehen Vorschaubilder von allein; für das, was schon da ist,
braucht es diesen einen Anstoß. Er läuft im Vordergrund und meldet Zahlen:
Ein Vorgang, der den halben Bestand neu schreibt, soll nicht stumm im
Hintergrund verschwinden.
*/
func (h *Handler) RebuildThumbnails(w http.ResponseWriter, r *http.Request) {
if _, ok := requireAdmin(r); !ok {
response.Error(w, http.StatusForbidden, "admin required")
return
}
list, err := h.files.ImageFiles(r.Context())
if err != nil {
response.Error(w, http.StatusInternalServerError, "could not list images")
return
}
var rebuilt, failed int
for _, f := range list {
if !thumbnails.SupportedMIME(f.MimeType) {
continue
}
rc, err := h.storage.Get(r.Context(), f.StorageKey)
if err != nil {
failed++
continue
}
err = thumbnails.Generate(r.Context(), h.storage, f.ID.String(), f.MimeType, rc)
rc.Close()
if err != nil {
failed++
continue
}
// Auch setzen, wenn es schon stand: Dateien, bei denen die Erzeugung
// beim Hochladen fehlschlug, bekommen so nachträglich eines.
if err := h.files.UpdateThumbnail(r.Context(), f.ID, true); err != nil {
failed++
continue
}
rebuilt++
}
h.logAdmin(r, audit.ActionGarbageCollect, "storage", "", "",
fmt.Sprintf("thumbnails rebuilt: %d of %d images, %d failed",
rebuilt, len(list), failed))
response.JSON(w, http.StatusOK, map[string]any{
"images": len(list),
"rebuilt": rebuilt,
"failed": failed,
})
}