Skip to content

Commit

Permalink
增加生成动态头像的方法
Browse files Browse the repository at this point in the history
  • Loading branch information
lvpengc committed Oct 21, 2020
1 parent b125831 commit 4e8c9e5
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 1 deletion.
21 changes: 21 additions & 0 deletions foundation/avatar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package foundation

import (
"github.com/lyupengpublish/golibs/myutils/calc"
"image/color"
)
var colors = []uint32{
0xff6200, 0x42c58e, 0x5a8de1, 0x785fe0,
}
//生成头像的方式
func GeneraterAvater(width int,height int,content string) []byte {
ab := calc.NewAvatarBuilder("../static/SourceHanSansSC-Medium.ttf", &calc.SourceHansSansSCMedium{})
ab.SetBackgroundColorHex(colors[3])
ab.SetFrontgroundColor(color.White)
ab.SetFontSize(80)
ab.SetAvatarSize(width, height)
if data,err:=ab.GenerateImage(content);err==nil {
return data
}
return nil
}
11 changes: 11 additions & 0 deletions foundation/avatar_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package foundation

import (
"testing"
)

func Test_ge(t *testing.T) {

GeneraterAvater()

}
6 changes: 5 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ module github.com/lyupengpublish/golibs

go 1.13

require github.com/aliyun/alibaba-cloud-sdk-go v1.61.572
require (
github.com/aliyun/alibaba-cloud-sdk-go v1.61.572
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
Expand All @@ -26,6 +28,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
14 changes: 14 additions & 0 deletions myutils/calc/SourceHansSansSCMedium.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package calc
import "regexp"
type SourceHansSansSCMedium struct{}
func (f *SourceHansSansSCMedium) CalculateCenterLocation(s string, ab *AvatarBuilder) (x int, y int) {
cr := regexp.MustCompile("[\u4e00-\u9FA5]{1}")
er := regexp.MustCompile("[a-zA-Z]{1}")
nr := regexp.MustCompile("[0-9]{1}")
cCount := len(cr.FindAllStringSubmatch(s, -1))
eCount := len(er.FindAllStringSubmatch(s, -1))
nCount := len(nr.FindAllStringSubmatch(s, -1))
x = ab.W/2 - (cCount*ab.GetFontWidth()+eCount*ab.GetFontWidth()*3/5+nCount*ab.GetFontWidth()*3/5)/2
y = ab.H/2 + ab.GetFontWidth()*4/11
return
}
163 changes: 163 additions & 0 deletions myutils/calc/avatarbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package calc

import (
"bufio"
"bytes"
"errors"
"image"
"image/color"
"image/draw"
"image/png"
"io/ioutil"
"os"

"github.com/golang/freetype"
"golang.org/x/image/font"
)

type FontCenterCalculator interface {
// CalculateCenterLocation used to calculate center location in different font style
CalculateCenterLocation(string, *AvatarBuilder) (int, int)
}

type AvatarBuilder struct {
W int
H int
fontfile string
fontsize float64
bg color.Color
fg color.Color
ctx *freetype.Context
calc FontCenterCalculator
}

func NewAvatarBuilder(fontfile string, calc FontCenterCalculator) *AvatarBuilder {
ab := &AvatarBuilder{}
ab.fontfile = fontfile
ab.bg, ab.fg = color.White, color.Black
ab.W, ab.H = 200, 200
ab.fontsize = 95
ab.calc = calc

return ab
}

func (ab *AvatarBuilder) SetFrontgroundColor(c color.Color) {
ab.fg = c
}

func (ab *AvatarBuilder) SetBackgroundColor(c color.Color) {
ab.bg = c
}

func (ab *AvatarBuilder) SetFrontgroundColorHex(hex uint32) {
ab.fg = ab.hexToRGBA(hex)
}

func (ab *AvatarBuilder) SetBackgroundColorHex(hex uint32) {
ab.bg = ab.hexToRGBA(hex)
}

func (ab *AvatarBuilder) SetFontSize(size float64) {
ab.fontsize = size
}

func (ab *AvatarBuilder) SetAvatarSize(w int, h int) {
ab.W = w
ab.H = h
}


func (ab *AvatarBuilder) GenerateImageAndSave(s string, outname string) error {
bs, err := ab.GenerateImage(s)
if err != nil {
return err
}

// Save that RGBA image to disk.
outFile, err := os.Create(outname)
if err != nil {
return errors.New("create file: " + err.Error())
}
defer outFile.Close()

b := bufio.NewWriter(outFile)
if _, err := b.Write(bs); err != nil {
return errors.New("write bytes to file: " + err.Error())

}
if err = b.Flush(); err != nil {
return errors.New("flush image: " + err.Error())
}

return nil
}

func (ab *AvatarBuilder) GenerateImage(s string) ([]byte, error) {
rgba := ab.buildColorImage()
if ab.ctx == nil {
if err := ab.buildDrawContext(rgba); err != nil {
return nil, err
}
}

x, y := ab.calc.CalculateCenterLocation(s, ab)
pt := freetype.Pt(x, y)
if _, err := ab.ctx.DrawString(s, pt); err != nil {
return nil, errors.New("draw string: " + err.Error())
}

buf := &bytes.Buffer{}
if err := png.Encode(buf, rgba); err != nil {
return nil, errors.New("png encode: " + err.Error())
}

return buf.Bytes(), nil
}

func (ab *AvatarBuilder) buildColorImage() *image.RGBA {
bg := image.NewUniform(ab.bg)
rgba := image.NewRGBA(image.Rect(0, 0, ab.W, ab.H))
draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
return rgba
}

func (ab *AvatarBuilder) hexToRGBA(h uint32) *color.RGBA {
rgba := &color.RGBA{
R: uint8(h >> 16),
G: uint8((h & 0x00ff00) >> 8),
B: uint8(h & 0x0000ff),
A: 255,
}

return rgba
}

func (ab *AvatarBuilder) buildDrawContext(rgba *image.RGBA) error {
// Read the font data.
fontBytes, err := ioutil.ReadFile(ab.fontfile)
if err != nil {
return errors.New("error when open font file:" + err.Error())
}

f, err := freetype.ParseFont(fontBytes)
if err != nil {
return errors.New("error when parse font file:" + err.Error())
}

c := freetype.NewContext()
c.SetDPI(72)
c.SetFont(f)
c.SetFontSize(ab.fontsize)
c.SetClip(rgba.Bounds())
c.SetDst(rgba)
c.SetSrc(image.NewUniform(ab.fg))
c.SetHinting(font.HintingNone)

ab.ctx = c
return nil
}

func (ab *AvatarBuilder) GetFontWidth() int {
return int(ab.ctx.PointToFixed(ab.fontsize) >> 6)
}
Binary file added static/SourceHanSansSC-Medium.ttf
Binary file not shown.

0 comments on commit 4e8c9e5

Please sign in to comment.