🍱 🎨 ️ 运势 不解压 不传 base64

This commit is contained in:
fumiama 2022-01-13 16:43:50 +08:00
parent bc989f2fb0
commit f05f09d741
2 changed files with 103 additions and 158 deletions

2
data

@ -1 +1 @@
Subproject commit 1349bd0d4a64daa5d5d76659a787a8594358b55b
Subproject commit 64113f69a74952a35f5c7432a2c0569188bb038c

View File

@ -3,12 +3,11 @@ package fortune
import (
"archive/zip"
"bytes"
"encoding/base64"
"crypto/md5"
"encoding/hex"
"encoding/json"
"image/jpeg"
"image"
"io"
"io/ioutil"
"math/rand"
"os"
"strconv"
@ -24,13 +23,19 @@ import (
control "github.com/FloatTech/zbputils/control"
"github.com/FloatTech/zbputils/file"
"github.com/FloatTech/zbputils/math"
"github.com/FloatTech/zbputils/process"
"github.com/FloatTech/zbputils/txt2img"
)
var (
// 底图缓存位置
base = "data/fortune/"
// 素材下载网站
site = "https://pan.dihe.moe/fortune/"
images = "data/Fortune/"
// 基础文件位置
omikujson = "data/Fortune/text.json"
// 字体文件位置
font = "data/Font/sakura.ttf"
// 生成图缓存位置
cache = images + "cache/"
// 底图类型列表:车万 DC4 爱因斯坦 星空列车 樱云之恋 富婆妹 李清歌
// 公主连结 原神 明日方舟 碧蓝航线 碧蓝幻想 战双 阴阳师
table = [...]string{"车万", "DC4", "爱因斯坦", "星空列车", "樱云之恋", "富婆妹", "李清歌", "公主连结", "原神", "明日方舟", "碧蓝航线", "碧蓝幻想", "战双", "阴阳师"}
@ -38,13 +43,32 @@ var (
index = make(map[string]uint8)
// 下载锁
dlmu sync.Mutex
// 签文
omikujis []map[string]string
)
func init() {
for i, s := range table {
index[s] = uint8(i)
}
err := os.MkdirAll(base, 0755)
err := os.MkdirAll(images, 0755)
if err != nil {
panic(err)
}
err = os.MkdirAll(cache, 0755)
if err != nil {
panic(err)
}
process.SleepAbout1sTo2s()
data, err := file.GetLazyData(omikujson, true, false)
if err != nil {
panic(err)
}
err = json.Unmarshal(data, &omikujis)
if err != nil {
panic(err)
}
_, err = file.GetLazyData(font, false, true)
if err != nil {
panic(err)
}
@ -81,38 +105,6 @@ func init() {
})
en.OnFullMatchGroup([]string{"运势", "抽签"}).SetBlock(true).SecondPriority().
Handle(func(ctx *zero.Ctx) {
// 检查签文文件是否存在
mikuji := base + "运势签文.json"
if file.IsNotExist(mikuji) {
dlmu.Lock()
if file.IsNotExist(mikuji) {
ctx.SendChain(message.Text("正在下载签文文件,请稍后..."))
err := file.DownloadTo(site+"运势签文.json", mikuji, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
dlmu.Unlock()
return
}
ctx.SendChain(message.Text("下载签文文件完毕"))
}
dlmu.Unlock()
}
// 检查字体文件是否存在
ttf := base + "sakura.ttf"
if file.IsNotExist(ttf) {
dlmu.Lock()
if file.IsNotExist(ttf) {
ctx.SendChain(message.Text("正在下载字体文件,请稍后..."))
err := file.DownloadTo(site+"sakura.ttf", ttf, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
dlmu.Unlock()
return
}
ctx.SendChain(message.Text("下载字体文件完毕"))
}
dlmu.Unlock()
}
// 获取该群背景类型,默认车万
kind := "车万"
gid := ctx.Event.GroupID
@ -129,127 +121,93 @@ func init() {
}
}
// 检查背景图片是否存在
folder := base + kind
if file.IsNotExist(folder) {
dlmu.Lock()
if file.IsNotExist(folder) {
ctx.SendChain(message.Text("正在下载背景图片,请稍后..."))
zipfile := kind + ".zip"
zipcache := base + zipfile
err := file.DownloadTo(site+zipfile, zipcache, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
dlmu.Unlock()
return
}
ctx.SendChain(message.Text("下载背景图片完毕"))
err = unpack(zipcache, folder+"/")
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
dlmu.Unlock()
return
}
ctx.SendChain(message.Text("解压背景图片完毕"))
// 释放空间
os.Remove(zipcache)
}
dlmu.Unlock()
zipfile := images + kind + ".zip"
_, err = file.GetLazyData(zipfile, false, false)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 生成种子
t, _ := strconv.ParseInt(time.Now().Format("20060102"), 10, 64)
seed := ctx.Event.UserID + t
// 随机获取背景
background, err := randimage(folder+"/", seed)
background, index, err := randimage(zipfile, seed)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 随机获取签文
title, text, err := randtext(mikuji, seed)
title, text, err := randtext(seed)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
digest := md5.Sum(helper.StringToBytes(zipfile + strconv.Itoa(index) + title + text))
cachefile := cache + hex.EncodeToString(digest[:])
if file.IsExist(cachefile) {
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + cachefile))
return
}
dlmu.Lock()
f, err := os.Create(cachefile)
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
_ = f.Close()
_ = os.Remove(cachefile)
dlmu.Unlock()
return
}
// 绘制背景
d, err := draw(background, title, text)
err = draw(background, title, text, f)
_ = f.Close()
dlmu.Unlock()
if err != nil {
ctx.SendChain(message.Text("ERROR: ", err))
return
}
// 发送图片
ctx.SendChain(message.Image("base64://" + helper.BytesToString(d)))
ctx.SendChain(message.Image("file:///" + file.BOTPATH + "/" + cachefile))
})
}
// @function unpack 解压资源包
// @param tgt 压缩文件位置
// @param dest 解压位置
// @return 错误信息
func unpack(tgt, dest string) error {
// 路径目录不存在则创建目录
if file.IsNotExist(dest) {
if err := os.MkdirAll(dest, 0755); err != nil {
panic(err)
}
}
reader, err := zip.OpenReader(tgt)
if err != nil {
return err
}
defer reader.Close()
// 遍历解压到文件
for _, file := range reader.File {
// 打开解压文件
rc, err := file.Open()
if err != nil {
return err
}
// 打开目标文件
w, err := os.OpenFile(dest+file.Name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
rc.Close()
return err
}
// 复制到文件
_, err = io.Copy(w, rc)
rc.Close()
w.Close()
if err != nil {
return err
}
}
return nil
}
// @function randimage 随机选取文件夹下的文件
// @param path 文件夹路径
// @function randimage 随机选取zip内的文件
// @param path zip路径
// @param seed 随机数种子
// @return 文件路径 & 错误信息
func randimage(path string, seed int64) (string, error) {
rd, err := ioutil.ReadDir(path)
func randimage(path string, seed int64) (im image.Image, index int, err error) {
reader, err := zip.OpenReader(path)
if err != nil {
return "", err
return
}
defer reader.Close()
rand.Seed(seed)
return path + rd[rand.Intn(len(rd))].Name(), nil
index = rand.Intn(len(reader.File))
file := reader.File[index]
f, err := file.Open()
if err != nil {
return
}
defer f.Close()
im, _, err = image.Decode(f)
return
}
// @function randtext 随机选取签文
// @param file 文件路径
// @param seed 随机数种子
// @return 签名 & 签文 & 错误信息
func randtext(file string, seed int64) (string, string, error) {
data, err := ioutil.ReadFile(file)
if err != nil {
return "", "", err
}
temp := []map[string]string{}
if err := json.Unmarshal(data, &temp); err != nil {
return "", "", err
}
func randtext(seed int64) (string, string, error) {
rand.Seed(seed)
r := rand.Intn(len(temp))
return temp[r]["title"], temp[r]["content"], nil
r := rand.Intn(len(omikujis))
return omikujis[r]["title"], omikujis[r]["content"], nil
}
// @function draw 绘制运势图
@ -258,27 +216,23 @@ func randtext(file string, seed int64) (string, string, error) {
// @param title 签名
// @param text 签文
// @return 错误信息
func draw(background, title, text string) ([]byte, error) {
// 加载背景
back, err := gg.LoadImage(background)
if err != nil {
return nil, err
}
canvas := gg.NewContext(back.Bounds().Size().Y, back.Bounds().Size().X)
canvas.DrawImage(back, 0, 0)
func draw(back image.Image, title, text string, dst io.Writer) error {
var txtc txt2img.TxtCanvas
txtc.Canvas = gg.NewContext(back.Bounds().Size().Y, back.Bounds().Size().X)
txtc.Canvas.DrawImage(back, 0, 0)
// 写标题
canvas.SetRGB(1, 1, 1)
if err := canvas.LoadFontFace(base+"sakura.ttf", 45); err != nil {
return nil, err
txtc.Canvas.SetRGB(1, 1, 1)
if err := txtc.Canvas.LoadFontFace(font, 45); err != nil {
return err
}
sw, _ := canvas.MeasureString(title)
canvas.DrawString(title, 140-sw/2, 112)
sw, _ := txtc.Canvas.MeasureString(title)
txtc.Canvas.DrawString(title, 140-sw/2, 112)
// 写正文
canvas.SetRGB(0, 0, 0)
if err := canvas.LoadFontFace(base+"sakura.ttf", 23); err != nil {
return nil, err
txtc.Canvas.SetRGB(0, 0, 0)
if err := txtc.Canvas.LoadFontFace(font, 23); err != nil {
return err
}
tw, th := canvas.MeasureString("测")
tw, th := txtc.Canvas.MeasureString("测")
tw, th = tw+10, th+10
r := []rune(text)
xsum := rowsnum(len(r), 9)
@ -288,7 +242,7 @@ func draw(background, title, text string) ([]byte, error) {
xnow := rowsnum(i+1, 9)
ysum := math.Min(len(r)-(xnow-1)*9, 9)
ynow := i%9 + 1
canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(ysum, ynow, th)+320.0)
txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(ysum, ynow, th)+320.0)
}
case 2:
div := rowsnum(len(r), 2)
@ -298,23 +252,14 @@ func draw(background, title, text string) ([]byte, error) {
ynow := i%div + 1
switch xnow {
case 1:
canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow, th)+320.0)
txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow, th)+320.0)
case 2:
canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow+(9-ysum), th)+320.0)
txtc.Canvas.DrawString(string(o), -offest(xsum, xnow, tw)+115, offest(9, ynow+(9-ysum), th)+320.0)
}
}
}
// 转成 base64
buffer := new(bytes.Buffer)
encoder := base64.NewEncoder(base64.StdEncoding, buffer)
var opt jpeg.Options
opt.Quality = 70
err = jpeg.Encode(encoder, canvas.Image(), &opt)
if err != nil {
return nil, err
}
encoder.Close()
return buffer.Bytes(), nil
_, err := txtc.WriteTo(dst)
return err
}
func offest(total, now int, distance float64) float64 {