想法來源
每次寫文章都得花點時間找圖,有點點麻煩,(其實就是懶。。。)。而且翻了翻之前的文章配圖,大概是這個樣子。
emmm,風格還挺統一的。但身為正義凜然的公眾號博主,老是用這樣圖,會有些圖文不符,也不符合我這正襟危坐的人物形象,而且,做為一名程式猿,能用程式碼解決的事情,自然要用程式碼來解決。
最近看到有些技術類公眾號,都使用了統一的圖片模版,比如這樣:
左邊放上logo,右邊放字,簡約大氣。於是,想著自己也整一個。
圖片分析
要如何生成這樣一張圖呢,我們來簡單來分析一下。
最底層是一張純色的底圖,這個不難,之前已經介紹過如何繪製純色底圖了,具體顏色可以用工具吸色看看。
第二層是文字,在前面的文章中,已經介紹過如何繪製文字,在這裡剛好能用上。
第三層是logo,還沒有介紹過將一張圖覆蓋在另一張圖上的操作,本文會對此進行講解。
這裡還需要注意的就是文字跟logo的區域,在繪製時,需要將文字框和圖片框的位置計算好,這個可以使用 Sketch 工具來完成。
這樣就得到了Logo和文字位置的具體資訊。
接下來就可以開始寫程式碼了
程式碼編寫
首先,我們先繪製一個純色的背景。RGB色值為:(63, 64, 87),底圖的寬和高通過 Sketch 工具測出分別為 1050和442。
import (
"github.com/fogleman/gg"
"testing"
)
func TestDrawWxPic(t *testing.T){
weight := 1050
height := 442
dc := gg.NewContext(weight, height)
dc.SetRGB255(63, 64, 87)
dc.Clear()
dc.SavePNG("out.png")
}
輸出圖片如下:
然後來繪製第二層的文字:
import (
"github.com/fogleman/gg"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"io/ioutil"
"testing"
)
func TestDrawWxPic(t *testing.T){
width := 1050
height := 442
dc := gg.NewContext(width, height)
dc.SetRGB255(63, 64, 87)
dc.Clear()
fontFilePath := "/Users/bytedance/Downloads/FangZhengKaiTiJianTi.TTF"
fontFace, err := getOpenTypeFontFace(fontFilePath, 76, 72)
if err != nil {
panic(err)
}
dc.SetFontFace(*fontFace)
dc.SetRGB255(238, 241, 247)
// 文字框最大寬度
maxWordsWidth := 660.0
x := 645.0
y := 224.0
dc.DrawStringWrapped("高併發的祕密武器 epoll 機制", x, y, 0.5, 0.6, maxWordsWidth, 1.1, gg.AlignCenter)
dc.SavePNG("out.png")
}
func getOpenTypeFontFace(fontFilePath string, fontSize, dpi float64)(*font.Face, error){
fontData, fontFileReadErr := ioutil.ReadFile(fontFilePath)
if fontFileReadErr != nil {
returnnil, fontFileReadErr
}
otfFont, parseErr := opentype.Parse(fontData)
if parseErr != nil {
returnnil, parseErr
}
otfFace, newFaceErr := opentype.NewFace(otfFont, &opentype.FaceOptions{
Size: fontSize,
DPI: dpi,
})
if newFaceErr != nil {
returnnil, newFaceErr
}
return &otfFace, nil
}
DrawStringWrapped
方法已經在之前的文章中介紹過了,這裡就不綴述了,文字框的位置可以通過 (x,y,ax,ay)
這四個引數來調整。
輸出效果如下:
字型不太一樣,位置是差不多了。
最後來把logo拼上去:
import (
"github.com/disintegration/imaging"
"github.com/fogleman/gg"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"io/ioutil"
"testing"
)
func TestDrawWxPic(t *testing.T){
...
dc.DrawStringWrapped("高併發的祕密武器 epoll 機制", x, y, 0.5, 0.6, maxWordsWidth, 1.1, gg.AlignCenter)
//開始壓縮圖片
src, openErr := imaging.Open("logo.png")
if openErr != nil {
panic(openErr)
}
src = imaging.Resize(src, 240, 240, imaging.Lanczos)
dc.DrawImageAnchored(src, 182, 220, 0.5, 0.5)
dc.SavePNG("out.png")
}
fogleman/gg
包不支援對圖片使用 resize
的操作,因此這裡引入了一個新包,github.com/disintegration/imaging
。效果如下:
emm,看起來顏色有些不諧調,改一下背景色,然後放大一下logo試試:
嗯,這樣就好多了,把這段程式碼封裝成方法,傳入標題和檔案儲存位置,即可一鍵生成封面圖。
完整程式碼如下:
import (
"github.com/disintegration/imaging"
"github.com/fogleman/gg"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"io/ioutil"
"testing"
)
func TestDrawWxPic(t *testing.T){
generateWxImage("微信公眾號封面圖\n一鍵生成", "result")
}
func generateWxImage(title string, savingFileName string) {
width := 1050
height := 442
dc := gg.NewContext(width, height)
dc.SetRGB255(47, 54, 66)
dc.Clear()
fontFilePath := "FangZhengKaiTiJianTi.TTF"
fontFace, err := getOpenTypeFontFace(fontFilePath, 76, 72)
if err != nil {
panic(err)
}
dc.SetFontFace(*fontFace)
dc.SetRGB255(238, 241, 247)
// 文字框最大寬度
maxWordsWidth := 660.0
x := 665.0
y := 224.0
dc.DrawStringWrapped(title, x, y, 0.5, 0.6, maxWordsWidth, 1.1, gg.AlignCenter)
//開始壓縮圖片
src, openErr := imaging.Open("logo.png")
if openErr != nil {
panic(openErr)
}
src = imaging.Resize(src, 360, 360, imaging.Lanczos)
dc.DrawImageAnchored(src, 182, 220, 0.5, 0.5)
dc.SavePNG(savingFileName + ".png")
}
func getOpenTypeFontFace(fontFilePath string, fontSize, dpi float64)(*font.Face, error){
fontData, fontFileReadErr := ioutil.ReadFile(fontFilePath)
if fontFileReadErr != nil {
returnnil, fontFileReadErr
}
otfFont, parseErr := opentype.Parse(fontData)
if parseErr != nil {
returnnil, parseErr
}
otfFace, newFaceErr := opentype.NewFace(otfFont, &opentype.FaceOptions{
Size: fontSize,
DPI: dpi,
})
if newFaceErr != nil {
returnnil, newFaceErr
}
return &otfFace, nil
}
小結
回顧一下整個過程,其實只要想清楚最終想要的效果,然後把步驟拆解開來,程式碼其實寫起來並不複雜,重要的還是邏輯,至於類似於如何實現圖片裁剪、文字拼接、圖片縮放,這些通常都有現成的庫可以拿來就用。
當然,如果感興趣也可以深入研究其中的實現原理。就像前面所說,瞭解這些工具,可以增加手中的牌,遇到問題時自然更加左右逢源。
最近的大部分時間都花在了健身上,很長時間都沒有好好寫部落格了,接下來得好好寫文章了,光有輸入確實還不夠,用輸出反推輸入,會更加有的放矢。