Files

83 lines
1.7 KiB
Go
Raw Permalink Normal View History

package media
import (
"bytes"
"context"
"image"
_ "image/gif"
"image/jpeg"
_ "image/png"
"golang.org/x/image/draw"
"golang.org/x/image/webp"
)
const maxUploadSize = 25 << 20 // 25 MiB
// IsImage reports whether the content type is a decodable image format.
func IsImage(contentType string) bool {
switch contentType {
case "image/jpeg", "image/png", "image/gif", "image/webp":
return true
default:
return false
}
}
// Generate returns a JPEG thumbnail of at most maxDim on its larger side.
// It returns nil for non-images or when the source is already small enough.
func Generate(ctx context.Context, r *bytes.Reader, contentType string, maxDim int) ([]byte, error) {
if !IsImage(contentType) {
return nil, nil
}
if err := ctx.Err(); err != nil {
return nil, err
}
src, err := decodeImage(r, contentType)
if err != nil {
return nil, err
}
bounds := src.Bounds()
w, h := bounds.Dx(), bounds.Dy()
if w <= maxDim && h <= maxDim {
return nil, nil
}
scale := float64(maxDim) / float64(max(w, h))
nw, nh := int(float64(w)*scale), int(float64(h)*scale)
if nw < 1 {
nw = 1
}
if nh < 1 {
nh = 1
}
dst := image.NewRGBA(image.Rect(0, 0, nw, nh))
draw.BiLinear.Scale(dst, dst.Bounds(), src, bounds, draw.Over, nil)
if err := ctx.Err(); err != nil {
return nil, err
}
var buf bytes.Buffer
if err := jpeg.Encode(&buf, dst, &jpeg.Options{Quality: 80}); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func decodeImage(r *bytes.Reader, contentType string) (image.Image, error) {
if contentType == "image/webp" {
return webp.Decode(r)
}
img, _, err := image.Decode(r)
return img, err
}
func max(a, b int) int {
if a > b {
return a
}
return b
}