每次写文章都得花点时间找图,有点点麻烦,(其实就是懒。。。)。而且翻了翻之前的文章配图,大概是这个样子。
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 }
回顾一下整个过程,其实只要想清楚最终想要的效果,然后把步骤拆解开来,代码其实写起来并不复杂,重要的还是逻辑,至于类似于如何实现图片裁剪、文字拼接、图片缩放,这些通常都有现成的库可以拿来就用。
当然,如果感兴趣也可以深入研究其中的实现原理。就像前面所说,了解这些工具,可以增加手中的牌,遇到问题时自然更加左右逢源。
最近的大部分时间都花在了健身上,很长时间都没有好好写博客了,接下来得好好写文章了,光有输入确实还不够,用输出反推输入,会更加有的放矢。