gosora/common/thumbnailer.go
Azareal bf851bd9fc We now use Go 1.11 modules. This should help with build times, deployment and development, although it does mean that the minimum requirement for Gosora has been bumped up from Go 1.10 to Go 1.11
Added support for dyntmpl to the template system.
The Account Dashboard now sort of uses dyntmpl, more work needed here.
Renamed the pre_render_view_topic hook to pre_render_topic.
Added the GetCurrentLangPack() function.
Added the alerts_no_new_alerts phrase.
Added the account_level_list phrase.

Refactored the route rename logic in the patcher to cut down on the amount of boilerplate.
Added more route renames to the patcher. You will need to run the patcher / updater in this commit.
2018-10-27 13:40:36 +10:00

146 lines
3.7 KiB
Go

package common
import (
"image"
"image/gif"
"image/jpeg"
_ "image/png"
"os"
"strconv"
"github.com/Azareal/Gosora/query_gen"
"github.com/pkg/errors"
)
func ThumbTask(thumbChan chan bool) {
for {
// Put this goroutine to sleep until we have work to do
<-thumbChan
// TODO: Use a real queue
acc := qgen.NewAcc()
err := acc.Select("users_avatar_queue").Columns("uid").Limit("0,5").EachInt(func(uid int) error {
// TODO: Do a bulk user fetch instead?
user, err := Users.Get(uid)
if err != nil {
return errors.WithStack(err)
}
// Has the avatar been removed or already been processed by the thumbnailer?
if len(user.RawAvatar) < 2 || user.RawAvatar[1] == '.' {
_, _ = acc.Delete("users_avatar_queue").Where("uid = ?").Run(uid)
return nil
}
// This means it's an external image, they aren't currently implemented, but this is here for when they are
if user.RawAvatar[0] != '.' {
return nil
}
/*if user.RawAvatar == ".gif" {
return nil
}*/
if user.RawAvatar != ".png" && user.RawAvatar != ".jpg" && user.RawAvatar != ".jpeg" && user.RawAvatar != ".gif" {
return nil
}
err = Thumbnailer.Resize(user.RawAvatar[1:], "./uploads/avatar_"+strconv.Itoa(user.ID)+user.RawAvatar, "./uploads/avatar_"+strconv.Itoa(user.ID)+"_tmp"+user.RawAvatar, "./uploads/avatar_"+strconv.Itoa(user.ID)+"_w48"+user.RawAvatar, 48)
if err != nil {
return errors.WithStack(err)
}
err = user.ChangeAvatar("." + user.RawAvatar)
if err != nil {
return errors.WithStack(err)
}
_, err = acc.Delete("users_avatar_queue").Where("uid = ?").Run(uid)
return errors.WithStack(err)
})
if err != nil {
LogError(err)
}
if err = acc.FirstError(); err != nil {
LogError(err)
}
}
}
var Thumbnailer ThumbnailerInt
type ThumbnailerInt interface {
Resize(format string, inPath string, tmpPath string, outPath string, width int) error
}
type RezThumbnailer struct {
}
func (thumb *RezThumbnailer) Resize(format string, inPath string, tmpPath string, outPath string, width int) error {
// TODO: Sniff the aspect ratio of the image and calculate the dest height accordingly, bug make sure it isn't excessively high
return nil
}
func (thumb *RezThumbnailer) resize(format string, inPath string, outPath string, width int, height int) error {
return nil
}
// ! Note: CaireThumbnailer can't handle gifs, so we'll have to either cap their sizes or have another resizer deal with them
type CaireThumbnailer struct {
}
func NewCaireThumbnailer() *CaireThumbnailer {
return &CaireThumbnailer{}
}
func precodeImage(format string, inPath string, tmpPath string) error {
imageFile, err := os.Open(inPath)
if err != nil {
return err
}
defer imageFile.Close()
img, _, err := image.Decode(imageFile)
if err != nil {
return err
}
outFile, err := os.Create(tmpPath)
if err != nil {
return err
}
defer outFile.Close()
// TODO: Make sure animated gifs work after being encoded
if format == "gif" {
return gif.Encode(outFile, img, nil)
}
return jpeg.Encode(outFile, img, nil)
}
func (thumb *CaireThumbnailer) Resize(format string, inPath string, tmpPath string, outPath string, width int) error {
err := precodeImage(format, inPath, tmpPath)
if err != nil {
return err
}
return nil
// TODO: Caire doesn't work. Try something else. Or get them to fix the index out of range. We get enough wins from re-encoding as jpeg anyway
/*imageFile, err := os.Open(tmpPath)
if err != nil {
return err
}
defer imageFile.Close()
outFile, err := os.Create(outPath)
if err != nil {
return err
}
defer outFile.Close()
p := &caire.Processor{NewWidth: width, Scale: true}
return p.Process(imageFile, outFile)*/
}
/*
type LilliputThumbnailer struct {
}
*/