diff --git a/cibernox/src/avatarme/encoder/encoder.go b/cibernox/src/avatarme/encoder/encoder.go new file mode 100644 index 0000000..e41d7e1 --- /dev/null +++ b/cibernox/src/avatarme/encoder/encoder.go @@ -0,0 +1,32 @@ +package encoder + +import ( + "fmt" + "image" + "image/jpeg" + "image/png" + "os" + "regexp" +) + +var extensionRegexp *regexp.Regexp = regexp.MustCompile(`\.(png|jpe?g)$`) + +// Exports the given image in the given path. +// +func ExportImage(img *image.RGBA, filepath string) { + file, err := os.Create(filepath) + if err != nil { + fmt.Println("Error creating file") + } + defer file.Close() + + extension := extensionRegexp.FindString(filepath) + + if extension == ".png" { + png.Encode(file, img) + } else if extension == ".jpg" || extension == ".jpeg" { + jpeg.Encode(file, img, &jpeg.Options{95}) + } else { + fmt.Println("Invalid extension") + } +} diff --git a/cibernox/src/avatarme/generators/pixelated/pixelated.go b/cibernox/src/avatarme/generators/pixelated/pixelated.go new file mode 100644 index 0000000..1917edd --- /dev/null +++ b/cibernox/src/avatarme/generators/pixelated/pixelated.go @@ -0,0 +1,68 @@ +package pixelated + +import ( + "crypto/md5" + "fmt" + "image" + "image/color" + "image/draw" +) + +const ( + avatarSide int = 8 + signatureLength int = avatarSide * avatarSide + enlarger string = "md5-enlarger" +) + +var palette map[byte]color.RGBA = map[byte]color.RGBA{ + 48: color.RGBA{255, 255, 255, 255}, // 0 => white, + 49: color.RGBA{213, 0, 0, 255}, // 1 => red, + 50: color.RGBA{255, 255, 255, 255}, // 2 => white, + 51: color.RGBA{255, 255, 255, 255}, // 3 => white, + 52: color.RGBA{255, 76, 0, 255}, // 4 => orange, + 53: color.RGBA{255, 255, 255, 255}, // 5 => white, + 54: color.RGBA{255, 255, 255, 255}, // 6 => white, + 55: color.RGBA{255, 255, 11, 255}, // 7 => yellow, + 56: color.RGBA{255, 76, 0, 255}, // 8 => orange, + 57: color.RGBA{213, 0, 0, 255}, // 9 => red, + 97: color.RGBA{239, 0, 113, 255}, // a => magenta, + 98: color.RGBA{54, 0, 151, 255}, // b => purple, + 99: color.RGBA{0, 0, 205, 255}, // c => blue, + 100: color.RGBA{0, 152, 232, 255}, // d => cyan, + 101: color.RGBA{26, 176, 0, 255}, // e => green, + 102: color.RGBA{0, 0, 0, 255}, // f => black, +} + +// Generates a MD5 hash from the given string limited to exactly 64 chars. +// If the length of the string is not enough to generate a valid hash, appends some content +// at the end. +// +func getMD5(s string) string { + length := len(s) + if length < 16 { + s = s + enlarger[0:16-length] + } + hasher := md5.New() + return fmt.Sprintf("%x", hasher.Sum([]byte(s))) +} + +// Generates a image.RGBA of colors given a hexadecimal string. +// +func BuildImage(text string, size int) *image.RGBA { + hash := getMD5(text) + scale := size / avatarSide + + img := image.NewRGBA(image.Rect(0, 0, avatarSide*scale, avatarSide*scale)) + + for x := 0; x < avatarSide; x++ { + for y := 0; y < avatarSide; y++ { + color := palette[hash[x*avatarSide+y]] + startPoint := image.Point{x * scale, y * scale} + endPoint := image.Point{x*scale + scale, y*scale + scale} + rectangle := image.Rectangle{startPoint, endPoint} + draw.Draw(img, rectangle, &image.Uniform{color}, image.ZP, draw.Src) + } + } + + return img +} diff --git a/cibernox/src/avatarme/main.go b/cibernox/src/avatarme/main.go new file mode 100644 index 0000000..bf20d5a --- /dev/null +++ b/cibernox/src/avatarme/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "./encoder" + "./generators/pixelated" + "github.com/codegangsta/cli" + "os" + "fmt" +) + +func main() { + app := cli.NewApp() + app.Name = "Avatarme" + app.Usage = "Generates an unique avatar for the given string" + app.Version = "0.0.1" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "output, o", Value: "output.png", Usage: "path of the output file"}, + cli.IntFlag{Name: "size, s", Value: 256, Usage: "side length of the generated image (in px). Will be ronded to a multiple of 8"}, + } + app.Action = func(c *cli.Context) { + if len(c.Args()) <= 0 { + fmt.Println("Error: You need to supply a string to encode") + return + } + text := c.Args()[0] + img := pixelated.BuildImage(text, c.Int("size")) + encoder.ExportImage(img, c.String("output")) + } + + app.Run(os.Args) +}