From 89b672be8d8d38473c71fb3654f7fd29f1d7dda7 Mon Sep 17 00:00:00 2001 From: lixiangwuxian Date: Tue, 13 May 2025 23:41:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20ResizeImageByM?= =?UTF-8?q?axHeight2Image=20=E5=87=BD=E6=95=B0=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=84=E7=90=86=20GIF=20=E6=A0=BC=E5=BC=8F=E5=B9=B6=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=A4=9A=E4=B8=AA=E5=9B=BE=E5=83=8F=E5=8F=8A=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E4=BF=A1=E6=81=AF=EF=BC=8C=E6=94=AF=E6=8C=81=E8=BF=94?= =?UTF-8?q?=E5=9B=9EGIF=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- go.sum | 4 ++-- service/beatleader/model.go | 12 ++++++++--- service/scoresaber/model.go | 12 ++++++++--- util/picture.go | 43 ++++++++++++++++++++++++++++++------- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index cce478e..a7c1f69 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.0 toolchain go1.23.3 require ( - git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513115110-2cf9da089612 + git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513153039-c482f721b1ae github.com/bytedance/mockey v1.2.14 github.com/chromedp/cdproto v0.0.0-20241003230502-a4a8f7c660df github.com/chromedp/chromedp v0.10.0 diff --git a/go.sum b/go.sum index 5976a66..8b18f54 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250510064143-ba9126d54ac6 h1:v1cEHG5kGJN5Tu+3icJ6gfrcwrXJRZQMCu8eb4goEKQ= -git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250510064143-ba9126d54ac6/go.mod h1:luas4p32Wtsywcz+8HsxIB3gf65FDDBa+3XYhm0S2b8= git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513115110-2cf9da089612 h1:ew7YcheoePX1rQ9XQxqvfWLkAdGyCVD3h8LRjO5i/dQ= git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513115110-2cf9da089612/go.mod h1:luas4p32Wtsywcz+8HsxIB3gf65FDDBa+3XYhm0S2b8= +git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513153039-c482f721b1ae h1:uFuLriBS+ciaUanGbe3FV8acxlwVvV1CA+zkn7292i0= +git.lxtend.com/lixiangwuxian/imagedd v0.0.0-20250513153039-c482f721b1ae/go.mod h1:luas4p32Wtsywcz+8HsxIB3gf65FDDBa+3XYhm0S2b8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= diff --git a/service/beatleader/model.go b/service/beatleader/model.go index 10763ac..5ea4bad 100644 --- a/service/beatleader/model.go +++ b/service/beatleader/model.go @@ -571,13 +571,14 @@ func (p PlayerDataLite) LastDiffToImage(lastQueryData PlayerDataLite) string { log.Default().Printf("渲染文字失败,err:%v", err) } - avatar, err := util.ResizeImageByMaxHeight2Image(filePath, uint(textImg.Bounds().Dy())) + avatar, delay, err := util.ResizeImageByMaxHeight2Image(filePath, uint(textImg.Bounds().Dy())) if err != nil { log.Default().Printf("缩放头像失败,url:%s,err:%v", p.Avatar, err) } avatarSpirit := sprite.Sprite{ Name: "avatar", - Images: []image.Image{avatar}, + Images: avatar, + Delay: delay, Index: 1, } if avatar == nil { @@ -606,7 +607,12 @@ func (p PlayerDataLite) LastDiffToImage(lastQueryData PlayerDataLite) string { Position: image.Point{X: minX - 5, Y: minY - 5}, } baseboard.AddSprite(&backgroundSpirit) - + if len(avatarSpirit.Images) > 1 { + if err := baseboard.SaveToGIF(util.GenTempFilePath("cbl.gif")); err != nil { + log.Default().Printf("保存图片失败,err:%v", err) + } + return util.GenTempFilePath("cbl.gif") + } if err := baseboard.SaveToPng(util.GenTempFilePath("cbl.png")); err != nil { log.Default().Printf("保存图片失败,err:%v", err) } diff --git a/service/scoresaber/model.go b/service/scoresaber/model.go index 9b2debc..2a3951b 100644 --- a/service/scoresaber/model.go +++ b/service/scoresaber/model.go @@ -390,13 +390,14 @@ func (p PlayerDataLite) LastDiffToImage(lastQueryData PlayerDataLite) string { log.Default().Printf("渲染文字失败,err:%v", err) } - avatar, err := util.ResizeImageByMaxHeight2Image(filePath, uint(textImg.Bounds().Dy())) + avatar, delay, err := util.ResizeImageByMaxHeight2Image(filePath, uint(textImg.Bounds().Dy())) if err != nil { log.Default().Printf("缩放头像失败,url:%s,err:%v", p.ProfilePicture, err) } avatarSpirit := sprite.Sprite{ Name: "avatar", - Images: []image.Image{avatar}, + Images: avatar, + Delay: delay, Index: 1, } if avatar == nil { @@ -425,7 +426,12 @@ func (p PlayerDataLite) LastDiffToImage(lastQueryData PlayerDataLite) string { Position: image.Point{X: minX - 5, Y: minY - 5}, } baseboard.AddSprite(&backgroundSpirit) - + if len(avatarSpirit.Images) > 1 { + if err := baseboard.SaveToGIF(util.GenTempFilePath("css.gif")); err != nil { + log.Default().Printf("保存图片失败,err:%v", err) + } + return util.GenTempFilePath("css.gif") + } if err := baseboard.SaveToPng(util.GenTempFilePath("css.png")); err != nil { log.Default().Printf("保存图片失败,err:%v", err) } diff --git a/util/picture.go b/util/picture.go index e362ba0..df8acd7 100644 --- a/util/picture.go +++ b/util/picture.go @@ -3,6 +3,7 @@ package util import ( "errors" "image" + "image/gif" "image/jpeg" "image/png" "os" @@ -123,12 +124,16 @@ func ResizeImageByMaxHeight2File(imagePath string, maxHeight uint) (outputPath s var img image.Image var decodeErr error + var gifImg *gif.GIF + ext := strings.ToLower(filepath.Ext(imagePath)) switch ext { case ".jpg", ".jpeg": img, decodeErr = jpeg.Decode(file) case ".png": img, decodeErr = png.Decode(file) + case ".gif": + gifImg, decodeErr = gif.DecodeAll(file) default: return "", errors.New("unsupported image format") } @@ -139,7 +144,15 @@ func ResizeImageByMaxHeight2File(imagePath string, maxHeight uint) (outputPath s // 计算缩放后的尺寸,保持宽高比 // 传入0作为宽度,resize包会自动计算等比例的宽度 - resized := resize.Resize(0, maxHeight, img, resize.Lanczos3) + var resized image.Image + if gifImg == nil { + resized = resize.Resize(0, maxHeight, img, resize.Lanczos3) + } else { + for i, frame := range gifImg.Image { + resized = resize.Resize(0, maxHeight, frame, resize.Lanczos3) + gifImg.Image[i] = resized.(*image.Paletted) + } + } // 创建输出文件 outputPath = strings.TrimSuffix(imagePath, ext) + "_resized" + ext @@ -155,16 +168,18 @@ func ResizeImageByMaxHeight2File(imagePath string, maxHeight uint) (outputPath s return outputPath, jpeg.Encode(out, resized, nil) case ".png": return outputPath, png.Encode(out, resized) + case ".gif": + return outputPath, gif.EncodeAll(out, gifImg) default: return "", errors.New("unsupported image format") } } -func ResizeImageByMaxHeight2Image(imagePath string, maxHeight uint) (output image.Image, err error) { +func ResizeImageByMaxHeight2Image(imagePath string, maxHeight uint) (output []image.Image, delay []int, err error) { // 打开源图片文件 file, err := os.Open(imagePath) if err != nil { - return nil, err + return nil, nil, err } defer file.Close() @@ -172,25 +187,37 @@ func ResizeImageByMaxHeight2Image(imagePath string, maxHeight uint) (output imag var img image.Image var decodeErr error + var gifImg *gif.GIF + ext := strings.ToLower(filepath.Ext(imagePath)) switch ext { case ".jpg", ".jpeg": img, decodeErr = jpeg.Decode(file) case ".png": img, decodeErr = png.Decode(file) + case ".gif": + gifImg, decodeErr = gif.DecodeAll(file) default: - return nil, errors.New("unsupported image format") + return nil, nil, errors.New("unsupported image format") } if decodeErr != nil { - return nil, decodeErr + return nil, nil, decodeErr } // 计算缩放后的尺寸,保持宽高比 // 传入0作为宽度,resize包会自动计算等比例的宽度 - resized := resize.Resize(0, maxHeight, img, resize.Lanczos3) - - return resized, nil + var resized []image.Image + if gifImg == nil { + resized = []image.Image{resize.Resize(0, maxHeight, img, resize.Lanczos3)} + } else { + for _, frame := range gifImg.Image { + img := resize.Resize(0, maxHeight, frame, resize.Lanczos3) + resized = append(resized, img) + } + delay = gifImg.Delay + } + return resized, delay, nil } func GetResizedIamgePathByOrgPath(orgPath string) string {