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>
This commit is contained in:
1 parent
edefce3572
commit
4bd9a6ca56
10 files changed
+514
-2
No files matched your search
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"golang.org/x/image/draw"
|
||||
|
||||
"aether/internal/imageutil"
|
||||
"aether/internal/storage"
|
||||
)
|
||||
|
||||
@@ -44,11 +45,28 @@ func Generate(ctx context.Context, st storage.Storage, fileID, mimeType string,
|
||||
return fmt.Errorf("unsupported MIME type: %s", mimeType)
|
||||
}
|
||||
|
||||
img, _, err := image.Decode(src)
|
||||
// Den Anfang zwischenspeichern: Dort steht die EXIF-Drehung, und danach
|
||||
// muss derselbe Strom noch dekodiert werden. Nur der Anfang, nicht die
|
||||
// ganze Datei – ein 40-MB-Foto soll nicht zweimal im Speicher liegen.
|
||||
head := make([]byte, imageutil.HeadBytes)
|
||||
n, err := io.ReadFull(src, head)
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return fmt.Errorf("read image head: %w", err)
|
||||
}
|
||||
head = head[:n]
|
||||
orientation := imageutil.Orientation(head)
|
||||
|
||||
img, _, err := image.Decode(io.MultiReader(bytes.NewReader(head), src))
|
||||
if err != nil {
|
||||
return fmt.Errorf("decode image: %w", err)
|
||||
}
|
||||
|
||||
// Vor dem Verkleinern drehen. Andersherum stimmte das Seitenverhältnis
|
||||
// nicht: Ein hochkantes Foto würde als 256×128 eingepasst und danach
|
||||
// gedreht – aus dem Bild wären 128×256 geworden, aber mit dem Zuschnitt
|
||||
// eines Querformats.
|
||||
img = imageutil.Apply(img, orientation)
|
||||
|
||||
thumb := resize(img, maxWidth, maxHeight)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
Reference in new issue
Block a user