aboutsummaryrefslogtreecommitdiff
path: root/main.go
blob: 7e59b1bc488192f10a2ec20c6031843dcfad4847 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package main

import (
	// Bag 4: bytes, crypto, encoding, image, regexp
	"bytes"
	"crypto/sha256"
	"encoding/base64"
	"image"
	"image/color"
	"image/png"
	"regexp"

	// Pantry: flag
	"flag"
	"fmt"
)

var usernamePattern = regexp.MustCompile("[a-zA-Z][a-zA-Z0-9]*")

func main() {
	username := flag.String("username", "", "username to encode as image (must contain only letters a-zA-Z0-9 and start with a letter)")
	mult := flag.Int("mult", 20, "the multiplier to apply to the 10x10 generated image (must be >= 1)")
	flag.Parse()

	if !usernamePattern.MatchString(*username) {
		flag.Usage()
		return
	}

	if *mult < 1 {
		flag.Usage()
		return
	}

	hash := sha256.Sum256([]byte(*username))
	img := makeBigger(tesselate(generateImage(hash)), *mult)
	str, err := encodePNG(img)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(str)
}

func newColor(b []byte) color.NRGBA {
	if len(b) != 3 {
		panic("cannot make color without exactly 3 bytes")
	}
	return color.NRGBA{
		R: b[0],
		G: b[1],
		B: b[2],
		A: 255,
	}
}

func generateImage(hash [32]byte) *image.NRGBA {
	img := image.NewNRGBA(image.Rect(0, 0, 5, 5))
	colorA := newColor(hash[0:3])
	colorB := newColor(hash[3:6])
	offset := 6
	for x := 0; x < 5; x++ {
		for y := 0; y < 5; y++ {
			on := hash[offset] > 127
			color := colorA
			if on {
				color = colorB
			}
			img.Set(x, y, color)
			offset++
		}
	}
	return img
}

func encodePNG(img *image.NRGBA) (string, error) {
	var b bytes.Buffer
	if err := png.Encode(&b, img); err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(b.Bytes()), nil
}

func tesselate(img *image.NRGBA) *image.NRGBA {
	newImg := image.NewNRGBA(image.Rect(0, 0, img.Bounds().Max.X*2, img.Bounds().Max.Y*2))
	for x := 0; x < img.Bounds().Max.X; x++ {
		for y := 0; y < img.Bounds().Max.Y; y++ {
			x1 := img.Bounds().Max.X*2 - 1
			y1 := img.Bounds().Max.Y*2 - 1
			newImg.Set(x, y, img.At(x, y))
			newImg.Set(x1-x, y, img.At(x, y))
			newImg.Set(x, y1-y, img.At(x, y))
			newImg.Set(x1-x, y1-y, img.At(x, y))
		}
	}
	return newImg
}

func makeBigger(img *image.NRGBA, mult int) *image.NRGBA {
	newImg := image.NewNRGBA(image.Rect(0, 0, img.Bounds().Max.X*mult, img.Bounds().Max.Y*mult))
	for x := 0; x < img.Bounds().Max.X; x++ {
		for y := 0; y < img.Bounds().Max.Y; y++ {
			for i := 0; i < mult; i++ {
				for j := 0; j < mult; j++ {
					newImg.Set(x*mult+i, y*mult+j, img.At(x, y))
				}
			}
		}
	}
	return newImg
}