Skip to content

Better builtin avatar generator #17707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 19, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/codeformat/formatimports_test.go
Original file line number Diff line number Diff line change
@@ -50,7 +50,7 @@ import (
"bytes"
"fmt"
"image"
"image/color/palette"
"image/color"

_ "image/gif" // for processing gif images
_ "image/jpeg" // for processing jpeg images
@@ -76,7 +76,7 @@ import (
"bytes"
"fmt"
"image"
"image/color/palette"
"image/color"

_ "image/gif" // for processing gif images
_ "image/jpeg" // for processing jpeg images
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -63,7 +63,6 @@ require (
github.com/hashicorp/go-version v1.3.1
github.com/hashicorp/golang-lru v0.5.4
github.com/huandu/xstrings v1.3.2
github.com/issue9/identicon v1.2.0
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
github.com/json-iterator/go v1.1.11
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -661,10 +661,6 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/issue9/assert v1.4.1 h1:gUtOpMTeaE4JTe9kACma5foOHBvVt1p5XTFrULDwdXI=
github.com/issue9/assert v1.4.1/go.mod h1:Yktk83hAVl1SPSYtd9kjhBizuiBIqUQyj+D5SE2yjVY=
github.com/issue9/identicon v1.2.0 h1:ek+UcTTyMW/G0iNbLOAlrPC13eSzXTWhbJSs8PHhHGQ=
github.com/issue9/identicon v1.2.0/go.mod h1:A9toNT0ky/1WP5iNFyDmrkNiYH6eX3HcN5V6uH0g0ec=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
21 changes: 4 additions & 17 deletions modules/avatar/avatar.go
Original file line number Diff line number Diff line change
@@ -8,16 +8,15 @@ import (
"bytes"
"fmt"
"image"
"image/color/palette"
"image/color"

_ "image/gif" // for processing gif images
_ "image/jpeg" // for processing jpeg images
_ "image/png" // for processing png images

"code.gitea.io/gitea/modules/avatar/identicon"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"

"github.com/issue9/identicon"
"github.com/nfnt/resize"
"github.com/oliamb/cutter"
)
@@ -28,20 +27,8 @@ const AvatarSize = 290
// RandomImageSize generates and returns a random avatar image unique to input data
// in custom size (height and width).
func RandomImageSize(size int, data []byte) (image.Image, error) {
randExtent := len(palette.WebSafe) - 32
integer, err := util.RandomInt(int64(randExtent))
if err != nil {
return nil, fmt.Errorf("util.RandomInt: %v", err)
}
colorIndex := int(integer)
backColorIndex := colorIndex - 1
if backColorIndex < 0 {
backColorIndex = randExtent - 1
}

// Define size, background, and forecolor
imgMaker, err := identicon.New(size,
palette.WebSafe[backColorIndex], palette.WebSafe[colorIndex:colorIndex+32]...)
// we use white as background, and use dark colors to draw blocks
imgMaker, err := identicon.New(size, color.White, identicon.DarkColors...)
if err != nil {
return nil, fmt.Errorf("identicon.New: %v", err)
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
// SPDX-License-Identifier: MIT
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Copied and modified from https://github.com/issue9/identicon/ (MIT License)

package identicon

import "image"

var (
// 可以出现在中间的方块,一般为了美观,都是对称图像。
// the blocks can appear in center, these blocks can be more beautiful
centerBlocks = []blockFunc{b0, b1, b2, b3, b19, b26, b27}

// 所有方块
// all blocks
blocks = []blockFunc{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27}
)

// 所有 block 函数的类型
type blockFunc func(img *image.Paletted, x, y, size int, angle int)

// 将多边形 points 旋转 angle 个角度,然后输出到 img 上,起点为 x,y 坐标
//
// points 中的坐标是基于左上角是原点的坐标系。
// draw a polygon by points, and the polygon is rotated by angle.
func drawBlock(img *image.Paletted, x, y, size int, angle int, points []int) {
if angle > 0 { // 0 角度不需要转换
if angle != 0 {
m := size / 2
rotate(points, m, m, angle)
}
@@ -33,7 +34,7 @@ func drawBlock(img *image.Paletted, x, y, size int, angle int, points []int) {
}
}

// 全空白
// blank
//
// --------
// | |
@@ -42,7 +43,7 @@ func drawBlock(img *image.Paletted, x, y, size int, angle int, points []int) {
// --------
func b0(img *image.Paletted, x, y, size int, angle int) {}

// 全填充正方形
// full-filled
//
// --------
// |######|
@@ -57,7 +58,7 @@ func b1(img *image.Paletted, x, y, size int, angle int) {
}
}

// 中间小方块
// a small block
// ----------
// | |
// | #### |
@@ -66,8 +67,8 @@ func b1(img *image.Paletted, x, y, size int, angle int) {
// ----------
func b2(img *image.Paletted, x, y, size int, angle int) {
l := size / 4
x = x + l
y = y + l
x += l
y += l

for i := x; i < x+2*l; i++ {
for j := y; j < y+2*l; j++ {
@@ -76,7 +77,7 @@ func b2(img *image.Paletted, x, y, size int, angle int) {
}
}

// 菱形
// diamond
//
// ---------
// | # |
@@ -133,7 +134,7 @@ func b5(img *image.Paletted, x, y, size int, angle int) {
})
}

// b6 矩形
// b6
//
// --------
// |### |
@@ -151,7 +152,7 @@ func b6(img *image.Paletted, x, y, size int, angle int) {
})
}

// b7 斜放的锥形
// b7 italic cone
//
// ---------
// | # |
@@ -170,7 +171,7 @@ func b7(img *image.Paletted, x, y, size int, angle int) {
})
}

// b8 三个堆叠的三角形
// b8 three small triangles
//
// -----------
// | # |
@@ -184,23 +185,23 @@ func b8(img *image.Paletted, x, y, size int, angle int) {
m := size / 2
mm := m / 2

// 顶部三角形
// top
drawBlock(img, x, y, size, angle, []int{
m, 0,
3 * mm, m,
mm, m,
m, 0,
})

// 底下左边
// bottom left
drawBlock(img, x, y, size, angle, []int{
mm, m,
m, size,
0, size,
mm, m,
})

// 底下右边
// bottom right
drawBlock(img, x, y, size, angle, []int{
3 * mm, m,
size, size,
@@ -209,7 +210,7 @@ func b8(img *image.Paletted, x, y, size int, angle int) {
})
}

// b9 斜靠的三角形
// b9 italic triangle
//
// ---------
// |# |
@@ -257,7 +258,7 @@ func b10(img *image.Paletted, x, y, size int, angle int) {
})
}

// b11 左上角1/4大小的方块
// b11
//
// ----------
// |#### |
135 changes: 135 additions & 0 deletions modules/avatar/identicon/colors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package identicon

import "image/color"

// DarkColors are dark colors for avatar blocks, they come from image/color/palette.WebSafe, and light colors (0xff) are removed
var DarkColors = []color.Color{
color.RGBA{0x00, 0x00, 0x33, 0xff},
color.RGBA{0x00, 0x00, 0x66, 0xff},
color.RGBA{0x00, 0x00, 0x99, 0xff},
color.RGBA{0x00, 0x00, 0xcc, 0xff},
color.RGBA{0x00, 0x33, 0x00, 0xff},
color.RGBA{0x00, 0x33, 0x33, 0xff},
color.RGBA{0x00, 0x33, 0x66, 0xff},
color.RGBA{0x00, 0x33, 0x99, 0xff},
color.RGBA{0x00, 0x33, 0xcc, 0xff},
color.RGBA{0x00, 0x66, 0x00, 0xff},
color.RGBA{0x00, 0x66, 0x33, 0xff},
color.RGBA{0x00, 0x66, 0x66, 0xff},
color.RGBA{0x00, 0x66, 0x99, 0xff},
color.RGBA{0x00, 0x66, 0xcc, 0xff},
color.RGBA{0x00, 0x99, 0x00, 0xff},
color.RGBA{0x00, 0x99, 0x33, 0xff},
color.RGBA{0x00, 0x99, 0x66, 0xff},
color.RGBA{0x00, 0x99, 0x99, 0xff},
color.RGBA{0x00, 0x99, 0xcc, 0xff},
color.RGBA{0x00, 0xcc, 0x00, 0xff},
color.RGBA{0x00, 0xcc, 0x33, 0xff},
color.RGBA{0x00, 0xcc, 0x66, 0xff},
color.RGBA{0x00, 0xcc, 0x99, 0xff},
color.RGBA{0x00, 0xcc, 0xcc, 0xff},
color.RGBA{0x33, 0x00, 0x00, 0xff},
color.RGBA{0x33, 0x00, 0x33, 0xff},
color.RGBA{0x33, 0x00, 0x66, 0xff},
color.RGBA{0x33, 0x00, 0x99, 0xff},
color.RGBA{0x33, 0x00, 0xcc, 0xff},
color.RGBA{0x33, 0x33, 0x00, 0xff},
color.RGBA{0x33, 0x33, 0x33, 0xff},
color.RGBA{0x33, 0x33, 0x66, 0xff},
color.RGBA{0x33, 0x33, 0x99, 0xff},
color.RGBA{0x33, 0x33, 0xcc, 0xff},
color.RGBA{0x33, 0x66, 0x00, 0xff},
color.RGBA{0x33, 0x66, 0x33, 0xff},
color.RGBA{0x33, 0x66, 0x66, 0xff},
color.RGBA{0x33, 0x66, 0x99, 0xff},
color.RGBA{0x33, 0x66, 0xcc, 0xff},
color.RGBA{0x33, 0x99, 0x00, 0xff},
color.RGBA{0x33, 0x99, 0x33, 0xff},
color.RGBA{0x33, 0x99, 0x66, 0xff},
color.RGBA{0x33, 0x99, 0x99, 0xff},
color.RGBA{0x33, 0x99, 0xcc, 0xff},
color.RGBA{0x33, 0xcc, 0x00, 0xff},
color.RGBA{0x33, 0xcc, 0x33, 0xff},
color.RGBA{0x33, 0xcc, 0x66, 0xff},
color.RGBA{0x33, 0xcc, 0x99, 0xff},
color.RGBA{0x33, 0xcc, 0xcc, 0xff},
color.RGBA{0x66, 0x00, 0x00, 0xff},
color.RGBA{0x66, 0x00, 0x33, 0xff},
color.RGBA{0x66, 0x00, 0x66, 0xff},
color.RGBA{0x66, 0x00, 0x99, 0xff},
color.RGBA{0x66, 0x00, 0xcc, 0xff},
color.RGBA{0x66, 0x33, 0x00, 0xff},
color.RGBA{0x66, 0x33, 0x33, 0xff},
color.RGBA{0x66, 0x33, 0x66, 0xff},
color.RGBA{0x66, 0x33, 0x99, 0xff},
color.RGBA{0x66, 0x33, 0xcc, 0xff},
color.RGBA{0x66, 0x66, 0x00, 0xff},
color.RGBA{0x66, 0x66, 0x33, 0xff},
color.RGBA{0x66, 0x66, 0x66, 0xff},
color.RGBA{0x66, 0x66, 0x99, 0xff},
color.RGBA{0x66, 0x66, 0xcc, 0xff},
color.RGBA{0x66, 0x99, 0x00, 0xff},
color.RGBA{0x66, 0x99, 0x33, 0xff},
color.RGBA{0x66, 0x99, 0x66, 0xff},
color.RGBA{0x66, 0x99, 0x99, 0xff},
color.RGBA{0x66, 0x99, 0xcc, 0xff},
color.RGBA{0x66, 0xcc, 0x00, 0xff},
color.RGBA{0x66, 0xcc, 0x33, 0xff},
color.RGBA{0x66, 0xcc, 0x66, 0xff},
color.RGBA{0x66, 0xcc, 0x99, 0xff},
color.RGBA{0x66, 0xcc, 0xcc, 0xff},
color.RGBA{0x99, 0x00, 0x00, 0xff},
color.RGBA{0x99, 0x00, 0x33, 0xff},
color.RGBA{0x99, 0x00, 0x66, 0xff},
color.RGBA{0x99, 0x00, 0x99, 0xff},
color.RGBA{0x99, 0x00, 0xcc, 0xff},
color.RGBA{0x99, 0x33, 0x00, 0xff},
color.RGBA{0x99, 0x33, 0x33, 0xff},
color.RGBA{0x99, 0x33, 0x66, 0xff},
color.RGBA{0x99, 0x33, 0x99, 0xff},
color.RGBA{0x99, 0x33, 0xcc, 0xff},
color.RGBA{0x99, 0x66, 0x00, 0xff},
color.RGBA{0x99, 0x66, 0x33, 0xff},
color.RGBA{0x99, 0x66, 0x66, 0xff},
color.RGBA{0x99, 0x66, 0x99, 0xff},
color.RGBA{0x99, 0x66, 0xcc, 0xff},
color.RGBA{0x99, 0x99, 0x00, 0xff},
color.RGBA{0x99, 0x99, 0x33, 0xff},
color.RGBA{0x99, 0x99, 0x66, 0xff},
color.RGBA{0x99, 0x99, 0x99, 0xff},
color.RGBA{0x99, 0x99, 0xcc, 0xff},
color.RGBA{0x99, 0xcc, 0x00, 0xff},
color.RGBA{0x99, 0xcc, 0x33, 0xff},
color.RGBA{0x99, 0xcc, 0x66, 0xff},
color.RGBA{0x99, 0xcc, 0x99, 0xff},
color.RGBA{0x99, 0xcc, 0xcc, 0xff},
color.RGBA{0xcc, 0x00, 0x00, 0xff},
color.RGBA{0xcc, 0x00, 0x33, 0xff},
color.RGBA{0xcc, 0x00, 0x66, 0xff},
color.RGBA{0xcc, 0x00, 0x99, 0xff},
color.RGBA{0xcc, 0x00, 0xcc, 0xff},
color.RGBA{0xcc, 0x33, 0x00, 0xff},
color.RGBA{0xcc, 0x33, 0x33, 0xff},
color.RGBA{0xcc, 0x33, 0x66, 0xff},
color.RGBA{0xcc, 0x33, 0x99, 0xff},
color.RGBA{0xcc, 0x33, 0xcc, 0xff},
color.RGBA{0xcc, 0x66, 0x00, 0xff},
color.RGBA{0xcc, 0x66, 0x33, 0xff},
color.RGBA{0xcc, 0x66, 0x66, 0xff},
color.RGBA{0xcc, 0x66, 0x99, 0xff},
color.RGBA{0xcc, 0x66, 0xcc, 0xff},
color.RGBA{0xcc, 0x99, 0x00, 0xff},
color.RGBA{0xcc, 0x99, 0x33, 0xff},
color.RGBA{0xcc, 0x99, 0x66, 0xff},
color.RGBA{0xcc, 0x99, 0x99, 0xff},
color.RGBA{0xcc, 0x99, 0xcc, 0xff},
color.RGBA{0xcc, 0xcc, 0x00, 0xff},
color.RGBA{0xcc, 0xcc, 0x33, 0xff},
color.RGBA{0xcc, 0xcc, 0x66, 0xff},
color.RGBA{0xcc, 0xcc, 0x99, 0xff},
color.RGBA{0xcc, 0xcc, 0xcc, 0xff},
}
141 changes: 141 additions & 0 deletions modules/avatar/identicon/identicon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

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

package identicon

import (
"crypto/sha256"
"fmt"
"image"
"image/color"
)

const minImageSize = 16

// Identicon is used to generate pseudo-random avatars
type Identicon struct {
foreColors []color.Color
backColor color.Color
size int
rect image.Rectangle
}

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

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

return &Identicon{
foreColors: fore,
backColor: back,
size: size,
rect: image.Rect(0, 0, size, size),
}, nil
}

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

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

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

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

/*
# Algorithm
Origin: An image is splitted into 9 areas
```
-------------
| 1 | 2 | 3 |
-------------
| 4 | 5 | 6 |
-------------
| 7 | 8 | 9 |
-------------
```
Area 1/3/9/7 use a 90-degree rotating pattern.
Area 1/3/9/7 use another 90-degree rotating pattern.
Area 5 uses a random patter.
The Patched Fix: make the image left-right mirrored to get rid of something like "swastika"
*/

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

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

blockSize := size / 3
twoBlockSize := 2 * blockSize

// center
c(p, blockSize+padding, blockSize+padding, blockSize, 0)

// left top (1)
b1(p, 0+padding, 0+padding, blockSize, b1Angle)
// center top (2)
b2(p, blockSize+padding, 0+padding, blockSize, b2Angle)

b1Angle = nextAngle(b1Angle)
b2Angle = nextAngle(b2Angle)
// right top (3)
// b1(p, twoBlockSize+padding, 0+padding, blockSize, b1Angle)
// right middle (6)
// b2(p, twoBlockSize+padding, blockSize+padding, blockSize, b2Angle)

b1Angle = nextAngle(b1Angle)
b2Angle = nextAngle(b2Angle)
// right bottom (9)
// b1(p, twoBlockSize+padding, twoBlockSize+padding, blockSize, b1Angle)
// center bottom (8)
b2(p, blockSize+padding, twoBlockSize+padding, blockSize, b2Angle)

b1Angle = nextAngle(b1Angle)
b2Angle = nextAngle(b2Angle)
// lef bottom (7)
b1(p, 0+padding, twoBlockSize+padding, blockSize, b1Angle)
// left middle (4)
b2(p, 0+padding, blockSize+padding, blockSize, b2Angle)

// then we make it left-right mirror, so we didn't draw 3/6/9 before
for x := 0; x < size/2; x++ {
for y := 0; y < size; y++ {
p.SetColorIndex(size-x, y, p.ColorIndexAt(x, y))
}
}
}
42 changes: 42 additions & 0 deletions modules/avatar/identicon/identicon_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

//go:build test_avatar_identicon
// +build test_avatar_identicon

package identicon

import (
"image/color"
"image/png"
"os"
"strconv"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGenerate(t *testing.T) {
dir, _ := os.Getwd()
dir = dir + "/testdata"
if st, err := os.Stat(dir); err != nil || !st.IsDir() {
t.Errorf("can not save generated images to %s", dir)
}

backColor := color.White
imgMaker, err := New(64, backColor, DarkColors...)
assert.NoError(t, err)
for i := 0; i < 100; i++ {
s := strconv.Itoa(i)
img := imgMaker.Make([]byte(s))

f, err := os.Create(dir + "/" + s + ".png")
if !assert.NoError(t, err) {
continue
}
defer f.Close()
err = png.Encode(f, img)
assert.NoError(t, err)
}
}
69 changes: 69 additions & 0 deletions modules/avatar/identicon/polygon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

// Copied and modified from https://github.com/issue9/identicon/ (MIT License)

package identicon

var (
// cos(0),cos(90),cos(180),cos(270)
cos = []int{1, 0, -1, 0}

// sin(0),sin(90),sin(180),sin(270)
sin = []int{0, 1, 0, -1}
)

// rotate the points by center point (x,y)
// angle: [0,1,2,3] means [0,90,180,270] degree
func rotate(points []int, x, y int, angle int) {
// the angle is only used internally, and it has been guaranteed to be 0/1/2/3, so we do not check it again
for i := 0; i < len(points); i += 2 {
px, py := points[i]-x, points[i+1]-y
points[i] = px*cos[angle] - py*sin[angle] + x
points[i+1] = px*sin[angle] + py*cos[angle] + y
}
}

// check whether the point is inside the polygon (defined by the points)
// the first and the last point must be the same
func pointInPolygon(x, y int, polygonPoints []int) bool {
if len(polygonPoints) < 8 { // a valid polygon must have more than 2 points
return false
}

// reference: nonzero winding rule, https://en.wikipedia.org/wiki/Nonzero-rule
// split the plane into two by the check point horizontally:
// y>0,includes (x>0 && y==0)
// y<0,includes (x<0 && y==0)
//
// then scan every point in the polygon.
//
// if current point and previous point are in different planes (eg: curY>0 && prevY<0),
// check the clock-direction from previous point to current point (use check point as origin).
// if the direction is clockwise, then r++, otherwise then r--
// finally, if 2==abs(r), then the check point is inside the polygon

r := 0
prevX, prevY := polygonPoints[0], polygonPoints[1]
prev := (prevY > y) || ((prevX > x) && (prevY == y))
for i := 2; i < len(polygonPoints); i += 2 {
currX, currY := polygonPoints[i], polygonPoints[i+1]
curr := (currY > y) || ((currX > x) && (currY == y))

if curr == prev {
prevX, prevY = currX, currY
continue
}

if mul := (prevX-x)*(currY-y) - (currX-x)*(prevY-y); mul >= 0 {
r++
} else { // mul < 0
r--
}
prevX, prevY = currX, currY
prev = curr
}

return r == 2 || r == -2
}
1 change: 1 addition & 0 deletions modules/avatar/identicon/testdata/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
23 changes: 0 additions & 23 deletions vendor/github.com/issue9/identicon/.gitignore

This file was deleted.

22 changes: 0 additions & 22 deletions vendor/github.com/issue9/identicon/LICENSE

This file was deleted.

38 changes: 0 additions & 38 deletions vendor/github.com/issue9/identicon/README.md

This file was deleted.

35 changes: 0 additions & 35 deletions vendor/github.com/issue9/identicon/doc.go

This file was deleted.

5 changes: 0 additions & 5 deletions vendor/github.com/issue9/identicon/go.mod

This file was deleted.

2 changes: 0 additions & 2 deletions vendor/github.com/issue9/identicon/go.sum

This file was deleted.

137 changes: 0 additions & 137 deletions vendor/github.com/issue9/identicon/identicon.go

This file was deleted.

65 changes: 0 additions & 65 deletions vendor/github.com/issue9/identicon/polygon.go

This file was deleted.

3 changes: 0 additions & 3 deletions vendor/modules.txt
Original file line number Diff line number Diff line change
@@ -507,9 +507,6 @@ github.com/hashicorp/hcl/json/token
github.com/huandu/xstrings
# github.com/imdario/mergo v0.3.12
github.com/imdario/mergo
# github.com/issue9/identicon v1.2.0
## explicit
github.com/issue9/identicon
# github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
## explicit
github.com/jaytaylor/html2text