管理端按用户查询开启通讯录/相册/媒体拉取;服务端写入路径自动压图;新增 /v1/sign 与 /v1/energy。 Co-authored-by: Cursor <cursoragent@cursor.com>
143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
package media
|
|
|
|
import (
|
|
"bytes"
|
|
"image"
|
|
"image/color"
|
|
"image/jpeg"
|
|
"testing"
|
|
|
|
pkgmedia "spark-server/internal/pkg/media"
|
|
)
|
|
|
|
func TestCompressImageDownscales(t *testing.T) {
|
|
img := image.NewRGBA(image.Rect(0, 0, 2000, 1000))
|
|
for y := 0; y < 1000; y++ {
|
|
for x := 0; x < 2000; x++ {
|
|
img.Set(x, y, color.RGBA{R: uint8(x % 255), G: uint8(y % 255), B: 40, A: 255})
|
|
}
|
|
}
|
|
src, err := EncodePNG(img)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
opt := &Options{Limits: pkgmedia.DefaultLimits(), JPEGQuality: 80}
|
|
res, err := CompressImage(src, opt)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pkgmedia.LongestEdge(res.Width, res.Height) > pkgmedia.DefaultImageMaxEdge {
|
|
t.Fatalf("edge %dx%d still over 1080", res.Width, res.Height)
|
|
}
|
|
if int64(len(res.Data)) > pkgmedia.DefaultImageMaxBytes {
|
|
t.Fatalf("size %d > %d", len(res.Data), pkgmedia.DefaultImageMaxBytes)
|
|
}
|
|
if res.MIME != "image/jpeg" {
|
|
t.Fatalf("mime %s", res.MIME)
|
|
}
|
|
small := image.NewRGBA(image.Rect(0, 0, 100, 80))
|
|
smallSrc, err := EncodePNG(small)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
def := &Options{Limits: pkgmedia.DefaultLimits()}
|
|
keep, err := CompressImage(smallSrc, def)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if keep.Width != 100 || keep.Height != 80 {
|
|
t.Fatalf("should keep small image dims, got %dx%d", keep.Width, keep.Height)
|
|
}
|
|
}
|
|
|
|
func TestCompressImageUnder150KiB(t *testing.T) {
|
|
src := mustOversizedJPEG(t, int(pkgmedia.DefaultImageMaxBytes)+1)
|
|
res, err := CompressImage(src, DefaultOptions())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if int64(len(res.Data)) > pkgmedia.DefaultImageMaxBytes {
|
|
t.Fatalf("after compress %d > %d", len(res.Data), pkgmedia.DefaultImageMaxBytes)
|
|
}
|
|
out, mime, err := EnsureUnderLimit(src, "image/jpeg", nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if int64(len(out)) > pkgmedia.DefaultImageMaxBytes {
|
|
t.Fatalf("EnsureUnderLimit %d", len(out))
|
|
}
|
|
if mime != "image/jpeg" {
|
|
t.Fatalf("mime %s", mime)
|
|
}
|
|
}
|
|
|
|
// mustOversizedJPEG grows a noisy JPEG until len >= minBytes (JPEG of smooth
|
|
// gradients can stay tiny; use per-pixel noise and bump resolution as needed).
|
|
func mustOversizedJPEG(t *testing.T, minBytes int) []byte {
|
|
t.Helper()
|
|
for side := 800; side <= 4800; side += 400 {
|
|
img := image.NewRGBA(image.Rect(0, 0, side, side*3/4))
|
|
w, h := img.Bounds().Dx(), img.Bounds().Dy()
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
n := uint32(x*374761393 + y*668265263 + side*97)
|
|
n ^= n << 13
|
|
n ^= n >> 17
|
|
n ^= n << 5
|
|
img.Set(x, y, color.RGBA{R: uint8(n), G: uint8(n >> 8), B: uint8(n >> 16), A: 255})
|
|
}
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := jpeg.Encode(&buf, img, &jpeg.Options{Quality: 100}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if buf.Len() >= minBytes {
|
|
return buf.Bytes()
|
|
}
|
|
}
|
|
t.Fatalf("could not synthesize JPEG >= %d bytes", minBytes)
|
|
return nil
|
|
}
|
|
|
|
func TestCompressAvatar(t *testing.T) {
|
|
img := image.NewRGBA(image.Rect(0, 0, 500, 500))
|
|
src, err := EncodePNG(img)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
res, err := CompressAvatar(src, &Options{Limits: pkgmedia.DefaultLimits()})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if pkgmedia.LongestEdge(res.Width, res.Height) > pkgmedia.DefaultAvatarMaxEdge {
|
|
t.Fatalf("avatar %dx%d", res.Width, res.Height)
|
|
}
|
|
if int64(len(res.Data)) > pkgmedia.DefaultAvatarMaxBytes {
|
|
t.Fatalf("avatar size %d", len(res.Data))
|
|
}
|
|
}
|
|
|
|
func TestPrepareBotImage(t *testing.T) {
|
|
img := image.NewRGBA(image.Rect(0, 0, 1600, 900))
|
|
src, err := EncodePNG(img)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a, err := PrepareBotImage(src, &Options{Limits: pkgmedia.DefaultLimits()})
|
|
if err != nil || a == nil || a.Size <= 0 {
|
|
t.Fatalf("%+v %v", a, err)
|
|
}
|
|
if a.Size > pkgmedia.DefaultImageMaxBytes {
|
|
t.Fatalf("bot image %d > 150KiB", a.Size)
|
|
}
|
|
}
|
|
|
|
func TestIsImageMIME(t *testing.T) {
|
|
if !IsImageMIME("image/jpeg") || !IsImageMIME("image/png; charset=binary") {
|
|
t.Fatal("want image")
|
|
}
|
|
if IsImageMIME("audio/mpeg") || IsImageMIME("video/mp4") {
|
|
t.Fatal("reject non-image")
|
|
}
|
|
}
|