198 lines
5.4 KiB
Go
198 lines
5.4 KiB
Go
package xibao
|
||
|
||
import (
|
||
"image"
|
||
"image/color"
|
||
"log"
|
||
"os"
|
||
"strings"
|
||
|
||
"git.lxtend.com/lixiangwuxian/imagedd/sprite"
|
||
"git.lxtend.com/lixiangwuxian/imagedd/text2img"
|
||
"git.lxtend.com/qqbot/message"
|
||
"git.lxtend.com/qqbot/util"
|
||
"github.com/fogleman/gg"
|
||
"golang.org/x/image/font/opentype"
|
||
)
|
||
|
||
func GenerateCongratulationImage(text string, inputFile, outputFile string, isGood bool) {
|
||
// 加载喜报背景图片
|
||
im, err := gg.LoadImage(inputFile) // 需要提前准备的背景图片
|
||
if err != nil {
|
||
log.Print("无法加载喜报图片:", err)
|
||
return
|
||
}
|
||
|
||
// 创建与背景图片大小相同的画布
|
||
width := im.Bounds().Dx()
|
||
height := im.Bounds().Dy()
|
||
dc := gg.NewContext(width, height)
|
||
|
||
// 将背景图片绘制到画布上
|
||
dc.DrawImage(im, 0, 0)
|
||
// 判断是否为图片
|
||
if imgUrl, ok := isImageCQ(text); ok {
|
||
filePath, err := util.DownloadFile(imgUrl, "/tmp/qqbot", false)
|
||
if err != nil {
|
||
log.Print("无法下载图片:", err)
|
||
return
|
||
}
|
||
imC, err := gg.LoadImage(filePath)
|
||
if err != nil {
|
||
log.Print("无法加载图片:", err)
|
||
return
|
||
}
|
||
widthC := imC.Bounds().Dx()
|
||
heightC := imC.Bounds().Dy()
|
||
dcC := gg.NewContext(widthC, heightC)
|
||
dcC.DrawImage(imC, 0, 0)
|
||
|
||
// 保存原始状态
|
||
dcC.Push()
|
||
|
||
scaleFactor := 1.0
|
||
|
||
// 根据高度比例进行缩放
|
||
if float64(heightC) > float64(height)/1.8 {
|
||
scaleFactor = (float64(height) / 1.8) / float64(heightC)
|
||
}
|
||
|
||
// 根据宽度比例进行缩放
|
||
if float64(widthC) > float64(width)/1.1 {
|
||
scaleFactor = (float64(width) / 1.1) / float64(widthC)
|
||
}
|
||
|
||
// 针对宽高较小的情况进行缩放
|
||
if heightC < height/5 && widthC < width/4 {
|
||
if float64(widthC)*(float64(height)/5)/float64(heightC) > float64(width/4) {
|
||
scaleFactor = (float64(height) / 5) / float64(heightC)
|
||
// log.Print(fmt.Sprintf("图片高度过小,已缩放至高度的 %f 倍", scaleFactor))
|
||
} else {
|
||
scaleFactor = (float64(width) / 4) / float64(widthC)
|
||
// log.Print(fmt.Sprintf("图片宽度过小,已缩放至宽度的 %f 倍", scaleFactor))
|
||
}
|
||
}
|
||
|
||
// 应用缩放比例
|
||
// 计算缩放后的图像尺寸
|
||
newWidth := int(float64(widthC) * scaleFactor)
|
||
newHeight := int(float64(heightC) * scaleFactor)
|
||
|
||
// 创建一个新的上下文,使用缩放后的尺寸
|
||
dcScaledC := gg.NewContext(newWidth, newHeight)
|
||
|
||
// 将原始图像缩放并绘制到新的上下文中
|
||
dcScaledC.Scale(scaleFactor, scaleFactor)
|
||
dcScaledC.DrawImage(imC, 0, 0)
|
||
|
||
// 在最终画布上绘制缩放后的图像
|
||
dc.DrawImageAnchored(dcScaledC.Image(), width/2, height/2, 0.5, 0.5)
|
||
dc.SavePNG(outputFile)
|
||
return
|
||
}
|
||
|
||
// 设置字体和大小,字体文件需要自备,放在合适的路径
|
||
// if err := dc.LoadFontFace("./resource/emoji.ttf", 96); err != nil {
|
||
// log.Print("无法加载字体:", err)
|
||
// return
|
||
// }
|
||
fontBytes, err := os.ReadFile("./resource/emoji.ttf")
|
||
if err != nil {
|
||
log.Printf("failed to load font: %v", err)
|
||
}
|
||
|
||
// 解析字体
|
||
font, err := opentype.Parse(fontBytes)
|
||
if err != nil {
|
||
log.Printf("failed to parse font: %v", err)
|
||
}
|
||
|
||
// 设置字体大小和 DPI
|
||
const fontSize = 48
|
||
const dpi = 72
|
||
|
||
// 创建 font.Face,用于渲染文本
|
||
face, err := opentype.NewFace(font, &opentype.FaceOptions{
|
||
Size: fontSize,
|
||
DPI: dpi,
|
||
Hinting: 0,
|
||
})
|
||
if err != nil {
|
||
log.Printf("failed to create font face: %v", err)
|
||
return
|
||
}
|
||
|
||
dc.SetFontFace(face)
|
||
|
||
if err := dc.LoadFontFace("./resource/font.ttf", 96); err != nil {
|
||
log.Print("无法加载字体:", err)
|
||
return
|
||
}
|
||
|
||
if isGood {
|
||
// 设置文本颜色为红色
|
||
dc.SetRGB(0.8, 0, 0)
|
||
} else {
|
||
dc.SetRGB(0, 0, 0.8)
|
||
}
|
||
// 将文本按 \n 分割为多行
|
||
lines := strings.Split(text, "\n")
|
||
|
||
// 设置初始绘制的 y 位置,可以根据需要调整
|
||
startY := float64(height) / 2
|
||
lineHeight := 120.0 // 行高,可以根据字体大小调整
|
||
|
||
// 居中绘制每一行
|
||
for i, line := range lines {
|
||
i = i - len(lines)/2
|
||
x := float64(width) / 2
|
||
y := startY + float64(i)*lineHeight
|
||
dc.DrawStringAnchored(line, x, y, 0.5, 0.5)
|
||
}
|
||
|
||
// 将生成的图片保存为输出文件
|
||
err = dc.SavePNG(outputFile)
|
||
if err != nil {
|
||
log.Print("无法保存生成的图片:", err)
|
||
}
|
||
}
|
||
|
||
func GenerateCongratulationImageNew(text string, inputFile, outputFile string, isGood bool) {
|
||
baseboard := sprite.NewNamedSpriteBoard()
|
||
backgroundImageSprite, err := sprite.LoadSpriteFromFile("bg", inputFile)
|
||
backgroundImageSprite.Index = 0
|
||
if err != nil {
|
||
log.Print("无法加载背景图片:", err)
|
||
return
|
||
}
|
||
baseboard.AddSprite(backgroundImageSprite)
|
||
var textColor color.RGBA
|
||
if isGood {
|
||
// 设置文本颜色为红色
|
||
textColor = color.RGBA{R: 255 * 0.8, G: 0, B: 0, A: 0}
|
||
} else {
|
||
textColor = color.RGBA{R: 0, G: 0, B: 255 * 0.8, A: 0}
|
||
}
|
||
textImage, err := text2img.RenderTextToTrimmedImage(nil, text, 48, textColor, 0, 0)
|
||
if err != nil {
|
||
log.Print("无法渲染文本:", err)
|
||
return
|
||
}
|
||
textSprite := sprite.Sprite{
|
||
Name: "text",
|
||
Images: []image.Image{textImage},
|
||
Position: image.Point{X: backgroundImageSprite.GetCurrentImage().Bounds().Dx()/2 - textImage.Bounds().Dx()/2, Y: backgroundImageSprite.GetCurrentImage().Bounds().Dy()/2 - textImage.Bounds().Dy()/2},
|
||
Index: 1,
|
||
}
|
||
baseboard.AddSprite(&textSprite)
|
||
baseboard.SaveToApng(outputFile)
|
||
}
|
||
|
||
func isImageCQ(text string) (string, bool) {
|
||
imgMsg := message.ImageMessage{}
|
||
if err := imgMsg.ParseMessage(text); err == nil {
|
||
return imgMsg.Data.URL, true
|
||
}
|
||
return "", false
|
||
}
|