3 分鐘帶你通過 Go 生成宣傳海報!
對於公網應用來說,海報功能是非常非常重要的,它不僅能擴大應用的知名度,還能起到營銷的作用。
那從技術上講,海報該怎麼去做呢?
大部分應用都會選擇前端渲染,比如 canvas 渲染,這是最常見的。當然也有一些應用選擇後端生成,兩者各有各的好處,也有各自的缺點。
這裏我們不去討論前端怎麼渲染,只講後端怎麼生成。
先來看下我們將要完成的效果,這是沒有加文字和二維碼的圖片:
這是加上我們的二維碼和漢字的樣子:
因爲微信不允許使用二維碼的圖片,所以我給打馬賽克了。
一、使用 Go 的 image 庫
Go 在處理圖形上,並沒有其他語言,比如 Java、Python 這些庫多。
主要 Go 的發力點並不在上面,但是如果工作需要用到 Go 來做海報,也不是不可以。
首先我們可以看到 Go 的官方包裏面也提供了 image 包,可以用它來處理圖片。
但是,並不是特別建議新手小白直接用這包來處理圖片,那你會觸碰到很多底層的知識。
更加建議使用一些別人封裝好的庫,使用起來會更加便捷順手。所以這裏我們就直接跳過了哈,嘻嘻。
二、github.com/golang/freetype
這裏我推薦的第一個庫是這個,他相對來說封裝得不是那麼面目全非,所以代碼量會多一些,但是他比較能熟悉 image 標準庫的使用。
1、安裝
這個庫的官網地址:https://github.com/golang/freetype
安裝命令:
go get github.com/golang/freetype
然後就可以直接使用了,不過後面我們會用到重置圖片大小,需要用到另外一個庫,這裏也可以一起安裝下:
go get github.com/nfnt/resize
2、準備材料
在實際開發中,你需要向設計師要兩張圖,一張是最後的效果圖,一張是把需要生成的素材摳掉了的圖。
如果裏面涉及到自定義字體的還得讓他們提供字體給我們。
3、上代碼
首先來看下我的文件結構:
-
cmd 是我的入口文件
-
public 素材這些我都放這下面了
-
fonts 這裏面我放的是我們的自定義字體
-
image 這裏我放了兩張圖,bg.png 背景圖 和 wx.png 二維碼圖。
接下來直接上代碼:
package main
import (
"bytes"
"fmt"
"github.com/golang/freetype"
"github.com/golang/freetype/truetype"
"github.com/nfnt/resize"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)
var (
fontKai *truetype.Font // 字體
)
func main() {
// 根據路徑打開模板文件
templateFile, err := os.Open("./public/image/bg.png")
if err != nil {
panic(err)
}
defer templateFile.Close()
// 解碼
templateFileImage, err := png.Decode(templateFile)
if err != nil {
panic(err)
}
// 新建一張和模板文件一樣大小的畫布
newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
// 將模板圖片畫到新建的畫布上
draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)
// 加載字體文件 這裏我們加載兩種字體文件
fontKai, err = loadFont("./public/fonts/kz_wyzt.ttf")
if err != nil {
log.Panicln(err.Error())
return
}
// 向圖片中寫入文字
// 在寫入之前有一些準備工作
content := freetype.NewContext()
content.SetClip(newTemplateImage.Bounds())
content.SetDst(newTemplateImage)
// 設置字體顏色
content.SetSrc(image.White)
// 設置字體分辨率
content.SetDPI(72)
// 設置字體大小
content.SetFontSize(40)
// 設置字體樣式,就是我們上面加載的字體
content.SetFont(fontKai)
// 正式寫入文字
// 參數1:要寫入的文字
// 參數2:文字座標
content.DrawString("電話:13800008888 地址:xxx_xxx_xxx 商鋪", freetype.Pt(151, 2100))
// 讀取二維碼圖片
erCodeTemplateFile, err := os.Open("./public/image/wx.png")
if err != nil {
panic(err)
}
defer templateFile.Close()
// 解碼
imageData, err := png.Decode(erCodeTemplateFile)
if err != nil {
panic(err)
}
// 2、重新調整要粘貼圖片尺寸
imageData = resize.Resize(300, 300, imageData, resize.Lanczos3)
// 粘貼縮略圖
draw.Draw(newTemplateImage,
newTemplateImage.Bounds().Add(image.Pt(1200, 1800)),
imageData,
imageData.Bounds().Min,
draw.Over)
// 保存圖片
saveFile(newTemplateImage)
}
// 根據路徑加載字體文件
// path 字體的路徑
func loadFont(path string) (font *truetype.Font, err error) {
var fontBytes []byte
fontBytes, err = ioutil.ReadFile(path) // 讀取字體文件
if err != nil {
err = fmt.Errorf("加載字體文件出錯:%s", err.Error())
return
}
font, err = freetype.ParseFont(fontBytes) // 解析字體文件
if err != nil {
err = fmt.Errorf("解析字體文件出錯,%s", err.Error())
return
}
return
}
func saveFile(pic *image.RGBA) {
dstFile, err := os.Create("./public/out/1.png")
if err != nil {
fmt.Println(err)
}
defer dstFile.Close()
png.Encode(dstFile, pic)
}
大部分代碼都寫了註釋,如果你有疑問歡迎加我們交流羣提問。
三、github.com/hitailang/poster
咱們做事絕對不能一杆子捅到底,還得再準備一個備用庫。
前不久一個同學,發消息問我,有個庫不能用了,庫的 GitHub 都打不開了,問我怎麼辦?
**我能怎麼辦?**這顯然是作者關庫了唄,不想開放了哇,遇到這種要麼找別人下好的給你,要麼就直接換庫唄,找個替代庫。
這個庫在封裝上比較便利,使用起來比上一個庫更加便捷。
1、安裝
官方地址:https://github.com/hitailang/poster
安裝命令:
go get github.com/hitailang/poster
2、上代碼
這個庫的官方 GitHub 首頁就有詳細的 demo,我這裏就直接抄過來了:
func main(){
nullHandler := &handler.NullHandler{}
ctx := &handler.Context{
//圖片都繪在這個PNG載體上
PngCarrier: core.NewPNG(0, 0, 750, 1334),
}
//繪製背景圖
backgroundHandler := &handler.BackgroundHandler{
X: 0, // 圖片x座標
Y: 0, // 圖片y座標
Path: "./assets/background.png", //圖片路徑
}
//繪製圓形圖像
imageCircleLocalHandler := &handler.ImageCircleLocalHandler{
X: 30, // 圖片x座標
Y: 50, // 圖片y座標
Path: "./assets/reward.png",
//URL: "http://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLJT9ncWLPov6rAzn4VCPSC4QoAvdangHRB1JgszqCvffggAysvzpm5MDb72Io4g9YAScHEw7xSWg/132", //圖片路徑
}
//繪製本地圖像
imageLocalHandler := &handler.ImageLocalHandler{
X: 30, // 圖片x座標
Y: 400,// 圖片y座標
Path: "./assets/reward.png", //圖片路徑
}
//繪製二維碼
qrCodeHandler := &handler.QRCodeHandler{
X: 30, // 二維碼x座標
Y: 860,// 二維碼y座標
URL: "https://github.com/hitailang/poster", // 二維碼跳轉URL地址
}
//繪製文字
textHandler1 := &handler.TextHandler{
Next: handler.Next{},
X: 180, // 文字x座標
Y: 105, // 文字y座標
Size: 20, // 文字大小
R: 255, // 文字顏色RGB值
G: 241,
B: 250,
Text: "如果覺得這個庫對您有用", // 文字內容
FontPath: "./assets/msyh.ttf", // 字體文件
}
//繪製文字
textHandler2 := &handler.TextHandler{
Next: handler.Next{},
X: 180,
Y: 150,
Size: 22,
R: 255,
G: 241,
B: 250,
Text: "請隨意讚賞~~",
FontPath: "./assets/msyh.ttf",
}
//結束繪製,把前面的內容合併成一張圖片,輸出到build目錄
endHandler := &handler.EndHandler{
Output: "./build/poster_" + xid.New().String() + ".png",
}
// 鏈式調用繪製過程
nullHandler.
SetNext(backgroundHandler).
SetNext(imageCircleLocalHandler).
SetNext(textHandler1).
SetNext(textHandler2).
SetNext(imageLocalHandler).
SetNext(qrCodeHandler).
SetNext(endHandler)
// 開始執行業務
if err := nullHandler.Run(ctx); err != nil {
// 異常
fmt.Println("Fail | Error:" + err.Error())
return
}
// 成功
fmt.Println("Success")
return
}
這個庫,有兩個缺點:
-
官方的 handler 在繪製圖片時,不支持縮放大小,所以如果有需要調整大小的,要麼自己實現它的 handler,要麼調整圖片大小
-
官方的庫在繪製圓形頭像時,只支持繪製 png 格式的,否則在剪切時會出現噪點
四、總結
一般開發中很少會讓後臺繪製海報,畢竟現在大部分海報上都會帶有分享者,也就是用戶的頭像信息啥的,屬於專屬圖片。
所以這種場景大部分都是提供模板給前端繪製。
但是有些場景,比如商品信息,活動信息等,這些統一的一樣的,還是有在後端生成的。
你學廢了麼?
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/9SDQGOQ3OnynS-R4VL3PtQ