package main import ( "crypto/sha1" "fmt" "slices" "strconv" "github.com/fogleman/gg" ) func main() { dc := gg.NewContext(800, 800) XBitPolygons(dc, "Jaybee18", 8, 8) dc.SavePNG("out.png") } func XBitPolygons(dc *gg.Context, username string, columns int, rows int) { hash := hash(username) dc.SetRGB255(255, 255, 255) dc.DrawRectangle(0, 0, 800, 800) dc.Fill() colorString := hash[0:6] r, g, b := rgbFromHex(colorString) dc.SetRGB255(r, g, b) enabledVertices := [][]bool{} for _, character := range hash[6:6+rows+1] { integer, _ := strconv.ParseUint(string(character), 16, columns/2+1) row := []bool{} for j := range columns/2+1 { on := hasBit(integer, j) row = append(row, on) } enabledVertices = append(enabledVertices, row) } w := 800 / columns h := 800 / rows for i := range rows { for j := range columns/2 { topLeft, tlx, tly := enabledVertices[i][j], float64(j*w), float64(i*h) topRight, trx, try := enabledVertices[i][j+1], float64(j*w+w), float64(i*h) bottomRight, brx, bry := enabledVertices[i+1][j+1], float64(j*w+w), float64(i*h+h) bottomLeft, blx, bly := enabledVertices[i+1][j], float64(j*w), float64(i*h+h) mx, my := tlx + float64(w/2), tly + float64(h/2) count := 0 if topLeft {count++} if topRight {count++} if bottomRight {count++} if bottomLeft {count++} if topLeft && topRight { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(tlx, tly) dc.LineTo(trx, try) dc.ClosePath() } if topRight && bottomRight { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(trx, try) dc.LineTo(brx, bry) dc.ClosePath() } if bottomRight && bottomLeft { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(brx, bry) dc.LineTo(blx, bly) dc.ClosePath() } if bottomLeft && topLeft { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(blx, bly) dc.LineTo(tlx, tly) dc.ClosePath() } dc.Fill() } } // Reverse for i := range len(enabledVertices) { slices.Reverse(enabledVertices[i]) } // Mirror left side for i := range rows { for j := range columns/2 { topLeft, tlx, tly := enabledVertices[i][j], float64(w*(columns/2)+j*w), float64(i*h) topRight, trx, try := enabledVertices[i][j+1], float64(w*(columns/2)+j*w+w), float64(i*h) bottomRight, brx, bry := enabledVertices[i+1][j+1], float64(w*(columns/2)+j*w+w), float64(i*h+h) bottomLeft, blx, bly := enabledVertices[i+1][j], float64(w*(columns/2)+j*w), float64(i*h+h) mx, my := tlx+float64(w/2), tly+float64(h/2) count := 0 if topLeft {count++} if topRight {count++} if bottomRight {count++} if bottomLeft {count++} if topLeft && topRight { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(tlx, tly) dc.LineTo(trx, try) dc.ClosePath() } if topRight && bottomRight { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(trx, try) dc.LineTo(brx, bry) dc.ClosePath() } if bottomRight && bottomLeft { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(brx, bry) dc.LineTo(blx, bly) dc.ClosePath() } if bottomLeft && topLeft { dc.NewSubPath() dc.MoveTo(mx, my) dc.LineTo(blx, bly) dc.LineTo(tlx, tly) dc.ClosePath() } dc.Fill() } } } /* 8x8 square of 100x100 px squares First 6 characters of the hash are the color For the next 8 characters each character represents 4 bits of a row being on or off. The image is then mirrored to the right side. 9d26bf3cf1fb2b2f02d4a2013333f4fcd551cb2e 9d26bf -> color 3 -> row1 c -> row2 ... b -> row8 3 = 0 0 1 1 c = 1 1 0 0 ... b = 1 0 1 1 */ func FourBitSquares(dc *gg.Context, username string) { hash := hash(username) colorString := hash[0:6] r, g, b := rgbFromHex(colorString) dc.SetRGB255(r, g, b) for i, character := range hash[6:14] { integer, _ := strconv.ParseUint(string(character), 16, 4) for j := range 4 { on := hasBit(integer, j) dc.DrawRectangle(float64(j * 100), float64(i * 100), 100, 100) dc.DrawRectangle(700 - float64(j * 100), float64(i * 100), 100, 100) if !on { dc.SetRGB255(r, g, b) } else { dc.SetRGB255(255, 255, 255) } dc.Fill() } } } func rgbFromHex(hex string) (int, int, int) { r, _ := strconv.ParseUint(hex[0:2], 16, 8) g, _ := strconv.ParseUint(hex[2:4], 16, 8) b, _ := strconv.ParseUint(hex[4:6], 16, 8) return int(r), int(g), int(b) } func hash(str string) string { h := sha1.New() h.Write([]byte(str)) res := h.Sum(nil) return fmt.Sprintf("%x", res) } func hasBit(n uint64, pos int) bool { val := n & (1 << pos) return (val > 0) }