88 lines
2.2 KiB
Go
88 lines
2.2 KiB
Go
|
|
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
|
||
|
|
}
|