【需求背景】
公司游戏要上字节小游戏,而且改用golang来作为服务端接口(之前微信小游戏是用php作为api接口的),平台对于ios游戏不支持内购支付(跟微信那些一样因为苹果分成问题)。微信小游戏还可通过客服小程序或者跳转到其它小程序来进行切支付,字节这边目前是没有的。那就只剩下网页支付了,但是直接给链接看起来像欺骗,也不美观,最后使用了二维码图片方式,由用户识别再支付。这时候就涉及到图片合并的问题了,毕竟单独一个二维码还是挺不好看的。备忘下~~
【代码示例】
package main
import (
"bytes"
"errors"
"github.com/gin-gonic/gin"
"github.com/nfnt/resize"
"github.com/skip2/go-qrcode"
"image"
"image/draw"
"image/jpeg"
"io/ioutil"
"os"
)
func main() {
r := gin.Default()
r.GET("/getIosPayImage", func(c *gin.Context) {
imgByte,err := getIosPayImage("二维码内容,可以是下单支付链接url","./ios_pay_bg.png",450)
if err !=nil {
c.String(200, "error:"+err.Error())
return
}
c.Header("Content-Type", "image/jpeg; charset=utf-8")
c.String(200, string(imgByte))
})
r.Run()
}
//获取合并支付二维码后的图片字节流
func getIosPayImage(content string, image_path string, size int) ([]byte, error) {
bg_img_path_byte,_ := getByteFromImagePath(image_path)
img_path_byte := getQrcodeToByte(content, size)
// 把二维码图片合到背景图片上,具体参数可以根据实际修改
rgba, err := mergeImageNew(bg_img_path_byte, img_path_byte, 135, 267, 450)
if err != nil {
return nil, errors.New("未知错误")
}
buf := new(bytes.Buffer)
err = jpeg.Encode(buf, rgba, nil)
if err != nil {
return nil, errors.New("订单不存在")
}
buf_byte := buf.Bytes()
return buf_byte, nil
}
//生成二维码图片并返回字节流
func getQrcodeToByte(content string, size int) []byte {
if size == 0 {
size = 256
}
png, err := qrcode.Encode(content, qrcode.Medium, size)
if err != nil {
return nil
}
return png
}
//从图片文件读取字节流
func getByteFromImagePath(img_path string) ([]byte, error) {
file, err := os.Open(img_path)
if err != nil {
return nil, err
}
defer file.Close()
bytes, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
}
return bytes, err
}
// MergeImageNew 图片合并 base_byte:原图图片字节流,maskUrl:小图图片字节流,
func mergeImageNew(base_byte []byte, mask_byte []byte, paddingX int, paddingY int, width uint) (*image.RGBA, error) {
var base image.Image
base, _ = getImageFromByte(base_byte)
mask, err := imageZoom(mask_byte, width)
if err != nil {
return nil, err
}
baseSrcBounds := base.Bounds().Max
maskSrcBounds := mask.Bounds().Max
newWidth := baseSrcBounds.X
newHeight := baseSrcBounds.Y
maskWidth := maskSrcBounds.X
maskHeight := maskSrcBounds.Y
des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) // 底板
//首先将一个图片信息存入jpg
draw.Draw(des, des.Bounds(), base, base.Bounds().Min, draw.Over)
//将另外一张图片信息存入jpg
draw.Draw(des, image.Rect(paddingX, paddingY, (paddingX+maskWidth), (maskHeight+paddingY)), mask, image.Point{}, draw.Over)
return des, nil
}
// ImageZoom 按宽度缩放图片
func imageZoom(img_byte []byte, width uint) (image.Image, error) {
m, err := getImageFromByte(img_byte)
if err != nil {
return nil, err
}
if width == 0 {
return m, nil
}
thImg := resize.Resize(width, 0, m, resize.Lanczos3)
return thImg, nil
}
//从字节流获取图片对象
func getImageFromByte(img_byte []byte) (image.Image, error) {
img_reader := bytes.NewReader(img_byte)
m, _, err := image.Decode(img_reader)
return m, err
}