Files
webp/models/image.go
2024-12-31 06:57:53 +08:00

142 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package models
import (
"fmt"
"image"
"io"
"log"
"net/http"
"os"
"path/filepath"
"regexp"
"github.com/chai2010/webp"
"github.com/disintegration/imaging"
giftowebp "github.com/sizeofint/gif-to-webp"
)
// Image is a struct that contains the information of an image
type Image struct {
image image.Image
format string
data []byte
}
// 初始化图片
func (img *Image) Init(content string) error {
if len(regexp.MustCompile(`image.gameuiux.cn`).FindStringSubmatch(content)) > 0 {
key := regexp.MustCompile(`^https?://image.gameuiux.cn/`).ReplaceAllString(content, "")
filePath := filepath.Join("data/oss", key)
// 先检查本地是否存在原图, 没有则从OSS下载
if _, err := os.Stat(filePath); err != nil {
if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
log.Fatalf("创建目录失败: %v\n", err)
}
bucket := GetBucket("gameui-image2")
fmt.Println("从 OSS 下载:", key, filePath)
if err := bucket.GetObjectToFile(key, filePath); err != nil {
log.Println("下载文件失败:", err)
return err
}
}
// 从本地打开文件
body, err := os.Open(filePath)
if err != nil {
log.Println("打开本地图片失败:", err)
return err
}
defer body.Close()
// 判断图片格式是否为 gif 或 GIF
if len(regexp.MustCompile(`\.gif$`).FindStringSubmatch(key)) > 0 {
img.format = "gif"
img.data, err = io.ReadAll(body)
if err != nil {
log.Println("读取图片失败", err)
return err
}
return nil
}
// 将文件解码为 image.Image
img.image, img.format, err = image.Decode(body)
if err != nil {
log.Println("解码图像失败", err)
return err
}
return nil
} else {
var resp *http.Response
log.Println("直接从网络下载图片:", content)
resp, err := http.Get(content)
if err != nil {
log.Println("下载图片失败", err)
return err
}
defer resp.Body.Close()
// 判断图片格式是否为 gif 或 GIF
if len(regexp.MustCompile(`\.gif$`).FindStringSubmatch(content)) > 0 {
img.format = "gif"
img.data, err = io.ReadAll(resp.Body)
if err != nil {
log.Println("读取图片失败", err)
return err
}
println("数据长度:", len(img.data))
return nil
}
// 将文件解码为 image.Image
img.image, img.format, err = image.Decode(resp.Body)
if err != nil {
log.Println("解码图像失败", err)
return nil
}
return nil
}
}
// 将图片输出为指定尺寸的 webp 格式(默认使用 Lanczos 缩放算法)
func (img *Image) ToWebP(width int, height int, fit string) ([]byte, error) {
// 如果原图是GIF格式的动态图片直接不作尺寸处理直接转换为webp格式
if img.format == "gif" {
converter := giftowebp.NewConverter()
converter.LoopCompatibility = true // 是否兼容循环动画
converter.WebPConfig.SetLossless(1) // 0 有损压缩 1无损压缩
converter.WebPConfig.SetMethod(6) // 压缩速度 0-6 0最快 6质量最好
converter.WebPConfig.SetQuality(100) // 压缩质量 0-100
converter.WebPAnimEncoderOptions.SetKmin(9)
converter.WebPAnimEncoderOptions.SetKmax(17)
return converter.Convert(img.data)
}
// 如果指定了宽高却没有指定fit, 则默认fit为cover
if width != 0 && height != 0 && fit == "" {
fit = "cover"
}
// 如果未指定宽高和fit, 则不缩放图片直接返回webp
if width == 0 && height == 0 && fit == "" {
return webp.EncodeRGBA(img.image, 100)
}
switch fit {
case "cover":
return webp.EncodeRGBA(imaging.Fill(img.image, width, height, imaging.Center, imaging.Lanczos), 100)
case "contain":
return webp.EncodeRGBA(imaging.Fit(img.image, width, height, imaging.Lanczos), 100)
case "fill":
return webp.EncodeRGBA(imaging.Fill(img.image, width, height, imaging.Center, imaging.Lanczos), 100)
case "inside":
return webp.EncodeRGBA(imaging.Fit(img.image, width, height, imaging.Lanczos), 100)
case "outside":
return webp.EncodeRGBA(imaging.Fill(img.image, width, height, imaging.Center, imaging.Lanczos), 100)
case "scale-down":
return webp.EncodeRGBA(imaging.Fit(img.image, width, height, imaging.Lanczos), 100)
default:
return webp.EncodeRGBA(imaging.Resize(img.image, width, height, imaging.Lanczos), 100)
}
}