feat: generate a BlurHash when uploading a new image

This commit is contained in:
kolaente 2021-12-12 21:42:35 +01:00 committed by Gitea
parent 362706b38d
commit f83b09af59
5 changed files with 47 additions and 17 deletions

View file

@ -640,7 +640,7 @@ func UpdateList(s *xorm.Session, list *List, auth web.Auth, updateListBackground
} }
if updateListBackground { if updateListBackground {
colsToUpdate = append(colsToUpdate, "background_file_id") colsToUpdate = append(colsToUpdate, "background_file_id", "background_blur_hash")
} }
wasFavorite, err := isFavorite(s, list.ID, auth, FavoriteKindList) wasFavorite, err := isFavorite(s, list.ID, auth, FavoriteKindList)
@ -801,14 +801,15 @@ func (l *List) Delete(s *xorm.Session, a web.Auth) (err error) {
} }
// SetListBackground sets a background file as list background in the db // SetListBackground sets a background file as list background in the db
func SetListBackground(s *xorm.Session, listID int64, background *files.File) (err error) { func SetListBackground(s *xorm.Session, listID int64, background *files.File, blurHash string) (err error) {
l := &List{ l := &List{
ID: listID, ID: listID,
BackgroundFileID: background.ID, BackgroundFileID: background.ID,
BackgroundBlurHash: blurHash,
} }
_, err = s. _, err = s.
Where("id = ?", l.ID). Where("id = ?", l.ID).
Cols("background_file_id"). Cols("background_file_id", "background_blur_hash").
Update(l) Update(l)
return return
} }

View file

@ -144,7 +144,7 @@ func (ld *ListDuplicate) Create(s *xorm.Session, doer web.Auth) (err error) {
} }
} }
if err := SetListBackground(s, ld.List.ID, file); err != nil { if err := SetListBackground(s, ld.List.ID, file, ld.List.BackgroundBlurHash); err != nil {
return err return err
} }

View file

@ -17,6 +17,9 @@
package handler package handler
import ( import (
"github.com/bbrks/go-blurhash"
"golang.org/x/image/draw"
"image"
"io" "io"
"net/http" "net/http"
"strconv" "strconv"
@ -134,6 +137,18 @@ func (bp *BackgroundProvider) SetBackground(c echo.Context) error {
return c.JSON(http.StatusOK, list) return c.JSON(http.StatusOK, list)
} }
func CreateBlurHash(srcf io.Reader) (hash string, err error) {
src, _, err := image.Decode(srcf)
if err != nil {
return "", err
}
dst := image.NewRGBA(image.Rect(0, 0, 32, 32))
draw.NearestNeighbor.Scale(dst, dst.Rect, src, src.Bounds(), draw.Over, nil)
return blurhash.Encode(4, 3, dst)
}
// UploadBackground uploads a background and passes the id of the uploaded file as an Image to the Set function of the BackgroundProvider. // UploadBackground uploads a background and passes the id of the uploaded file as an Image to the Set function of the BackgroundProvider.
func (bp *BackgroundProvider) UploadBackground(c echo.Context) error { func (bp *BackgroundProvider) UploadBackground(c echo.Context) error {
s := db.NewSession() s := db.NewSession()
@ -153,15 +168,15 @@ func (bp *BackgroundProvider) UploadBackground(c echo.Context) error {
_ = s.Rollback() _ = s.Rollback()
return err return err
} }
src, err := file.Open() srcf, err := file.Open()
if err != nil { if err != nil {
_ = s.Rollback() _ = s.Rollback()
return err return err
} }
defer src.Close() defer srcf.Close()
// Validate we're dealing with an image // Validate we're dealing with an image
mime, err := mimetype.DetectReader(src) mime, err := mimetype.DetectReader(srcf)
if err != nil { if err != nil {
_ = s.Rollback() _ = s.Rollback()
return handler.HandleHTTPError(err, c) return handler.HandleHTTPError(err, c)
@ -170,10 +185,10 @@ func (bp *BackgroundProvider) UploadBackground(c echo.Context) error {
_ = s.Rollback() _ = s.Rollback()
return c.JSON(http.StatusBadRequest, models.Message{Message: "Uploaded file is no image."}) return c.JSON(http.StatusBadRequest, models.Message{Message: "Uploaded file is no image."})
} }
_, _ = src.Seek(0, io.SeekStart) _, _ = srcf.Seek(0, io.SeekStart)
// Save the file // Save the file
f, err := files.CreateWithMime(src, file.Filename, uint64(file.Size), auth, mime.String()) f, err := files.CreateWithMime(srcf, file.Filename, uint64(file.Size), auth, mime.String())
if err != nil { if err != nil {
_ = s.Rollback() _ = s.Rollback()
if files.IsErrFileIsTooLarge(err) { if files.IsErrFileIsTooLarge(err) {
@ -183,9 +198,16 @@ func (bp *BackgroundProvider) UploadBackground(c echo.Context) error {
return handler.HandleHTTPError(err, c) return handler.HandleHTTPError(err, c)
} }
image := &background.Image{ID: strconv.FormatInt(f.ID, 10)} // Generate a blurHash
_, _ = srcf.Seek(0, io.SeekStart)
list.BackgroundBlurHash, err = CreateBlurHash(srcf)
if err != nil {
return handler.HandleHTTPError(err, c)
}
err = p.Set(s, image, list, auth) // Save it
img := &background.Image{ID: strconv.FormatInt(f.ID, 10)}
err = p.Set(s, img, list, auth)
if err != nil { if err != nil {
_ = s.Rollback() _ = s.Rollback()
return handler.HandleHTTPError(err, c) return handler.HandleHTTPError(err, c)
@ -300,6 +322,7 @@ func RemoveListBackground(c echo.Context) error {
list.BackgroundFileID = 0 list.BackgroundFileID = 0
list.BackgroundInformation = nil list.BackgroundInformation = nil
list.BackgroundBlurHash = ""
err = models.UpdateList(s, list, auth, true) err = models.UpdateList(s, list, auth, true)
if err != nil { if err != nil {
return err return err

View file

@ -52,7 +52,7 @@ func (p *Provider) Search(s *xorm.Session, search string, page int64) (result []
// @Failure 404 {object} models.Message "The list does not exist." // @Failure 404 {object} models.Message "The list does not exist."
// @Failure 500 {object} models.Message "Internal error" // @Failure 500 {object} models.Message "Internal error"
// @Router /lists/{id}/backgrounds/upload [put] // @Router /lists/{id}/backgrounds/upload [put]
func (p *Provider) Set(s *xorm.Session, image *background.Image, list *models.List, auth web.Auth) (err error) { func (p *Provider) Set(s *xorm.Session, img *background.Image, list *models.List, auth web.Auth) (err error) {
// Remove the old background if one exists // Remove the old background if one exists
if list.BackgroundFileID != 0 { if list.BackgroundFileID != 0 {
file := files.File{ID: list.BackgroundFileID} file := files.File{ID: list.BackgroundFileID}
@ -62,12 +62,12 @@ func (p *Provider) Set(s *xorm.Session, image *background.Image, list *models.Li
} }
file := &files.File{} file := &files.File{}
file.ID, err = strconv.ParseInt(image.ID, 10, 64) file.ID, err = strconv.ParseInt(img.ID, 10, 64)
if err != nil { if err != nil {
return return
} }
list.BackgroundInformation = &models.ListBackgroundType{Type: models.ListBackgroundUpload} list.BackgroundInformation = &models.ListBackgroundType{Type: models.ListBackgroundUpload}
return models.SetListBackground(s, list.ID, file) return models.SetListBackground(s, list.ID, file, list.BackgroundBlurHash)
} }

View file

@ -18,6 +18,7 @@ package migration
import ( import (
"bytes" "bytes"
"code.vikunja.io/api/pkg/modules/background/handler"
"io/ioutil" "io/ioutil"
"xorm.io/xorm" "xorm.io/xorm"
@ -115,7 +116,12 @@ func insertFromStructure(s *xorm.Session, str []*models.NamespaceWithListsAndTas
return err return err
} }
err = models.SetListBackground(s, l.ID, file) hash, err := handler.CreateBlurHash(backgroundFile)
if err != nil {
return err
}
err = models.SetListBackground(s, l.ID, file, hash)
if err != nil { if err != nil {
return err return err
} }