Skip to content
Permalink
Browse files

optimize, x30 performance

  • Loading branch information...
holys committed Nov 12, 2015
1 parent b941fb4 commit f25ea56e8863bb86dfd3d8656d65f310c8c626ce
Showing with 45 additions and 25 deletions.
  1. +38 −8 avatar/avatar.go
  2. +0 −11 avatar/draw.go
  3. +7 −6 cmd/avatar/main.go
@@ -1,13 +1,15 @@
package avatar

import (
"bytes"
"errors"
"image"
"image/color"
"image/png"
"strings"
"sync"
"unicode"

"github.com/dchest/lru"
"stathat.com/c/consistent"
)

@@ -29,22 +31,19 @@ var (
ErrUnsupportChar = errors.New("unsupported character")

c = consistent.New()

once sync.Once
globalDrawer *drawer
)

type InitialsAvatar struct {
drawer *drawer
cache *lru.Cache
}

// New creates an instance of InitialsAvatar
func New(fontFile string) *InitialsAvatar {
avatar := new(InitialsAvatar)
once.Do(func() {
globalDrawer = newDrawer(fontFile)
})
avatar.drawer = globalDrawer
avatar.drawer = newDrawer(fontFile)
avatar.cache = lru.New(lru.Config{MaxItems: 1024})

return avatar
}

@@ -66,6 +65,37 @@ func (a *InitialsAvatar) Draw(name string, size int) (image.Image, error) {
return a.drawer.Draw(initials, size, bgcolor), nil
}

func (a *InitialsAvatar) DrawToBytes(name string, size int) ([]byte, error) {
if size <= 0 {
size = 48 // default size
}
name = strings.TrimSpace(name)
firstRune := []rune(name)[0]
if !isHan(firstRune) && !unicode.IsLetter(firstRune) {
return nil, ErrUnsupportChar
}
initials := getInitials(name)
bgcolor := getColorByName(name)

// get from cache
v, ok := a.cache.GetBytes(lru.Key(initials))
if ok {
return v, nil
}

m := a.drawer.Draw(initials, size, bgcolor)

var buf bytes.Buffer
err := png.Encode(&buf, m)
if err != nil {
return nil, err
}
// set cache
a.cache.SetBytes(lru.Key(initials), buf.Bytes())

return buf.Bytes(), nil
}

// is Chinese?
func isHan(r rune) bool {
if unicode.Is(unicode.Scripts["Han"], r) {
@@ -8,7 +8,6 @@ import (
"math"

"github.com/golang/freetype/truetype"
"github.com/hashicorp/golang-lru"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
@@ -19,7 +18,6 @@ type drawer struct {
dpi float64
fontHinting font.Hinting
face font.Face
cache *lru.Cache
}

func newDrawer(fontFile string) *drawer {
@@ -40,20 +38,12 @@ func newDrawer(fontFile string) *drawer {
DPI: g.dpi,
Hinting: g.fontHinting,
})
g.cache, err = lru.New(1024 * 1024)
if err != nil {
panic(err.Error())
}

return g
}

// our avatar image is square
func (g *drawer) Draw(s string, size int, bg *color.RGBA) image.Image {
if v, ok := g.cache.Get(s); ok {
return v.(image.Image)
}

// draw the background
dst := image.NewRGBA(image.Rect(0, 0, size, size))
draw.Draw(dst, dst.Bounds(), &image.Uniform{bg}, image.ZP, draw.Src)
@@ -72,7 +62,6 @@ func (g *drawer) Draw(s string, size int, bg *color.RGBA) image.Image {
}
drawer.DrawString(s)

g.cache.Add(s, dst)
return dst
}

@@ -3,12 +3,12 @@ package main
import (
"flag"
"fmt"
"image/png"
"log"
"net/http"
"path/filepath"
"strconv"

"github.com/davecheney/profile"
"github.com/holys/initials-avatar/avatar"
"github.com/labstack/echo"
mw "github.com/labstack/echo/middleware"
@@ -20,12 +20,12 @@ var (
)

type avatarHandler struct {
fontFile string
avatar *avatar.InitialsAvatar
}

func newAvatarHandler(fontFile string) *avatarHandler {
h := new(avatarHandler)
h.fontFile = fontFile
h.avatar = avatar.New(fontFile)
return h
}

@@ -41,20 +41,21 @@ func (h *avatarHandler) Get(ctx *echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}

a := avatar.New(h.fontFile)
m, err := a.Draw(name, sz)
data, err := h.avatar.DrawToBytes(name, sz)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}

ctx.Response().Header().Set("Content-Type", "image/png")
ctx.Response().Header().Set("Cache-Control", "max-age=600")
ctx.Response().WriteHeader(http.StatusOK)
ctx.Response().Write(data)

return png.Encode(ctx.Response().Writer(), m)
return nil
}

func main() {
defer profile.Start(profile.CPUProfile).Stop()
flag.Parse()
if len(*fontFile) == 0 {
log.Fatal("invalid font file path")

0 comments on commit f25ea56

Please sign in to comment.
You can’t perform that action at this time.