Files
ai/models/Image.go
2023-07-06 08:38:16 +08:00

108 lines
4.4 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 (
"bytes"
"database/sql/driver"
"encoding/json"
"fmt"
"image"
"io/ioutil"
"main/configs"
"time"
"github.com/chai2010/webp"
"github.com/disintegration/imaging"
giftowebp "github.com/sizeofint/gif-to-webp"
)
type Image struct {
ID int `json:"id" gorm:"primary_key"` // ID
Name string `json:"name"` // 名称
Hash string `json:"hash"` // 哈希值
Path string `json:"path"` // 路径
Type string `json:"type"` // 类型
Size int `json:"size"` // 大小
Width int `json:"width"` // 宽度
Height int `json:"height"` // 高度
Format string `json:"format"` // 格式
Prompt string `json:"prompt"` // 提示词
NegativePrompt string `json:"negative_prompt"` // 负向提示
Steps int `json:"steps"` // 迭代步数 (Steps 1~150)
CfgScale int `json:"cfg_scale"` // 引导比例(minimum: 1; maximum: 20)
SamplerName string `json:"sampler_name"` // 采样器名称
Seed int `json:"seed"` // 随机种子(minimum: 0; maximum: 2147483647)
FromImage int `json:"from_image"` // 来源图片(如果是从图片生成的, 则记录来源图片的ID)
Task string `json:"task"` // 任务编号(uuid)
Status string `json:"status"` // 任务状态(queued|running|finished|failed)
Progress int `json:"progress"` // 任务进度(0-100)
Public bool `json:"public"` // 是否公开
UserID int `json:"user_id"` // 用户ID
ModelID int `json:"model_id"` // 模型ID
Preview string `json:"preview" gorm:"-"` // 实时预览 base64
CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"`
UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"`
}
// 将图片输出为指定尺寸的 webp 格式(默认使用 Lanczos 缩放算法)
func (img *Image) ToWebP(width int, height int, fit string) ([]byte, error) {
// 從絕對路徑讀原始圖片
data, err := ioutil.ReadFile(fmt.Sprintf("data/images/%d", img.ID))
if err != nil {
return nil, err
}
// 將原始圖片轉換為 Image
imageData, format, err := image.Decode(bytes.NewReader(data))
if err != nil {
return nil, err
}
// 如果原图是GIF格式的动态图片直接不作尺寸处理直接转换为webp格式
if 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(data)
}
// 如果指定了宽高却没有指定fit, 则默认fit为cover
if width != 0 && height != 0 && fit == "" {
fit = "cover"
}
// 如果未指定宽高和fit, 则不缩放图片直接返回webp
if width == 0 && height == 0 && fit == "" {
return webp.EncodeRGBA(imageData, 100)
}
switch fit {
case "cover":
return webp.EncodeRGBA(imaging.Fill(imageData, width, height, imaging.Center, imaging.Lanczos), 100)
case "contain":
return webp.EncodeRGBA(imaging.Fit(imageData, width, height, imaging.Lanczos), 100)
case "fill":
return webp.EncodeRGBA(imaging.Fill(imageData, width, height, imaging.Center, imaging.Lanczos), 100)
case "inside":
return webp.EncodeRGBA(imaging.Fit(imageData, width, height, imaging.Lanczos), 100)
case "outside":
return webp.EncodeRGBA(imaging.Fill(imageData, width, height, imaging.Center, imaging.Lanczos), 100)
case "scale-down":
return webp.EncodeRGBA(imaging.Fit(imageData, width, height, imaging.Lanczos), 100)
default:
return webp.EncodeRGBA(imaging.Resize(imageData, width, height, imaging.Lanczos), 100)
}
}
func init() {
configs.ORMDB().AutoMigrate(&Image{})
}
type ImageList []string
func (list *ImageList) Scan(value interface{}) error {
return json.Unmarshal(value.([]byte), list)
}
func (list ImageList) Value() (driver.Value, error) {
return json.Marshal(list)
}