mirror of
https://github.com/Cernobor/oko-server.git
synced 2025-02-24 08:27:17 +00:00
All checks were successful
continuous-integration/drone/push Build is passing
* X-User-ID header is processed to get user ID. * Time of last request for a user is saved into DB. * Time of last upload and download is stored for a user. * Added DB migration to add columns into users table to store the times and app version. * Backward fix of datatype of the deadline column in features table. * Switched from crawshaw.io/sqlite to zombiezen.com/go/sqlite. * Refactored DB handling. * Used migration routine from zombiezen in favour of manual one. * Runtime DB reinit simply deletes the db file and initializes the db anew. Fix #6
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
package server
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"image"
|
|
"image/jpeg"
|
|
"io"
|
|
"math"
|
|
|
|
"golang.org/x/image/draw"
|
|
|
|
"cernobor.cz/oko-server/models"
|
|
)
|
|
|
|
func ptr[T any](x T) *T {
|
|
return &x
|
|
}
|
|
|
|
func Map[T any, U any](f func(T) U, x []T) []U {
|
|
res := make([]U, len(x))
|
|
for i, e := range x {
|
|
res[i] = f(e)
|
|
}
|
|
return res
|
|
}
|
|
|
|
var contentTypes map[string]struct{} = map[string]struct{}{"image/jpeg": {}, "image/png": {}}
|
|
|
|
func checkImageContentType(contentType string) bool {
|
|
_, ok := contentTypes[contentType]
|
|
return ok
|
|
}
|
|
|
|
func isUniqueFeatureID(features []models.Feature) bool {
|
|
ids := make(map[models.FeatureID]struct{}, len(features))
|
|
for _, f := range features {
|
|
if _, pres := ids[f.ID]; pres {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func resizePhoto(maxX, maxY, quality int, data io.Reader) ([]byte, error) {
|
|
src, _, err := image.Decode(data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode image: %w", err)
|
|
}
|
|
|
|
if maxX == 0 && maxY == 0 {
|
|
output := &bytes.Buffer{}
|
|
jpeg.Encode(output, src, &jpeg.Options{
|
|
Quality: 90,
|
|
})
|
|
|
|
return output.Bytes(), nil
|
|
}
|
|
|
|
var dst draw.Image
|
|
srcX := src.Bounds().Max.X
|
|
srcY := src.Bounds().Max.Y
|
|
srcRatio := float64(srcX) / float64(srcY)
|
|
if maxX == 0 && srcY > maxY {
|
|
newX := int(math.Round(float64(maxY) * srcRatio))
|
|
newY := maxY
|
|
dst = image.NewRGBA(image.Rect(0, 0, newX, newY))
|
|
draw.CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
|
|
} else if maxY == 0 && srcX > maxX {
|
|
newX := maxX
|
|
newY := int(math.Round(float64(maxX) / srcRatio))
|
|
dst = image.NewRGBA(image.Rect(0, 0, newX, newY))
|
|
draw.CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
|
|
} else if srcX > maxX || srcY > maxY {
|
|
tgtRatio := float64(maxX) / float64(maxY)
|
|
var newX, newY int
|
|
if srcRatio > tgtRatio {
|
|
newX = maxX
|
|
newY = int(math.Round(float64(maxX) / srcRatio))
|
|
} else {
|
|
newX = int(math.Round(float64(maxY) * srcRatio))
|
|
newY = maxY
|
|
}
|
|
dst = image.NewRGBA(image.Rect(0, 0, newX, newY))
|
|
draw.CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
|
|
} else {
|
|
dst = image.NewRGBA(image.Rect(0, 0, srcX, srcY))
|
|
draw.Copy(dst, image.Point{X: 0, Y: 0}, src, src.Bounds(), draw.Over, nil)
|
|
}
|
|
|
|
output := &bytes.Buffer{}
|
|
jpeg.Encode(output, dst, &jpeg.Options{
|
|
Quality: quality,
|
|
})
|
|
|
|
return output.Bytes(), nil
|
|
}
|