mirror of https://github.com/gogits/gogs.git
Browse Source
# Conflicts: # modules/bindata/bindata.go # public/css/gogs.min.css # templates/repo/header.tmplpull/1466/head
Unknwon
9 years ago
31 changed files with 1233 additions and 459 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,405 @@
|
||||
// Copyright 2015 by caixw, All rights reserved
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package identicon |
||||
|
||||
import ( |
||||
"image" |
||||
) |
||||
|
||||
var ( |
||||
// 可以出现在中间的方块,一般为了美观,都是对称图像。
|
||||
centerBlocks = []blockFunc{b0, b1, b2, b3} |
||||
|
||||
// 所有方块
|
||||
blocks = []blockFunc{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16} |
||||
) |
||||
|
||||
// 所有block函数的类型
|
||||
type blockFunc func(img *image.Paletted, x, y, size float64, angle int) |
||||
|
||||
// 将多边形points旋转angle个角度,然后输出到img上,起点为x,y坐标
|
||||
func drawBlock(img *image.Paletted, x, y, size float64, angle int, points []float64) { |
||||
if angle > 0 { // 0角度不需要转换
|
||||
// 中心坐标与x,y的距离,方便下面指定中心坐标(x+m,y+m),
|
||||
// 0.5的偏移值不能少,否则坐靠右,非正中央
|
||||
m := size/2 - 0.5 |
||||
rotate(points, x+m, y+m, angle) |
||||
} |
||||
|
||||
for i := x; i < x+size; i++ { |
||||
for j := y; j < y+size; j++ { |
||||
if pointInPolygon(i, j, points) { |
||||
img.SetColorIndex(int(i), int(j), 1) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 全空白
|
||||
//
|
||||
// --------
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// --------
|
||||
func b0(img *image.Paletted, x, y, size float64, angle int) { |
||||
} |
||||
|
||||
// 全填充正方形
|
||||
//
|
||||
// --------
|
||||
// |######|
|
||||
// |######|
|
||||
// |######|
|
||||
// --------
|
||||
func b1(img *image.Paletted, x, y, size float64, angle int) { |
||||
isize := int(size) |
||||
ix := int(x) |
||||
iy := int(y) |
||||
for i := ix + 1; i < ix+isize; i++ { |
||||
for j := iy + 1; j < iy+isize; j++ { |
||||
img.SetColorIndex(i, j, 1) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 中间小方块
|
||||
// ----------
|
||||
// | |
|
||||
// | #### |
|
||||
// | #### |
|
||||
// | |
|
||||
// ----------
|
||||
func b2(img *image.Paletted, x, y, size float64, angle int) { |
||||
l := size / 4 |
||||
x = x + l |
||||
y = y + l |
||||
|
||||
for i := x; i < x+2*l; i++ { |
||||
for j := y; j < y+2*l; j++ { |
||||
img.SetColorIndex(int(i), int(j), 1) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 菱形
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | ##### |
|
||||
// | ### |
|
||||
// | # |
|
||||
// ---------
|
||||
func b3(img *image.Paletted, x, y, size float64, angle int) { |
||||
m := size / 2 |
||||
points := []float64{} |
||||
|
||||
drawBlock(img, x, y, size, 0, append(points, |
||||
x+m, y, |
||||
x+size, y+m, |
||||
x+m, y+size, |
||||
x, y+m, |
||||
x+m, y, |
||||
)) |
||||
} |
||||
|
||||
// b4
|
||||
//
|
||||
// -------
|
||||
// |#####|
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// |------
|
||||
func b4(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+size, y, |
||||
x, y+size, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b5
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
func b5(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y, |
||||
x+size, |
||||
y+size, |
||||
x, y+size, |
||||
x+m, y, |
||||
)) |
||||
} |
||||
|
||||
// b6 矩形
|
||||
//
|
||||
// --------
|
||||
// |### |
|
||||
// |### |
|
||||
// |### |
|
||||
// --------
|
||||
func b6(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+m, y, |
||||
x+m, y+size, |
||||
x, y+size, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b7 斜放的锥形
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ## |
|
||||
// | #####|
|
||||
// | ####|
|
||||
// |--------
|
||||
func b7(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+size, y+m, |
||||
x+size, y+size, |
||||
x+m, y+size, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b8 三个堆叠的三角形
|
||||
//
|
||||
// -----------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// | # # |
|
||||
// | ### ### |
|
||||
// |#########|
|
||||
// -----------
|
||||
func b8(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
mm := m / 2 |
||||
|
||||
// 顶部三角形
|
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y, |
||||
x+3*mm, y+m, |
||||
x+mm, y+m, |
||||
x+m, y, |
||||
)) |
||||
|
||||
// 底下左边
|
||||
drawBlock(img, x, y, size, angle, append(points[:0], |
||||
x+mm, y+m, |
||||
x+m, y+size, |
||||
x, y+size, |
||||
x+mm, y+m, |
||||
)) |
||||
|
||||
// 底下右边
|
||||
drawBlock(img, x, y, size, angle, append(points[:0], |
||||
x+3*mm, y+m, |
||||
x+size, y+size, |
||||
x+m, y+size, |
||||
x+3*mm, y+m, |
||||
)) |
||||
} |
||||
|
||||
// b9 斜靠的三角形
|
||||
//
|
||||
// ---------
|
||||
// |# |
|
||||
// | #### |
|
||||
// | #####|
|
||||
// | #### |
|
||||
// | # |
|
||||
// ---------
|
||||
func b9(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+size, y+m, |
||||
x+m, y+size, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b10
|
||||
//
|
||||
// ----------
|
||||
// | ####|
|
||||
// | ### |
|
||||
// | ## |
|
||||
// | # |
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b10(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y, |
||||
x+size, y, |
||||
x+m, y+m, |
||||
x+m, y, |
||||
)) |
||||
|
||||
drawBlock(img, x, y, size, angle, append(points[:0], |
||||
x, y+m, |
||||
x+m, y+m, |
||||
x, y+size, |
||||
x, y+m, |
||||
)) |
||||
} |
||||
|
||||
// b11 左上角1/4大小的方块
|
||||
//
|
||||
// ----------
|
||||
// |#### |
|
||||
// |#### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
func b11(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+m, y, |
||||
x+m, y+m, |
||||
x, y+m, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b12
|
||||
//
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// |#########|
|
||||
// | ##### |
|
||||
// | # |
|
||||
// -----------
|
||||
func b12(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y+m, |
||||
x+size, y+m, |
||||
x+m, y+size, |
||||
x, y+m, |
||||
)) |
||||
} |
||||
|
||||
// b13
|
||||
//
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#########|
|
||||
// -----------
|
||||
func b13(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y+m, |
||||
x+size, y+size, |
||||
x, y+size, |
||||
x+m, y+m, |
||||
)) |
||||
} |
||||
|
||||
// b14
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ---------
|
||||
func b14(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y, |
||||
x+m, y+m, |
||||
x, y+m, |
||||
x+m, y, |
||||
)) |
||||
} |
||||
|
||||
// b15
|
||||
//
|
||||
// ----------
|
||||
// |##### |
|
||||
// |### |
|
||||
// |# |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
func b15(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x, y, |
||||
x+m, y, |
||||
x, y+m, |
||||
x, y, |
||||
)) |
||||
} |
||||
|
||||
// b16
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// ---------
|
||||
func b16(img *image.Paletted, x, y, size float64, angle int) { |
||||
points := []float64{} |
||||
m := size / 2 |
||||
drawBlock(img, x, y, size, angle, append(points, |
||||
x+m, y, |
||||
x+size, y+m, |
||||
x, y+m, |
||||
x+m, y, |
||||
)) |
||||
|
||||
drawBlock(img, x, y, size, angle, append(points[:0], |
||||
x+m, y+m, |
||||
x+size, y+size, |
||||
x, y+size, |
||||
x+m, y+m, |
||||
)) |
||||
} |
@ -0,0 +1,39 @@
|
||||
// Copyright 2015 by caixw, All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// 一个基于hash值生成随机图像的包。
|
||||
//
|
||||
// 关于identicon并没有统一的标准,一般用于在用户注册时,
|
||||
// 取用户的邮箱或是访问IP等数据(也可以是其它任何数据),
|
||||
// 进行hash运算,之后根据hash数据,产生一张图像,
|
||||
// 这样即可以为用户产生一张独特的头像,又不会泄漏用户的隐藏。
|
||||
//
|
||||
// 在identicon中,把图像分成以下九个部分:
|
||||
// -------------
|
||||
// | 1 | 2 | 3 |
|
||||
// -------------
|
||||
// | 4 | 5 | 6 |
|
||||
// -------------
|
||||
// | 7 | 8 | 9 |
|
||||
// -------------
|
||||
// 其中1、3、9、7为不同角度(依次增加90度)的同一张图片,
|
||||
// 2、6、8、4也是如此,这样可以保持图像是对称的,比较美观。
|
||||
// 5则单独使用一张图片。
|
||||
//
|
||||
// // 根据用户访问的IP,为其生成一张头像
|
||||
// img, _ := identicon.Make(128, color.NRGBA{},color.NRGBA{}, []byte("192.168.1.1"))
|
||||
// fi, _ := os.Create("/tmp/u1.png")
|
||||
// png.Encode(fi, img)
|
||||
// fi.Close()
|
||||
//
|
||||
// // 或者
|
||||
// ii, _ := identicon.New(128, color.NRGBA{}, color.NRGBA{}, color.NRGBA{})
|
||||
// img := ii.Make([]byte("192.168.1.1"))
|
||||
// img = ii.Make([]byte("192.168.1.2"))
|
||||
//
|
||||
// NOTE: go test 会在当前目录的testdata文件夹下产生大量的随机图片。
|
||||
// 要运行测试,必须保证该文件夹是存在的,且有相应的写入权限。
|
||||
package identicon |
||||
|
||||
const Version = "0.2.6.150603" |
@ -0,0 +1,147 @@
|
||||
// Copyright 2015 by caixw, All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package identicon |
||||
|
||||
import ( |
||||
"crypto/md5" |
||||
"fmt" |
||||
"image" |
||||
"image/color" |
||||
) |
||||
|
||||
const ( |
||||
minSize = 16 // 图片的最小尺寸
|
||||
maxForeColors = 32 // 在New()函数中可以指定的最大颜色数量
|
||||
) |
||||
|
||||
// Identicon 用于产生统一尺寸的头像。
|
||||
// 可以根据用户提供的数据,经过一定的算法,自动产生相应的图案和颜色。
|
||||
type Identicon struct { |
||||
foreColors []color.Color |
||||
backColor color.Color |
||||
size int |
||||
rect image.Rectangle |
||||
} |
||||
|
||||
// 声明一个Identicon实例。
|
||||
// size表示整个头像的大小。
|
||||
// back表示前景色。
|
||||
// fore表示所有可能的前景色,会为每个图像随机挑选一个作为其前景色。
|
||||
// NOTE:前景色不要与背景色太相近。
|
||||
func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) { |
||||
if len(fore) == 0 || len(fore) > maxForeColors { |
||||
return nil, fmt.Errorf("前景色数量必须介于[1]~[%v]之间,当前为[%v]", maxForeColors, len(fore)) |
||||
} |
||||
|
||||
if size < minSize { |
||||
return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize) |
||||
} |
||||
|
||||
return &Identicon{ |
||||
foreColors: fore, |
||||
backColor: back, |
||||
size: size, |
||||
|
||||
// 画布坐标从0开始,其长度应该是size-1
|
||||
rect: image.Rect(0, 0, size, size), |
||||
}, nil |
||||
} |
||||
|
||||
// 根据data数据产生一张唯一性的头像图片。
|
||||
func (i *Identicon) Make(data []byte) image.Image { |
||||
h := md5.New() |
||||
h.Write(data) |
||||
sum := h.Sum(nil) |
||||
|
||||
// 第一个方块
|
||||
index := int(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks) |
||||
b1 := blocks[index] |
||||
|
||||
// 第二个方块
|
||||
index = int(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks) |
||||
b2 := blocks[index] |
||||
|
||||
// 中间方块
|
||||
index = int(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks) |
||||
c := centerBlocks[index] |
||||
|
||||
// 旋转角度
|
||||
angle := int(sum[12]+sum[13]+sum[14]) % 4 |
||||
|
||||
// 根据最后一个字段,获取前景颜色
|
||||
index = int(sum[15]) % len(i.foreColors) |
||||
|
||||
p := image.NewPaletted(i.rect, []color.Color{i.backColor, i.foreColors[index]}) |
||||
drawBlocks(p, i.size, c, b1, b2, angle) |
||||
return p |
||||
} |
||||
|
||||
// 根据data数据产生一张唯一性的头像图片。
|
||||
// size 头像的大小。
|
||||
// back, fore头像的背景和前景色。
|
||||
func Make(size int, back, fore color.Color, data []byte) (image.Image, error) { |
||||
if size < minSize { |
||||
return nil, fmt.Errorf("参数size的值(%v)不能小于%v", size, minSize) |
||||
} |
||||
|
||||
h := md5.New() |
||||
h.Write(data) |
||||
sum := h.Sum(nil) |
||||
|
||||
// 第一个方块
|
||||
index := int(sum[0]+sum[1]+sum[2]+sum[3]) % len(blocks) |
||||
b1 := blocks[index] |
||||
|
||||
// 第二个方块
|
||||
index = int(sum[4]+sum[5]+sum[6]+sum[7]) % len(blocks) |
||||
b2 := blocks[index] |
||||
|
||||
// 中间方块
|
||||
index = int(sum[8]+sum[9]+sum[10]+sum[11]) % len(centerBlocks) |
||||
c := centerBlocks[index] |
||||
|
||||
// 旋转角度
|
||||
angle := int(sum[12]+sum[13]+sum[14]+sum[15]) % 4 |
||||
|
||||
// 画布坐标从0开始,其长度应该是size-1
|
||||
p := image.NewPaletted(image.Rect(0, 0, size, size), []color.Color{back, fore}) |
||||
drawBlocks(p, size, c, b1, b2, angle) |
||||
return p, nil |
||||
} |
||||
|
||||
// 将九个方格都填上内容。
|
||||
// p为画板。
|
||||
// c为中间方格的填充函数。
|
||||
// b1,b2为边上8格的填充函数。
|
||||
// angle为b1,b2的起始旋转角度。
|
||||
func drawBlocks(p *image.Paletted, size int, c, b1, b2 blockFunc, angle int) { |
||||
// 每个格子的长宽。先转换成float,再计算!
|
||||
blockSize := float64(size) / 3 |
||||
twoBlockSize := 2 * blockSize |
||||
|
||||
incr := func() { // 增加angle的值,但不会大于3
|
||||
angle++ |
||||
if angle > 3 { |
||||
angle = 0 |
||||
} |
||||
} |
||||
|
||||
c(p, blockSize, blockSize, blockSize, 0) |
||||
|
||||
b1(p, 0, 0, blockSize, angle) |
||||
b2(p, blockSize, 0, blockSize, angle) |
||||
|
||||
incr() |
||||
b1(p, twoBlockSize, 0, blockSize, angle) |
||||
b2(p, twoBlockSize, blockSize, blockSize, angle) |
||||
|
||||
incr() |
||||
b1(p, twoBlockSize, twoBlockSize, blockSize, angle) |
||||
b2(p, blockSize, twoBlockSize, blockSize, angle) |
||||
|
||||
incr() |
||||
b1(p, 0, twoBlockSize, blockSize, angle) |
||||
b2(p, 0, blockSize, blockSize, angle) |
||||
} |
@ -0,0 +1,114 @@
|
||||
// Copyright 2015 by caixw, All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package identicon |
||||
|
||||
import ( |
||||
"image" |
||||
"image/color" |
||||
"image/png" |
||||
"os" |
||||
"strconv" |
||||
"testing" |
||||
|
||||
"github.com/issue9/assert" |
||||
) |
||||
|
||||
var ( |
||||
back = color.RGBA{255, 0, 0, 100} |
||||
fore = color.RGBA{0, 255, 255, 100} |
||||
fores = []color.Color{color.Black, color.RGBA{200, 2, 5, 100}, color.RGBA{2, 200, 5, 100}} |
||||
size = 128 |
||||
) |
||||
|
||||
// 依次画出各个网络的图像。
|
||||
func TestBlocks(t *testing.T) { |
||||
p := []color.Color{back, fore} |
||||
|
||||
a := assert.New(t) |
||||
|
||||
for k, v := range blocks { |
||||
img := image.NewPaletted(image.Rect(0, 0, size*4, size), p) // 横向4张图片大小
|
||||
|
||||
for i := 0; i < 4; i++ { |
||||
v(img, float64(i*size), 0, float64(size), i) |
||||
} |
||||
|
||||
fi, err := os.Create("./testdata/block-" + strconv.Itoa(k) + ".png") |
||||
a.NotError(err).NotNil(fi) |
||||
a.NotError(png.Encode(fi, img)) |
||||
a.NotError(fi.Close()) // 关闭文件
|
||||
} |
||||
} |
||||
|
||||
// 产生一组测试图片
|
||||
func TestDrawBlocks(t *testing.T) { |
||||
a := assert.New(t) |
||||
|
||||
for i := 0; i < 20; i++ { |
||||
p := image.NewPaletted(image.Rect(0, 0, size, size), []color.Color{back, fore}) |
||||
c := (i + 1) % len(centerBlocks) |
||||
b1 := (i + 2) % len(blocks) |
||||
b2 := (i + 3) % len(blocks) |
||||
drawBlocks(p, size, centerBlocks[c], blocks[b1], blocks[b2], 0) |
||||
|
||||
fi, err := os.Create("./testdata/draw-" + strconv.Itoa(i) + ".png") |
||||
a.NotError(err).NotNil(fi) |
||||
a.NotError(png.Encode(fi, p)) |
||||
a.NotError(fi.Close()) // 关闭文件
|
||||
} |
||||
} |
||||
|
||||
func TestMake(t *testing.T) { |
||||
a := assert.New(t) |
||||
|
||||
for i := 0; i < 20; i++ { |
||||
img, err := Make(size, back, fore, []byte("make-"+strconv.Itoa(i))) |
||||
a.NotError(err).NotNil(img) |
||||
|
||||
fi, err := os.Create("./testdata/make-" + strconv.Itoa(i) + ".png") |
||||
a.NotError(err).NotNil(fi) |
||||
a.NotError(png.Encode(fi, img)) |
||||
a.NotError(fi.Close()) // 关闭文件
|
||||
} |
||||
} |
||||
|
||||
func TestIdenticon(t *testing.T) { |
||||
a := assert.New(t) |
||||
|
||||
ii, err := New(size, back, fores...) |
||||
a.NotError(err).NotNil(ii) |
||||
|
||||
for i := 0; i < 20; i++ { |
||||
img := ii.Make([]byte("identicon-" + strconv.Itoa(i))) |
||||
a.NotNil(img) |
||||
|
||||
fi, err := os.Create("./testdata/identicon-" + strconv.Itoa(i) + ".png") |
||||
a.NotError(err).NotNil(fi) |
||||
a.NotError(png.Encode(fi, img)) |
||||
a.NotError(fi.Close()) // 关闭文件
|
||||
} |
||||
} |
||||
|
||||
// BenchmarkMake 5000 229378 ns/op
|
||||
func BenchmarkMake(b *testing.B) { |
||||
a := assert.New(b) |
||||
for i := 0; i < b.N; i++ { |
||||
img, err := Make(size, back, fore, []byte("Make")) |
||||
a.NotError(err).NotNil(img) |
||||
} |
||||
} |
||||
|
||||
// BenchmarkIdenticon_Make 10000 222127 ns/op
|
||||
func BenchmarkIdenticon_Make(b *testing.B) { |
||||
a := assert.New(b) |
||||
|
||||
ii, err := New(size, back, fores...) |
||||
a.NotError(err).NotNil(ii) |
||||
|
||||
for i := 0; i < b.N; i++ { |
||||
img := ii.Make([]byte("Make")) |
||||
a.NotNil(img) |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
// Copyright 2015 by caixw, All rights reserved.
|
||||
// Use of this source code is governed by a MIT
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package identicon |
||||
|
||||
var ( |
||||
// 4个元素分别表示cos(0),cos(90),cos(180),cos(270)
|
||||
cos = []float64{1, 0, -1, 0} |
||||
|
||||
// 4个元素分别表示sin(0),sin(90),sin(180),sin(270)
|
||||
sin = []float64{0, 1, 0, -1} |
||||
) |
||||
|
||||
// 将points中的所有点,以x,y为原点旋转angle个角度。
|
||||
// angle取值只能是[0,1,2,3],分别表示[0,90,180,270]
|
||||
func rotate(points []float64, x, y float64, angle int) { |
||||
if angle > 3 { |
||||
panic("rotate:参数angle必须0,1,2,3三值之一") |
||||
} |
||||
|
||||
for i := 0; i < len(points); i += 2 { |
||||
px := points[i] - x |
||||
py := points[i+1] - y |
||||
points[i] = px*cos[angle] - py*sin[angle] + x |
||||
points[i+1] = px*sin[angle] + py*cos[angle] + y |
||||
} |
||||
} |
||||
|
||||
// 判断某个点是否在多边形之内,不包含构成多边形的线和点
|
||||
// x,y 需要判断的点坐标
|
||||
// points 组成多边形的所顶点,每两个元素表示一点顶点,其中最后一个顶点必须与第一个顶点相同。
|
||||
func pointInPolygon(x float64, y float64, points []float64) bool { |
||||
if len(points) < 8 { // 只有2个以上的点,才能组成闭合多边形
|
||||
return false |
||||
} |
||||
|
||||
// 大致算法如下:
|
||||
// 把整个平面以给定的测试点为原点分两部分:
|
||||
// - y>0,包含(x>0 && y==0)
|
||||
// - y<0,包含(x<0 && y==0)
|
||||
// 依次扫描每一个点,当该点与前一个点处于不同部分时(即一个在y>0区,一个在y<0区),
|
||||
// 则判断从前一点到当前点是顺时针还是逆时针(以给定的测试点为原点),如果是顺时针r++,否则r--。
|
||||
// 结果为:2==abs(r)。
|
||||
|
||||
r := 0 |
||||
x1, y1 := points[0], points[1] |
||||
prev := (y1 > y) || ((x1 > x) && (y1 == y)) |
||||
for i := 2; i < len(points); i += 2 { |
||||
x2, y2 := points[i], points[i+1] |
||||
curr := (y2 > y) || ((x2 > x) && (y2 == y)) |
||||
|
||||
if curr == prev { |
||||
x1, y1 = x2, y2 |
||||
continue |
||||
} |
||||
|
||||
mul := (x1-x)*(y2-y) - (x2-x)*(y1-y) |
||||
if mul > 0 { |
||||
r++ |
||||
} else if mul < 0 { |
||||
r-- |
||||
} |
||||
x1, y1 = x2, y2 |
||||
prev = curr |
||||
} |
||||
|
||||
return r == 2 || r == -2 |
||||
} |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,5 +0,0 @@
|
||||
{{if .Flash}} |
||||
<div class="sixteen wide center aligned centered column"> |
||||
{{template "base/alert" .}} |
||||
</div> |
||||
{{end}} |
@ -1,7 +1,5 @@
|
||||
<div class="ui left"> |
||||
<div class="ui compact menu"> |
||||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> |
||||
<a class="{{if .PageIsLabels}}active{{end}} item" href="{{.RepoLink}}/labels">{{.i18n.Tr "repo.labels"}}</a> |
||||
<a class="{{if .PageIsMilestones}}active{{end}} item" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> |
||||
</div> |
||||
<div class="ui compact small menu"> |
||||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">{{.i18n.Tr "repo.issues"}}</a> |
||||
<a class="{{if .PageIsLabels}}active{{end}} item" href="{{.RepoLink}}/labels">{{.i18n.Tr "repo.labels"}}</a> |
||||
<a class="{{if .PageIsMilestones}}active{{end}} item" href="{{.RepoLink}}/milestones">{{.i18n.Tr "repo.milestones"}}</a> |
||||
</div> |
Loading…
Reference in new issue