mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +09:00
Merge branch 'develop' of github.com:gogits/gogs into feature/pull_request2
# Conflicts: # modules/bindata/bindata.go # public/css/gogs.min.css # templates/repo/header.tmpl
This commit is contained in:
commit
a79586cc54
31 files changed
+1240
-466
No files matched your search
@@ -19,9 +19,11 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color/palette"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -32,6 +34,7 @@ import (
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
"github.com/gogits/gogs/modules/identicon"
|
||||
"github.com/gogits/gogs/modules/log"
|
||||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
@@ -59,6 +62,27 @@ func HashEmail(email string) string {
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
const _RANDOM_AVATAR_SIZE = 200
|
||||
|
||||
// RandomImage generates and returns a random avatar image.
|
||||
func RandomImage(data []byte) (image.Image, error) {
|
||||
randExtent := len(palette.WebSafe) - 32
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
colorIndex := rand.Intn(randExtent)
|
||||
backColorIndex := colorIndex - 1
|
||||
if backColorIndex < 0 {
|
||||
backColorIndex = randExtent - 1
|
||||
}
|
||||
|
||||
// Size, background, forecolor
|
||||
imgMaker, err := identicon.New(_RANDOM_AVATAR_SIZE,
|
||||
palette.WebSafe[backColorIndex], palette.WebSafe[colorIndex:colorIndex+32]...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return imgMaker.Make(data), nil
|
||||
}
|
||||
|
||||
// Avatar represents the avatar object.
|
||||
type Avatar struct {
|
||||
Hash string
|
||||
|
||||
@@ -772,7 +772,7 @@ func confLocaleLocale_deDeIni() (*asset, error) {
|
||||
return a, nil
|
||||
}
|
||||
|
||||
var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x7d\xeb\x72\xdc\x46\xb2\xe6\x7f\x3c\x05\xac\x0d\xad\xec\x08\xaa\x15\xb6\x63\x2f\xe1\x90\xe4\xa5\x49\xeb\x32\x47\x14\x75\x44\x6a\x66\x67\x15\x0a\x0c\xba\x01\x76\x63\xd4\x0d\xb4\x71\x61\x9b\xf3\x6b\x5f\x63\x5f\x6f\x9f\x64\x33\xbf\xcc\xac\x0b\x80\xa6\xe4\x39\x27\xf6\xfc\x21\xab\xab\xb2\x6e\x59\x59\x59\x79\xab\x42\xbe\xdf\x67\x45\xd9\xad\xd2\x67\xe9\x69\xba\xcf\xab\x7a\x5b\x76\x5d\xda\x95\xdb\x9b\xc7\x9b\xa6\xeb\xcb\x22\x7d\x59\xf5\xf4\xbb\xbd\xad\x56\x65\x92\x6c\x9a\x5d\x49\xa0\xaf\xe8\x5f\x52\xe4\xdd\x66\xd9\xe4\x6d\x41\x19\xe7\x96\x4e\xca\xdf\xf7\xdb\xa6\x65\xa0\x5f\x25\x95\x6c\xca\xed\x9e\xeb\xd0\xbf\xa4\xab\xd6\x75\x56\xd5\xf4\xf3\x8a\x52\xe9\xeb\x3a\xe9\x9a\x55\x95\x6f\xb3\xa0\x00\x19\x56\xfe\x53\xfa\x43\x5d\xa4\x57\x7d\xb9\x4f\x9f\x76\xbb\x7c\xbb\x7d\x9e\x77\xa8\xd2\x97\x69\xbe\x5a\x35\x43\xdd\x3f\x7d\x22\x05\xd2\x78\x33\xf4\xd6\xfa\xe5\xd0\x4b\xde\xb0\xb7\xac\x0f\xfb\xa4\x2d\xd7\x15\x4d\xac\xa5\xac\xf7\x9a\x4c\x0e\xe5\xb2\xab\x7a\x1e\xf4\x5f\x24\x95\xdc\x96\x6d\x57\x35\x3c\x9e\x3f\x4b\x2a\xd9\xe7\x6b\x06\x78\x47\xff\x92\xbe\xdc\xed\xb7\x39\x2a\x5c\x6b\x32\xd9\xe6\xf5\x7a\x10\x98\x37\x9a\x4c\x92\x81\x30\x57\xe7\xc0\xd9\x07\x4d\x26\xe5\x2e\xaf\xb6\x8c\x9f\xc7\x9c\xa0\x76\xbb\xee\xd0\x00\x8b\xef\x34\x49\x63\xcc\xfa\xbb\x7d\x89\x21\x3e\xbe\xa6\x54\xb2\xca\xf7\xfd\x6a\x93\x53\xce\x99\xa4\x12\x02\xda\x37\x34\xd6\xa6\xbd\x03\x9c\xfd\x48\x9a\x76\x9d\xd7\xd5\x3f\xf2\x5e\xc6\x7f\x19\xfc\x4c\x76\x55\xdb\x36\x3c\xf5\x0b\x24\x92\xba\x3c\x64\xdc\x0e\xe5\xbc\x2d\x0f\x61\x2b\x5c\xb2\xab\xd6\xad\xcc\x92\x0b\x2f\xf0\x8b\x5b\xe1\xb2\x9b\xa6\xfd\xac\x05\x2f\x38\x39\xaa\x4a\x83\xd0\xd2\xb8\xff\xbc\x26\xbc\x68\xe9\x05\x7e\x44\x00\x5d\x92\x17\xbb\xaa\xce\xf6\x79\x5d\x32\x8e\x4e\xf9\x17\xe1\x85\x7e\x25\xba\xdc\x59\x57\xf6\x7d\x55\xaf\x3b\x2e\x96\xac\xf4\x4a\xb3\x92\xa0\xcc\xe5\xf1\x78\xba\xec\xa6\x2c\x0b\x19\x51\x97\xbe\xa0\x74\xb2\x1f\xb6\x5b\x9a\xfb\x6f\x43\xd9\xf5\x0c\xff\x8e\x7e\xd3\x2c\xe4\x77\x52\x75\x1d\x25\x28\xfb\x35\x12\x09\x2d\x40\xbd\xc2\x90\xce\x90\x48\x92\x8f\x5d\x99\xb7\xab\xcd\xa7\x44\xfe\xa3\x47\x4e\x2c\x16\x8b\xa3\x4b\xc3\xe4\xa0\xa4\x20\x3d\x58\x07\xc9\xaa\x29\xf8\xc7\x19\xfd\xa3\xa6\xab\xba\xeb\x89\xa4\x3f\x25\x9a\x60\x30\x49\x09\x1a\xfb\xaa\xdf\x96\x3e\x13\xfb\xa3\xe3\x75\x48\x5f\x54\x6d\xd7\x3f\xee\x2b\x22\xb9\xf7\x43\x9d\xf0\xfc\x88\x9c\xb3\x62\x69\xbb\xfc\x65\x43\xd8\x41\x76\x4b\xf3\xbb\xb8\xbb\xfa\xd7\x37\x27\xe9\x3b\xda\xea\xeb\xb6\xa4\x74\x4a\x6d\xd0\x3f\xaa\xf3\xe3\x22\xa1\x5a\xd6\xd3\x79\xde\xe7\xcb\xbc\x2b\x3d\x5a\xb9\x50\x68\xd4\x95\x81\x52\x99\x6d\x80\x45\x74\x7d\x34\xdf\x39\x3a\xa7\x36\x74\x77\xb8\x36\xde\xf2\x16\xa1\x7c\xe6\x1a\xa8\xfc\x6e\x5b\x72\x3e\x35\x95\xbe\x7e\xfb\xf6\xf2\xfc\x97\xb4\xac\xd7\x55\x5d\xa6\x87\xaa\xdf\xa4\x43\x7f\xf3\xdf\xb3\x75\x59\x97\x2d\x31\x91\x55\x95\xd2\xce\x68\x89\x08\x52\x22\x4f\x99\xdc\x22\xe9\xba\x6d\xb6\x13\xf4\x5e\x5d\xbd\x49\x2f\x18\xc5\xfb\xbc\xdf\x60\x20\xfd\x26\xe9\x7e\xdb\x32\x8a\x5c\x87\xd7\x9b\x32\xbd\xa9\x68\xd6\x00\x6a\x6e\x0c\x1f\x69\xa1\x63\x5c\x24\x65\xdb\x66\xb4\xef\xfb\xbb\x4c\x2b\x6b\x7b\x63\x48\x69\x82\x48\xa7\x6e\xfa\x74\x59\xa6\xa8\xb3\x48\x12\x1b\xb0\x61\xf7\x74\xbf\xdf\x56\x2b\xd9\xb1\x2f\xa5\xcc\x23\x9a\x59\xb4\x62\x29\x84\x03\xa2\xac\x2c\x40\x17\xf1\xbf\xbb\x66\x68\xd3\x88\x0d\xa0\xfe\xa6\x24\xbe\xbc\x19\x68\xcb\xe5\xc4\x53\xb7\xcd\x50\x7c\x03\x4a\xb5\xd1\x7b\x42\x4d\xdf\x37\x34\x60\x60\xc7\x01\xf8\x2e\x4e\x89\xe2\xf8\x54\x68\xcb\x5d\x43\xdc\xc1\x11\x7b\x45\x04\x75\xa8\xa8\x90\x66\xda\xe5\xb7\xb4\xdf\xfa\x26\xed\x37\x55\x97\x16\x44\x6c\x2b\x6e\x98\xb6\xc6\x40\xfc\x58\xc8\x82\x08\x54\x48\xc3\xf2\xe2\x35\x00\xd4\x6e\x20\x6a\xda\x50\x63\xcc\xed\xf9\x68\xa2\x26\xe7\xc6\x89\x29\x51\x3b\xa0\x6f\xa2\xdc\x86\x78\x2b\x73\xbf\x73\x24\xf4\x77\xd8\x3e\x8d\x2a\xbf\xb9\xa1\x51\x75\x44\x15\xaf\xd2\xd5\xb6\x21\x92\xfa\xf0\xfe\x0d\x55\xde\xf4\xfd\x3e\xdb\x37\x2d\xc8\xf8\xfa\xfa\x1d\x6d\x8f\xb6\xf7\xb9\x01\xae\x19\xa6\x1e\x76\x4b\xfa\x75\xd8\x54\xc4\x04\xf2\x60\x81\x80\x8a\x2d\x1f\x30\x75\xda\xd4\x0b\xac\xd5\xd0\x6e\x47\xcb\x48\x5d\x5a\xc9\x91\xe1\xf1\x10\x9e\xf0\x9f\x2b\x3f\x4a\x4c\xb7\xa3\x53\xf8\x80\x45\xa5\xa9\x96\x38\x4d\x88\xb6\x9a\x3d\xb7\x1b\x10\xd7\xa5\x66\x78\x8a\xc2\x09\xe4\xca\xe5\x1c\xa2\x52\x9c\xf1\x01\x2f\xdd\xd1\x84\x75\x37\x5f\x5d\x10\x1a\xb0\xa5\x91\x7b\xd3\x36\x3b\xca\x7d\x41\xff\x7c\x86\x1f\xfe\x05\xb7\x07\x98\xbc\x28\x88\xcd\x74\x27\xe9\xfb\x17\x67\xe9\x7f\xf9\xf1\x87\x1f\x16\xe9\xeb\x9e\x37\x04\xd3\xc8\xdf\x79\x6d\x29\x29\x07\xa2\x03\xa5\x9d\xdb\xd3\xf2\x3f\x60\x02\x7f\x90\x3e\x45\xe9\xff\x28\x7f\xcf\xe9\x9c\x2d\x17\xab\x66\xf7\x9c\x37\xf7\x2e\xef\x17\x09\x97\x10\xd5\x28\x39\x5d\x95\x75\x41\x09\x3d\x56\xb5\x2c\xe0\x3a\x5a\x1e\x1c\xb2\x72\xfa\x67\xab\xa6\xbe\xa9\x5a\x9e\xd0\xaf\x75\xbe\x24\x9c\x98\x5c\x40\xec\x18\x25\x76\x76\x11\xd2\x68\x23\x57\x37\x77\x1e\x14\x53\x7d\xcb\x99\xba\xa0\x09\xcb\x4a\xd4\xa8\x8a\x4c\x0e\xcb\x57\xc8\xc6\xba\x5d\xd2\xf4\x5a\xc3\x77\xe7\x11\xde\xdc\xdc\x6c\x89\xb1\x19\xb3\xd2\x1e\x2e\x25\x57\xf8\x56\x08\x42\xc4\xb8\x87\x64\x7Line truncated
|
||||
var _confLocaleLocale_enUsIni = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xc4\x7d\xeb\x72\xdc\x46\xb2\xe6\x7f\x3c\x05\xac\x0d\xad\xec\x08\xaa\x15\xb6\x63\x2f\xe1\x90\xe4\xa5\x49\xeb\x32\x47\x14\x75\x44\x6a\x66\x67\x15\x0a\x0c\xba\x01\x76\x63\xd4\x0d\xb4\x71\x61\x9b\xf3\x6b\x5f\x63\x5f\x6f\x9f\x64\x33\xbf\xcc\xac\x0b\x80\xa6\xe4\x39\x27\xf6\xfc\x21\xab\xab\xb2\x6e\x59\x59\x59\x79\xab\x42\xbe\xdf\x67\x45\xd9\xad\xd2\x67\xe9\x69\xba\xcf\xab\x7a\x5b\x76\x5d\xda\x95\xdb\x9b\xc7\x9b\xa6\xeb\xcb\x22\x7d\x59\xf5\xf4\xbb\xbd\xad\x56\x65\x92\x6c\x9a\x5d\x49\xa0\xaf\xe8\x5f\x52\xe4\xdd\x66\xd9\xe4\x6d\x41\x19\xe7\x96\x4e\xca\xdf\xf7\xdb\xa6\x65\xa0\x5f\x25\x95\x6c\xca\xed\x9e\xeb\xd0\xbf\xa4\xab\xd6\x75\x56\xd5\xf4\xf3\x8a\x52\xe9\xeb\x3a\xe9\x9a\x55\x95\x6f\xb3\xa0\x00\x19\x56\xfe\x53\xfa\x43\x5d\xa4\x57\x7d\xb9\x4f\x9f\x76\xbb\x7c\xbb\x7d\x9e\x77\xa8\xd2\x97\x69\xbe\x5a\x35\x43\xdd\x3f\x7d\x22\x05\xd2\x78\x33\xf4\xd6\xfa\xe5\xd0\x4b\xde\xb0\xb7\xac\x0f\xfb\xa4\x2d\xd7\x15\x4d\xac\xa5\xac\xf7\x9a\x4c\x0e\xe5\xb2\xab\x7a\x1e\xf4\x5f\x24\x95\xdc\x96\x6d\x57\x35\x3c\x9e\x3f\x4b\x2a\xd9\xe7\x6b\x06\x78\x47\xff\x92\xbe\xdc\xed\xb7\x39\x2a\x5c\x6b\x32\xd9\xe6\xf5\x7a\x10\x98\x37\x9a\x4c\x92\x81\x30\x57\xe7\xc0\xd9\x07\x4d\x26\xe5\x2e\xaf\xb6\x8c\x9f\xc7\x9c\xa0\x76\xbb\xee\xd0\x00\x8b\xef\x34\x49\x63\xcc\xfa\xbb\x7d\x89\x21\x3e\xbe\xa6\x54\xb2\xca\xf7\xfd\x6a\x93\x53\xce\x99\xa4\x12\x02\xda\x37\x34\xd6\xa6\xbd\x03\x9c\xfd\x48\x9a\x76\x9d\xd7\xd5\x3f\xf2\x5e\xc6\x7f\x19\xfc\x4c\x76\x55\xdb\x36\x3c\xf5\x0b\x24\x92\xba\x3c\x64\xdc\x0e\xe5\xbc\x2d\x0f\x61\x2b\x5c\xb2\xab\xd6\xad\xcc\x92\x0b\x2f\xf0\x8b\x5b\xe1\xb2\x9b\xa6\xfd\xac\x05\x2f\x38\x39\xaa\x4a\x83\xd0\xd2\xb8\xff\xbc\x26\xbc\x68\xe9\x05\x7e\x44\x00\x5d\x92\x17\xbb\xaa\xce\xf6\x79\x5d\x32\x8e\x4e\xf9\x17\xe1\x85\x7e\x25\xba\xdc\x59\x57\xf6\x7d\x55\xaf\x3b\x2e\x96\xac\xf4\x4a\xb3\x92\xa0\xcc\xe5\xf1\x78\xba\xec\xa6\x2c\x0b\x19\x51\x97\xbe\xa0\x74\xb2\x1f\xb6\x5b\x9a\xfb\x6f\x43\xd9\xf5\x0c\xff\x8e\x7e\xd3\x2c\xe4\x77\x52\x75\x1d\x25\x28\xfb\x35\x12\x09\x2d\x40\xbd\xc2\x90\xce\x90\x48\x92\x8f\x5d\x99\xb7\xab\xcd\xa7\x44\xfe\xa3\x47\x4e\x2c\x16\x8b\xa3\x4b\xc3\xe4\xa0\xa4\x20\x3d\x58\x07\xc9\xaa\x29\xf8\xc7\x19\xfd\xa3\xa6\xab\xba\xeb\x89\xa4\x3f\x25\x9a\x60\x30\x49\x09\x1a\xfb\xaa\xdf\x96\x3e\x13\xfb\xa3\xe3\x75\x48\x5f\x54\x6d\xd7\x3f\xee\x2b\x22\xb9\xf7\x43\x9d\xf0\xfc\x88\x9c\xb3\x62\x69\xbb\xfc\x65\x43\xd8\x41\x76\x4b\xf3\xbb\xb8\xbb\xfa\xd7\x37\x27\xe9\x3b\xda\xea\xeb\xb6\xa4\x74\x4a\x6d\xd0\x3f\xaa\xf3\xe3\x22\xa1\x5a\xd6\xd3\x79\xde\xe7\xcb\xbc\x2b\x3d\x5a\xb9\x50\x68\xd4\x95\x81\x52\x99\x6d\x80\x45\x74\x7d\x34\xdf\x39\x3a\xa7\x36\x74\x77\xb8\x36\xde\xf2\x16\xa1\x7c\xe6\x1a\xa8\xfc\x6e\x5b\x72\x3e\x35\x95\xbe\x7e\xfb\xf6\xf2\xfc\x97\xb4\xac\xd7\x55\x5d\xa6\x87\xaa\xdf\xa4\x43\x7f\xf3\xdf\xb3\x75\x59\x97\x2d\x31\x91\x55\x95\xd2\xce\x68\x89\x08\x52\x22\x4f\x99\xdc\x22\xe9\xba\x6d\xb6\x13\xf4\x5e\x5d\xbd\x49\x2f\x18\xc5\xfb\xbc\xdf\x60\x20\xfd\x26\xe9\x7e\xdb\x32\x8a\x5c\x87\xd7\x9b\x32\xbd\xa9\x68\xd6\x00\x6a\x6e\x0c\x1f\x69\xa1\x63\x5c\x24\x65\xdb\x66\xb4\xef\xfb\xbb\x4c\x2b\x6b\x7b\x63\x48\x69\x82\x48\xa7\x6e\xfa\x74\x59\xa6\xa8\xb3\x48\x12\x1b\xb0\x61\xf7\x74\xbf\xdf\x56\x2b\xd9\xb1\x2f\xa5\xcc\x23\x9a\x59\xb4\x62\x29\x84\x03\xa2\xac\x2c\x40\x17\xf1\xbf\xbb\x66\x68\xd3\x88\x0d\xa0\xfe\xa6\x24\xbe\xbc\x19\x68\xcb\xe5\xc4\x53\xb7\xcd\x50\x7c\x03\x4a\xb5\xd1\x7b\x42\x4d\xdf\x37\x34\x60\x60\xc7\x01\xf8\x2e\x4e\x89\xe2\xf8\x54\x68\xcb\x5d\x43\xdc\xc1\x11\x7b\x45\x04\x75\xa8\xa8\x90\x66\xda\xe5\xb7\xb4\xdf\xfa\x26\xed\x37\x55\x97\x16\x44\x6c\x2b\x6e\x98\xb6\xc6\x40\xfc\x58\xc8\x82\x08\x54\x48\xc3\xf2\xe2\x35\x00\xd4\x6e\x20\x6a\xda\x50\x63\xcc\xed\xf9\x68\xa2\x26\xe7\xc6\x89\x29\x51\x3b\xa0\x6f\xa2\xdc\x86\x78\x2b\x73\xbf\x73\x24\xf4\x77\xd8\x3e\x8d\x2a\xbf\xb9\xa1\x51\x75\x44\x15\xaf\xd2\xd5\xb6\x21\x92\xfa\xf0\xfe\x0d\x55\xde\xf4\xfd\x3e\xdb\x37\x2d\xc8\xf8\xfa\xfa\x1d\x6d\x8f\xb6\xf7\xb9\x01\xae\x19\xa6\x1e\x76\x4b\xfa\x75\xd8\x54\xc4\x04\xf2\x60\x81\x80\x8a\x2d\x1f\x30\x75\xda\xd4\x0b\xac\xd5\xd0\x6e\x47\xcb\x48\x5d\x5a\xc9\x91\xe1\xf1\x10\x9e\xf0\x9f\x2b\x3f\x4a\x4c\xb7\xa3\x53\xf8\x80\x45\xa5\xa9\x96\x38\x4d\x88\xb6\x9a\x3d\xb7\x1b\x10\xd7\xa5\x66\x78\x8a\xc2\x09\xe4\xca\xe5\x1c\xa2\x52\x9c\xf1\x01\x2f\xdd\xd1\x84\x75\x37\x5f\x5d\x10\x1a\xb0\xa5\x91\x7b\xd3\x36\x3b\xca\x7d\x41\xff\x7c\x86\x1f\xfe\x05\xb7\x07\x98\xbc\x28\x88\xcd\x74\x27\xe9\xfb\x17\x67\xe9\x7f\xf9\xf1\x87\x1f\x16\xe9\xeb\x9e\x37\x04\xd3\xc8\xdf\x79\x6d\x29\x29\x07\xa2\x03\xa5\x9d\xdb\xd3\xf2\x3f\x60\x02\x7f\x90\x3e\x45\xe9\xff\x28\x7f\xcf\xe9\x9c\x2d\x17\xab\x66\xf7\x9c\x37\xf7\x2e\xef\x17\x09\x97\x10\xd5\x28\x39\x5d\x95\x75\x41\x09\x3d\x56\xb5\x2c\xe0\x3a\x5a\x1e\x1c\xb2\x72\xfa\x67\xab\xa6\xbe\xa9\x5a\x9e\xd0\xaf\x75\xbe\x24\x9c\x98\x5c\x40\xec\x18\x25\x76\x76\x11\xd2\x68\x23\x57\x37\x77\x1e\x14\x53\x7d\xcb\x99\xba\xa0\x09\xcb\x4a\xd4\xa8\x8a\x4c\x0e\xcb\x57\xc8\xc6\xba\x5d\xd2\xf4\x5a\xc3\x77\xe7\x11\xde\xdc\xdc\x6c\x89\xb1\x19\xb3\xd2\x1e\x2e\x25\x57\xf8\x56\x08\x42\xc4\xb8\x87\x64\x7Line truncated
|
||||
|
||||
func confLocaleLocale_enUsIniBytes() ([]byte, error) {
|
||||
return bindataRead(
|
||||
@@ -787,7 +787,7 @@ func confLocaleLocale_enUsIni() (*asset, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 36142, mode: os.FileMode(420), modTime: time.Unix(1439104292, 0)}
|
||||
info := bindataFileInfo{name: "conf/locale/locale_en-US.ini", size: 36177, mode: os.FileMode(420), modTime: time.Unix(1439138135, 0)}
|
||||
a := &asset{bytes: bytes, info: info}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,15 @@ func (repo *Repository) IsTagExist(tagName string) bool {
|
||||
return IsTagExist(repo.Path, tagName)
|
||||
}
|
||||
|
||||
func (repo *Repository) getTagsReversed() ([]string, error) {
|
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l", "--sort=-v:refname")
|
||||
if err != nil {
|
||||
return nil, concatenateError(err, stderr)
|
||||
}
|
||||
tags := strings.Split(stdout, "\n")
|
||||
return tags[:len(tags)-1], nil
|
||||
}
|
||||
|
||||
// GetTags returns all tags of given repository.
|
||||
func (repo *Repository) GetTags() ([]string, error) {
|
||||
if gitVer.AtLeast(MustParseVersion("2.0.0")) {
|
||||
@@ -33,15 +42,6 @@ func (repo *Repository) GetTags() ([]string, error) {
|
||||
return tags[:len(tags)-1], nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getTagsReversed() ([]string, error) {
|
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l", "--sort=-v:refname")
|
||||
if err != nil {
|
||||
return nil, errors.New(stderr)
|
||||
}
|
||||
tags := strings.Split(stdout, "\n")
|
||||
return tags[:len(tags)-1], nil
|
||||
}
|
||||
|
||||
func (repo *Repository) CreateTag(tagName, idStr string) error {
|
||||
_, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", tagName, idStr)
|
||||
if err != nil {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user