Skip to content
Open
Show file tree
Hide file tree
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
32 changes: 32 additions & 0 deletions cibernox/src/avatarme/encoder/encoder.go
Original file line number Diff line number Diff line change
@@ -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")
}
}
68 changes: 68 additions & 0 deletions cibernox/src/avatarme/generators/pixelated/pixelated.go
Original file line number Diff line number Diff line change
@@ -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
}
31 changes: 31 additions & 0 deletions cibernox/src/avatarme/main.go
Original file line number Diff line number Diff line change
@@ -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)
}