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
@@ -30,6 +30,7 @@ import (
|
||||
_ "golang.org/x/image/webp"
|
||||
|
||||
"aether/internal/auth"
|
||||
"aether/internal/imageutil"
|
||||
"aether/internal/storage"
|
||||
"aether/pkg/response"
|
||||
)
|
||||
@@ -45,10 +46,22 @@ const MaxBytes = 4 << 20
|
||||
|
||||
// Process liest ein Bild und gibt ein quadratisches PNG zurück.
|
||||
func Process(r io.Reader) ([]byte, error) {
|
||||
src, _, err := image.Decode(io.LimitReader(r, MaxBytes))
|
||||
// Dasselbe wie beim Vorschaubild: Der Anfang trägt die EXIF-Drehung, und
|
||||
// ein Profilbild kommt oft direkt aus einer Telefonkamera – also quer
|
||||
// gespeichert mit einer Notiz daneben.
|
||||
head := make([]byte, imageutil.HeadBytes)
|
||||
n, herr := io.ReadFull(io.LimitReader(r, MaxBytes), head)
|
||||
if herr != nil && herr != io.EOF && herr != io.ErrUnexpectedEOF {
|
||||
return nil, fmt.Errorf("bild nicht lesbar: %w", herr)
|
||||
}
|
||||
head = head[:n]
|
||||
|
||||
src, _, err := image.Decode(io.MultiReader(
|
||||
bytes.NewReader(head), io.LimitReader(r, MaxBytes-int64(n))))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("bild nicht lesbar: %w", err)
|
||||
}
|
||||
src = imageutil.Apply(src, imageutil.Orientation(head))
|
||||
b := src.Bounds()
|
||||
if b.Dx() <= 0 || b.Dy() <= 0 {
|
||||
return nil, fmt.Errorf("bild ist leer")
|
||||
|
||||
Reference in new issue
Block a user