You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

299 lines
6.3 KiB

package share_img
import (
"fmt"
"image"
"image/color"
"image/draw"
_ "image/jpeg"
"image/png"
"io/ioutil"
"os"
"path/filepath"
"recook/configs"
"recook/internal/back"
"recook/internal/static_path"
"runtime"
"github.com/astaxie/beego"
"github.com/gin-gonic/gin"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
farmhash "github.com/leemcloughlin/gofarmhash"
)
const (
fontDPI float64 = 72 // 屏幕每英寸的分辨率
)
var (
PingFangFont *truetype.Font
PingFangScRegular = "/qr_resource/PingFang-SC-Regular.ttf"
DefaultBackImage = "/qr_resource/default.png"
)
func init() {
dir, _ := os.Executable()
exPath := filepath.Dir(dir)
if runtime.GOOS != "linux" {
PingFangScRegular = "." + PingFangScRegular
DefaultBackImage = "." + DefaultBackImage
exPath = ""
}
fontBytes, err := ioutil.ReadFile(exPath + PingFangScRegular)
if err != nil {
panic(err)
}
PingFangFont, err = freetype.ParseFont(fontBytes)
if err != nil {
panic(err)
}
beego.SetLogFuncCall(true)
}
type shareImage struct {
File string
QrSize int
X int
Y int
}
func GetSharePhoto(c *gin.Context) {
share_code := c.Param("code")
url := fmt.Sprintf(`https://testh5.reecook.cn/#/user/appRegister/%s`, share_code)
if configs.IsProductionEnv() {
url = fmt.Sprintf(`https://h5.reecook.cn/#/user/appRegister/%s`, share_code)
}
dir, _ := os.Executable()
exPath := filepath.Dir(dir)
if runtime.GOOS != "linux" {
exPath = ""
}
//这边加个for 循环
//var imgBgArr = []string{"/qr_resource/default1.png", "/qr_resource/default2.png", "/qr_resource/default3.png"}
imgBgArr := []shareImage{{"/qr_resource/default1.jpg", 191, 725, 1334}, {"/qr_resource/default2.png", 115, 421, 874}, {"/qr_resource/default3.png", 254, 335, 1191}}
var imgBgArrs []string
urlImg1 := "https://testcdn.reecook.cn/static"
if configs.IsProductionEnv() {
urlImg1 = "https://cdn.reecook.cn/static"
}
for i, imgbg := range imgBgArr {
back_img := exPath + imgbg.File
// 判断文件是否存在
path, err := Merge(back_img, share_code, url, i, imgbg)
if err != nil {
beego.Error(err)
return
}
/* 允许追加空切片 */
imgBgArrs = append(imgBgArrs, urlImg1+path)
//img, err := imaging.Open(path)
//if err != nil {
// beego.Error(err)
// return
//}
//buffer := new(bytes.Buffer)
//if err := png.Encode(buffer, img); err != nil {
// http.Err(c, "png转码出错")
// return
//}
}
//上面生成多张
back.Suc(c, "操作成功", &imgBgArrs)
//c.Data(200, "image/png", buffer.Bytes())
}
// 判断所给路径文件/文件夹是否存在
func Exists(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
func GetFileName(back_img, code, url string, number int) (filename, save_path string, show_path string, err error) {
filename = fmt.Sprintf("%s_%d_%d.png", "shareInvite", farmhash.Hash64([]byte(fmt.Sprintf("%s_%s", back_img, code))), number)
save_path = filepath.Join(static_path.Dir.Root, static_path.Dir.Photo, filename)
show_path = filepath.Join(static_path.Dir.Photo, filename)
return filename, save_path, show_path, nil
}
func Merge(back_img, code, url string, number int, imgTemp shareImage) (path string, err error) {
_, save_path, show_path, err := GetFileName(back_img, code, url, number)
beego.Info(save_path)
if Exists(save_path) {
//不使用缓存
return show_path, nil
}
imgb, err := os.Open(back_img)
if err != nil {
return "", err
}
img, _, _ := image.Decode(imgb)
defer imgb.Close()
//share_img, err := GetShareCodeImage(code)
//if err != nil {
// panic(err)
//}
qr_img, err := QrForShare(url, imgTemp.QrSize)
if err != nil {
panic(err)
}
b := img.Bounds()
m := image.NewRGBA(b)
// // share add
//offset_share := image.Pt(340, 1081)
//draw.Draw(m, b, img, image.ZP, draw.Src)
//不显示邀请码
//draw.Draw(m, share_img.Bounds().Add(offset_share), share_img, image.ZP, draw.Over)
// qr add
offset := image.Pt(imgTemp.X, imgTemp.Y)
draw.Draw(m, b, img, image.ZP, draw.Src)
draw.Draw(m, qr_img.Bounds().Add(offset), qr_img, image.ZP, draw.Over)
// res_path := fmt.Sprintf("%s/%s_%s", save_path, DefaultBackImage, code)
imgw, _ := os.Create(save_path)
png.Encode(imgw, m)
//jpeg.Encode(imgw, m, &jpeg.Options{jpeg.DefaultQuality})
defer imgw.Close()
return show_path, nil
}
func GetShareCodeImage(code string) (image.Image, error) {
text := "邀请码:" + code
fontSize := 32
dx := getEachTextWidth(text) * int(fontSize) / 1000
dy := fontSize
// 新建一个 指定大小的 RGBA位图
img := image.NewNRGBA(image.Rect(0, 0, dx, dy+10))
// 画背景
for y := 0; y < dy+20; y++ {
for x := 0; x < dx; x++ {
// 设置某个点的颜色,依次是 RGBA
img.Set(x, y, color.RGBA{0, 0, 0, 0})
}
}
c := freetype.NewContext()
c.SetDPI(fontDPI)
c.SetFont(PingFangFont)
c.SetFontSize(float64(fontSize))
c.SetClip(img.Bounds())
c.SetDst(img)
c.SetSrc(image.NewUniform(color.RGBA{255, 255, 255, 255}))
pt := freetype.Pt(0, fontSize) // 字出现的位置
_, err := c.DrawString(text, pt)
if err != nil {
return nil, err
}
return img, nil
}
func getEachTextWidth(word string) int {
word_runes := []rune(word)
width := 0
for _, v := range word_runes {
if v, ok := number_map[string(v)]; ok {
width += v
} else {
width += number_map["base"]
}
}
return width
}
var number_map = map[string]int{
"base": 1000,
" ": 500,
"0": 880,
"1": 510,
"2": 780,
"3": 800,
"4": 880,
"5": 820,
"6": 840,
"7": 740,
"8": 870,
"9": 840,
"A": 960,
"B": 900,
"C": 810,
"D": 910,
"E": 800,
"F": 780,
"G": 940,
"H": 930,
"I": 500,
"J": 440,
"K": 820,
"L": 630,
"M": 1140,
"N": 880,
"O": 910,
"P": 870,
"Q": 900,
"R": 920,
"S": 870,
"T": 780,
"U": 910,
"V": 910,
"W": 1110,
"X": 910,
"Y": 860,
"Z": 880,
"a": 790,
"b": 810,
"c": 710,
"d": 820,
"e": 860,
"f": 580,
"g": 840,
"h": 780,
"i": 330,
"j": 440,
"k": 760,
"l": 330,
"m": 990,
"n": 830,
"o": 830,
"p": 880,
"q": 830,
"r": 540,
"s": 800,
"t": 590,
"u": 830,
"v": 810,
"w": 950,
"x": 830,
"y": 860,
"z": 800,
}