gitech

Форк
0
140 строк · 3.8 Кб
1
// Copyright 2021 The Gitea Authors. All rights reserved.
2
// SPDX-License-Identifier: MIT
3

4
// Copied and modified from https://github.com/issue9/identicon/ (MIT License)
5
// Generate pseudo-random avatars by IP, E-mail, etc.
6

7
package identicon
8

9
import (
10
	"crypto/sha256"
11
	"fmt"
12
	"image"
13
	"image/color"
14
)
15

16
const minImageSize = 16
17

18
// Identicon is used to generate pseudo-random avatars
19
type Identicon struct {
20
	foreColors []color.Color
21
	backColor  color.Color
22
	size       int
23
	rect       image.Rectangle
24
}
25

26
// New returns an Identicon struct with the correct settings
27
// size image size
28
// back background color
29
// fore all possible foreground colors. only one foreground color will be picked randomly for one image
30
func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) {
31
	if len(fore) == 0 {
32
		return nil, fmt.Errorf("foreground is not set")
33
	}
34

35
	if size < minImageSize {
36
		return nil, fmt.Errorf("size %d is smaller than min size %d", size, minImageSize)
37
	}
38

39
	return &Identicon{
40
		foreColors: fore,
41
		backColor:  back,
42
		size:       size,
43
		rect:       image.Rect(0, 0, size, size),
44
	}, nil
45
}
46

47
// Make generates an avatar by data
48
func (i *Identicon) Make(data []byte) image.Image {
49
	h := sha256.New()
50
	h.Write(data)
51
	sum := h.Sum(nil)
52

53
	b1 := int(sum[0]+sum[1]+sum[2]) % len(blocks)
54
	b2 := int(sum[3]+sum[4]+sum[5]) % len(blocks)
55
	c := int(sum[6]+sum[7]+sum[8]) % len(centerBlocks)
56
	b1Angle := int(sum[9]+sum[10]) % 4
57
	b2Angle := int(sum[11]+sum[12]) % 4
58
	foreColor := int(sum[11]+sum[12]+sum[15]) % len(i.foreColors)
59

60
	return i.render(c, b1, b2, b1Angle, b2Angle, foreColor)
61
}
62

63
func (i *Identicon) render(c, b1, b2, b1Angle, b2Angle, foreColor int) image.Image {
64
	p := image.NewPaletted(i.rect, []color.Color{i.backColor, i.foreColors[foreColor]})
65
	drawBlocks(p, i.size, centerBlocks[c], blocks[b1], blocks[b2], b1Angle, b2Angle)
66
	return p
67
}
68

69
/*
70
# Algorithm
71

72
Origin: An image is splitted into 9 areas
73

74
```
75
  -------------
76
  | 1 | 2 | 3 |
77
  -------------
78
  | 4 | 5 | 6 |
79
  -------------
80
  | 7 | 8 | 9 |
81
  -------------
82
```
83

84
Area 1/3/9/7 use a 90-degree rotating pattern.
85
Area 1/3/9/7 use another 90-degree rotating pattern.
86
Area 5 uses a random pattern.
87

88
The Patched Fix: make the image left-right mirrored to get rid of something like "swastika"
89
*/
90

91
// draw blocks to the paletted
92
// c: the block drawer for the center block
93
// b1,b2: the block drawers for other blocks (around the center block)
94
// b1Angle,b2Angle: the angle for the rotation of b1/b2
95
func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, b1Angle, b2Angle int) {
96
	nextAngle := func(a int) int {
97
		return (a + 1) % 4
98
	}
99

100
	padding := (size % 3) / 2 // in cased the size can not be aligned by 3 blocks.
101

102
	blockSize := size / 3
103
	twoBlockSize := 2 * blockSize
104

105
	// center
106
	c(p, blockSize+padding, blockSize+padding, blockSize, 0)
107

108
	// left top (1)
109
	b1(p, 0+padding, 0+padding, blockSize, b1Angle)
110
	// center top (2)
111
	b2(p, blockSize+padding, 0+padding, blockSize, b2Angle)
112

113
	b1Angle = nextAngle(b1Angle)
114
	b2Angle = nextAngle(b2Angle)
115
	// right top (3)
116
	// b1(p, twoBlockSize+padding, 0+padding, blockSize, b1Angle)
117
	// right middle (6)
118
	// b2(p, twoBlockSize+padding, blockSize+padding, blockSize, b2Angle)
119

120
	b1Angle = nextAngle(b1Angle)
121
	b2Angle = nextAngle(b2Angle)
122
	// right bottom (9)
123
	// b1(p, twoBlockSize+padding, twoBlockSize+padding, blockSize, b1Angle)
124
	// center bottom (8)
125
	b2(p, blockSize+padding, twoBlockSize+padding, blockSize, b2Angle)
126

127
	b1Angle = nextAngle(b1Angle)
128
	b2Angle = nextAngle(b2Angle)
129
	// lef bottom (7)
130
	b1(p, 0+padding, twoBlockSize+padding, blockSize, b1Angle)
131
	// left middle (4)
132
	b2(p, 0+padding, blockSize+padding, blockSize, b2Angle)
133

134
	// then we make it left-right mirror, so we didn't draw 3/6/9 before
135
	for x := 0; x < size/2; x++ {
136
		for y := 0; y < size; y++ {
137
			p.SetColorIndex(size-x, y, p.ColorIndexAt(x, y))
138
		}
139
	}
140
}
141

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.