github.com/status-im/status-go@v1.1.0/protocol/identity/ring/ring.go (about)

     1  package ring
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"image"
     7  	"image/png"
     8  	"math"
     9  
    10  	"github.com/fogleman/gg"
    11  
    12  	"github.com/status-im/status-go/multiaccounts"
    13  )
    14  
    15  type Theme int
    16  
    17  const (
    18  	LightTheme Theme = 1
    19  	DarkTheme  Theme = 2
    20  )
    21  
    22  var (
    23  	lightThemeIdenticonRingColors = []string{
    24  		"#000000", "#726F6F", "#C4C4C4", "#E7E7E7", "#FFFFFF", "#00FF00",
    25  		"#009800", "#B8FFBB", "#FFC413", "#9F5947", "#FFFF00", "#A8AC00",
    26  		"#FFFFB0", "#FF5733", "#FF0000", "#9A0000", "#FF9D9D", "#FF0099",
    27  		"#C80078", "#FF00FF", "#900090", "#FFB0FF", "#9E00FF", "#0000FF",
    28  		"#000086", "#9B81FF", "#3FAEF9", "#9A6600", "#00FFFF", "#008694",
    29  		"#C2FFFF", "#00F0B6"}
    30  	darkThemeIdenticonRingColors = []string{
    31  		"#000000", "#726F6F", "#C4C4C4", "#E7E7E7", "#FFFFFF", "#00FF00",
    32  		"#009800", "#B8FFBB", "#FFC413", "#9F5947", "#FFFF00", "#A8AC00",
    33  		"#FFFFB0", "#FF5733", "#FF0000", "#9A0000", "#FF9D9D", "#FF0099",
    34  		"#C80078", "#FF00FF", "#900090", "#FFB0FF", "#9E00FF", "#0000FF",
    35  		"#000086", "#9B81FF", "#3FAEF9", "#9A6600", "#00FFFF", "#008694",
    36  		"#C2FFFF", "#00F0B6"}
    37  )
    38  
    39  type DrawRingParam struct {
    40  	Theme      Theme                   `json:"theme"`
    41  	ColorHash  multiaccounts.ColorHash `json:"colorHash"`
    42  	ImageBytes []byte                  `json:"imageBytes"`
    43  	Height     int                     `json:"height"`
    44  	Width      int                     `json:"width"`
    45  	RingWidth  float64                 `json:"ringWidth"`
    46  }
    47  
    48  func DrawRing(param *DrawRingParam) ([]byte, error) {
    49  	var colors []string
    50  	switch param.Theme {
    51  	case LightTheme:
    52  		colors = lightThemeIdenticonRingColors
    53  	case DarkTheme:
    54  		colors = darkThemeIdenticonRingColors
    55  	default:
    56  		return nil, fmt.Errorf("unknown theme")
    57  	}
    58  
    59  	dc := gg.NewContext(param.Width, param.Height)
    60  	img, _, err := image.Decode(bytes.NewReader(param.ImageBytes))
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	dc.DrawImage(img, 0, 0)
    65  
    66  	radius := (float64(param.Height) - param.RingWidth) / 2
    67  	arcPos := 0.0
    68  
    69  	totalRingUnits := 0
    70  	for i := 0; i < len(param.ColorHash); i++ {
    71  		totalRingUnits += param.ColorHash[i][0]
    72  	}
    73  	unitRadLen := 2 * math.Pi / float64(totalRingUnits)
    74  
    75  	for i := 0; i < len(param.ColorHash); i++ {
    76  		dc.SetHexColor(colors[param.ColorHash[i][1]])
    77  		dc.DrawArc(float64(param.Width/2), float64(param.Height/2), radius, arcPos, arcPos+unitRadLen*float64(param.ColorHash[i][0]))
    78  		dc.SetLineWidth(param.RingWidth)
    79  		dc.SetLineCapButt()
    80  		dc.Stroke()
    81  		arcPos += unitRadLen * float64(param.ColorHash[i][0])
    82  	}
    83  
    84  	buf := new(bytes.Buffer)
    85  	err = png.Encode(buf, dc.Image())
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	return buf.Bytes(), nil
    91  }