always convert original avatar to png to avoid recompression

peertube
Namekuji 2023-01-27 12:45:52 -05:00
rodzic 6adbf5de60
commit e28f2edb2e
2 zmienionych plików z 45 dodań i 34 usunięć

Wyświetl plik

@ -22,42 +22,18 @@ import (
"gopkg.in/gographics/imagick.v2/imagick"
)
func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte, room *Room) ([]byte, error) {
func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte, room *Room) ([]byte, []byte, error) {
if u == nil {
return nil, errors.New("nil user")
return nil, nil, errors.New("nil user")
}
mtype := mimetype.Detect(fnew)
if !mimetype.EqualsAny(mtype.String(), "image/png", "image/jpeg", "image/webp", "image/gif") {
return nil, errors.New("file type not supported")
return nil, nil, errors.New("file type not supported")
}
hash := sha256.Sum256(fnew)
var err error
// Check if user's original avatar exists
saved := u.GetOriginalAvatarPath(hash, mtype)
if _, err := os.Stat(saved); err != nil {
if err := os.MkdirAll(filepath.Dir(saved), 0775); err != nil {
return nil, err
}
// Write user's avatar if the original version doesn't exist
if err := os.WriteFile(saved, fnew, 0664); err != nil {
return nil, err
}
}
fname := filepath.Base(saved)
coll := mainDB.Collection(COLLECTION_USER)
if _, err = coll.UpdateOne(ctx,
bson.D{{Key: "audon_id", Value: u.AudonID}},
bson.D{
{Key: "$set", Value: bson.D{{Key: "avatar", Value: fname}}},
}); err != nil {
return nil, err
}
buf := bytes.NewReader(fnew)
var newImg image.Image
@ -71,9 +47,45 @@ func (u *AudonUser) GetIndicator(ctx context.Context, fnew []byte, room *Room) (
newImg, err = gif.Decode(buf)
}
if err != nil {
return nil, err
return nil, nil, err
}
return u.createGIF(newImg, room.IsHost(u) || room.IsCoHost(u))
// encode to png to avoid recompression
origBuf := new(bytes.Buffer)
if err := png.Encode(origBuf, newImg); err != nil {
return nil, nil, err
}
origPng := origBuf.Bytes()
hash := sha256.Sum256(origPng)
// Check if user's original avatar exists
filename := fmt.Sprintf("%x.png", hash)
saved := u.getAvatarImagePath(filename)
if _, err := os.Stat(saved); err != nil {
if err := os.MkdirAll(filepath.Dir(saved), 0775); err != nil {
return nil, nil, err
}
// Write user's avatar if the original version doesn't exist
if err := os.WriteFile(saved, origPng, 0664); err != nil {
return nil, nil, err
}
}
coll := mainDB.Collection(COLLECTION_USER)
if _, err = coll.UpdateOne(ctx,
bson.D{{Key: "audon_id", Value: u.AudonID}},
bson.D{
{Key: "$set", Value: bson.D{{Key: "avatar", Value: filename}}},
}); err != nil {
return nil, nil, err
}
indicator, err := u.createGIF(newImg, room.IsHost(u) || room.IsCoHost(u))
if err != nil {
return nil, nil, err
}
return indicator, origPng, nil
}
func (u *AudonUser) createGIF(avatar image.Image, blue bool) ([]byte, error) {
@ -129,7 +141,7 @@ func (u *AudonUser) createGIF(avatar image.Image, blue bool) ([]byte, error) {
return os.ReadFile(u.GetGIFAvatarPath())
}
func (u *AudonUser) GetOriginalAvatarPath(hash [sha256.Size]byte, mtype *mimetype.MIME) string {
func (u *AudonUser) getOriginalAvatarPath(hash [sha256.Size]byte, mtype *mimetype.MIME) string {
filename := fmt.Sprintf("%x%s", hash, mtype.Extension())
return u.getAvatarImagePath(filename)
}

Wyświetl plik

@ -12,7 +12,6 @@ import (
"os"
"time"
"github.com/gabriel-vasile/mimetype"
"github.com/jaevor/go-nanoid"
"github.com/jellydator/ttlcache/v3"
"github.com/labstack/echo/v4"
@ -380,7 +379,7 @@ func joinRoomHandler(c echo.Context) (err error) {
if user.AvatarFile != "" {
orig, err := os.ReadFile(user.getAvatarImagePath(user.AvatarFile))
if err == nil && orig != nil {
resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(orig), base64.StdEncoding.EncodeToString(orig))
resp.Original = fmt.Sprintf("data:image/png;base64,%s", base64.StdEncoding.EncodeToString(orig))
} else if orig == nil {
user.AvatarFile = ""
}
@ -424,12 +423,12 @@ func joinRoomHandler(c echo.Context) (err error) {
}
// Generate indicator GIF
indicator, err := user.GetIndicator(c.Request().Context(), fnew, room)
indicator, original, err := user.GetIndicator(c.Request().Context(), fnew, room)
if err != nil {
c.Logger().Error(err)
return echo.NewHTTPError(http.StatusInternalServerError)
}
resp.Original = fmt.Sprintf("data:%s;base64,%s", mimetype.Detect(fnew), base64.StdEncoding.EncodeToString(fnew))
resp.Original = fmt.Sprintf("data:image/png;base64,%s", base64.StdEncoding.EncodeToString(original))
resp.Indicator = fmt.Sprintf("data:image/gif;base64,%s", base64.StdEncoding.EncodeToString(indicator))
} else if err != nil {
c.Logger().Error(err)