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、上代碼

首先來看下我的文件結構:

接下來直接上代碼:

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
}

這個庫,有兩個缺點:

四、總結

一般開發中很少會讓後臺繪製海報,畢竟現在大部分海報上都會帶有分享者,也就是用戶的頭像信息啥的,屬於專屬圖片。

所以這種場景大部分都是提供模板給前端繪製。

但是有些場景,比如商品信息,活動信息等,這些統一的一樣的,還是有在後端生成的。

你學廢了麼?

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/9SDQGOQ3OnynS-R4VL3PtQ