Files
pmomusic/pmocover/webp.go

88 lines
2.2 KiB
Go
Raw Normal View History

2025-09-09 09:07:48 +02:00
package pmocover
import (
"bytes"
"image"
"image/draw"
"os"
"path/filepath"
"strconv"
"github.com/chai2010/webp"
xdraw "golang.org/x/image/draw"
)
// encodeWebP convertit une image.Image en WebP avec compression sans perte.
func encodeWebP(img image.Image) ([]byte, error) {
var buf bytes.Buffer
if err := webp.Encode(&buf, img, &webp.Options{Lossless: true}); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// ensureSquare génère une image carrée paddée transparente
func ensureSquare(img image.Image, size int) image.Image {
dst := image.NewRGBA(image.Rect(0, 0, size, size))
draw.Draw(dst, dst.Bounds(), &image.Uniform{C: image.Transparent}, image.Point{}, draw.Src)
srcBounds := img.Bounds()
srcW, srcH := srcBounds.Dx(), srcBounds.Dy()
var scale float64
if srcW > srcH {
scale = float64(size) / float64(srcW)
} else {
scale = float64(size) / float64(srcH)
}
newW, newH := int(float64(srcW)*scale), int(float64(srcH)*scale)
// redimensionnement avec Catmull-Rom
tmp := image.NewRGBA(image.Rect(0, 0, newW, newH))
xdraw.CatmullRom.Scale(tmp, tmp.Bounds(), img, srcBounds, xdraw.Over, nil)
// centrer l'image redimensionnée dans le carré
offset := image.Pt((size-newW)/2, (size-newH)/2)
draw.Draw(dst, tmp.Bounds().Add(offset), tmp, image.Point{}, draw.Over)
return dst
}
// generateVariant génère une version carrée en WebP pour une taille donnée.
// Si le fichier existe déjà, il est renvoyé directement.
func (c *Cache) generateVariant(pk string, size int) ([]byte, error) {
variantPath := filepath.Join(c.dir, pk+"."+strconv.Itoa(size)+".webp")
// si le variant existe déjà, le renvoyer
if data, err := os.ReadFile(variantPath); err == nil {
return data, nil
}
// lire l'image originale
origPath := filepath.Join(c.dir, pk+".orig.webp")
data, err := os.ReadFile(origPath)
if err != nil {
return nil, err
}
img, _, err := image.Decode(bytes.NewReader(data))
if err != nil {
return nil, err
}
// générer une image carrée
sq := ensureSquare(img, size)
// encoder en WebP
buf, err := encodeWebP(sq)
if err != nil {
return nil, err
}
// sauvegarder le variant
if err := os.WriteFile(variantPath, buf, 0o644); err != nil {
return nil, err
}
return buf, nil
}