diff --git a/fourBitSquares.go b/fourBitSquares.go new file mode 100644 index 0000000..74f6806 --- /dev/null +++ b/fourBitSquares.go @@ -0,0 +1,50 @@ +package main + +import ( + "strconv" + + "github.com/fogleman/gg" +) + +/* +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() + } + } +} diff --git a/github.go b/github.go new file mode 100644 index 0000000..9f1e76d --- /dev/null +++ b/github.go @@ -0,0 +1,119 @@ +package main + +import ( + "crypto/md5" + "math" + "slices" + + "github.com/fogleman/gg" +) + +// Translated to Go from: https://github.com/dgraham/identicon +func GitHub(dc *gg.Context, userId string) { + hash := md5.Sum([]byte(userId)) + w := 800 + h := 800 + cols := 5 + rows := 5 + pw := w / cols + ph := h / rows + + // Background + dc.SetRGB255(240, 240, 240) + dc.DrawRectangle(0, 0, float64(w), float64(h)) + dc.Fill() + + dc.SetRGB255(foreground(hash[:])) + + // Foreground + enabledVertices := make([]bool, 25) + for i := range 15 { + byte := hash[i/2] + var nibble uint8 // 4 bits are called a nibble + if i % 2 == 0 { + nibble = (byte & 0xf0) >> 4 // left side + } else { + nibble = byte & 0x0f // right side + } + painted := nibble % 2 == 0 + + rowIdx := i % 5 + colIdx := 2 - i / 5 + mirrColIdx := 2 + i / 5 + + enabledVertices[rowIdx * 5 + colIdx] = painted + enabledVertices[rowIdx * 5 + mirrColIdx] = painted + } + + for row, pix := range slices.Collect(slices.Chunk(enabledVertices, 5)) { + for col, painted := range pix { + if painted { + x := col * pw + y := row * ph + + dc.DrawRectangle(float64(x), float64(y), float64(pw), float64(ph)) + dc.Fill() + } + } + } +} + + +func hue_to_rgb(a float32, b float32, hue float32) float32 { + var h float32 + if hue < 0.0 { + h = hue + 1.0 + } else if hue > 1.0 { + h = hue - 1.0 + } else { + h = hue + } + + if h < 1.0 / 6.0 { + return a + (b - a) * 6.0 * h + } + + if h < 1.0 / 2.0 { + return b + } + + if h < 2.0 / 3.0 { + return a + (b - a) * (2.0 / 3.0 - h) * 6.0 + } + + return a +} + +func foreground(source []uint8) (int, int, int) { + h1 := (uint16(source[12]) & 0x0f) << 8; + h2 := uint16(source[13]) + + h := uint32(h1 | h2) + s := uint32(source[14]) + l := uint32(source[15]) + + hue := float32(h * 360) / float32(4095) + sat := float32(s * 20) / float32(255) + lum := float32(l * 20) / float32(255) + + sat = 65.0 - sat + lum = 75.0 - lum + + hue = hue / 360.0 + sat = sat / 100.0 + lum = lum / 100.0 + + var b float32 + if lum <= 0.5 { + b = lum * (sat + 1.0) + } else { + b = lum + sat - lum * sat + } + a := lum * 2.0 - b + + r := hue_to_rgb(a, b, hue + 1.0 / 3.0) + g := hue_to_rgb(a, b, hue) + b = hue_to_rgb(a, b, hue - 1.0 / 3.0) + + return int(math.Round(float64(r * 255))), int(math.Round(float64(g * 255))), int(math.Round(float64(b * 255))) +} diff --git a/main.go b/main.go index 9e8f78d..c4264b8 100644 --- a/main.go +++ b/main.go @@ -1,13 +1,6 @@ package main import ( - "crypto/md5" - "crypto/sha1" - "fmt" - "math" - "slices" - "strconv" - "github.com/fogleman/gg" ) @@ -22,358 +15,3 @@ func main() { } // Bit font character overlay mit xor - -func hue_to_rgb(a float32, b float32, hue float32) float32 { - var h float32 - if hue < 0.0 { - h = hue + 1.0 - } else if hue > 1.0 { - h = hue - 1.0 - } else { - h = hue - } - - if h < 1.0 / 6.0 { - return a + (b - a) * 6.0 * h - } - - if h < 1.0 / 2.0 { - return b - } - - if h < 2.0 / 3.0 { - return a + (b - a) * (2.0 / 3.0 - h) * 6.0 - } - - return a -} - -func foreground(source []uint8) (int, int, int) { - h1 := (uint16(source[12]) & 0x0f) << 8; - h2 := uint16(source[13]) - - h := uint32(h1 | h2) - s := uint32(source[14]) - l := uint32(source[15]) - - hue := float32(h * 360) / float32(4095) - sat := float32(s * 20) / float32(255) - lum := float32(l * 20) / float32(255) - - sat = 65.0 - sat - lum = 75.0 - lum - - hue = hue / 360.0 - sat = sat / 100.0 - lum = lum / 100.0 - - var b float32 - if lum <= 0.5 { - b = lum * (sat + 1.0) - } else { - b = lum + sat - lum * sat - } - a := lum * 2.0 - b - - r := hue_to_rgb(a, b, hue + 1.0 / 3.0) - g := hue_to_rgb(a, b, hue) - b = hue_to_rgb(a, b, hue - 1.0 / 3.0) - - return int(math.Round(float64(r * 255))), int(math.Round(float64(g * 255))), int(math.Round(float64(b * 255))) -} - -// Translated to Go from: https://github.com/dgraham/identicon -func GitHub(dc *gg.Context, userId string) { - fmt.Printf("md5.Sum([]byte(userId)): %v\n", md5.Sum([]byte(userId))) - hash := md5.Sum([]byte(userId)) - // userIdHash := "da02efbbbe97337447671769e0f50c4a" // ohne newline (richtiges symbol) - w := 800 - h := 800 - cols := 5 - rows := 5 - pw := w / cols - ph := h / rows - - // Background - dc.SetRGB255(240, 240, 240) - dc.DrawRectangle(0, 0, float64(w), float64(h)) - dc.Fill() - - // Convert to bytes - // bytes := []uint8{} - // for i := 0; i < 32; i+=2 { - // integer, _ := strconv.ParseUint(string(userIdHash[i]) + string(userIdHash[i+1]), 16, 8) - // bytes = append(bytes, uint8(integer)) - // } - // fmt.Println(bytes) - - dc.SetRGB255(foreground(hash[:])) - - // Foreground - enabledVertices := make([]bool, 25) - // for i, character := range userIdHash[:15] { - // integer, _ := strconv.ParseUint(string(character), 16, 8) - // fmt.Println(integer) - // painted := integer % 2 == 0 - - // rowIdx := i % 5 - // colIdx := 2 - i / 5 - // mirrColIdx := 2 + i / 5 - - // enabledVertices[rowIdx * 5 + colIdx] = painted - // enabledVertices[rowIdx * 5 + mirrColIdx] = painted - // } - - for i := range 15 { - // integer, _ := strconv.ParseUint(string(character), 16, 8) - byte := hash[i/2] - var nibble uint8 // 4 bits are called a nibble - if i % 2 == 0 { - nibble = (byte & 0xf0) >> 4 // left side - } else { - nibble = byte & 0x0f // right side - } - painted := nibble % 2 == 0 - - rowIdx := i % 5 - colIdx := 2 - i / 5 - mirrColIdx := 2 + i / 5 - - enabledVertices[rowIdx * 5 + colIdx] = painted - enabledVertices[rowIdx * 5 + mirrColIdx] = painted - } - - - // 216 166 130 - // Foreground color - // da02efbbbe97337447671769e0f50c4a - // h1 = 3 -> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -> 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 - // h2 = 3 -> 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 - // h = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 = 771 - // s = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 = 7 - // l = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 = 4 - // hue = 277560 / 4095 = 67,78021978 (73710) - // sat = 140 / 255 = 0,54901961 - // lum = 80 / 255 = 0,31372549 - // - // 67.78021978, 64.45098039, 74.68627451 - // --- - // - // l = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 1 0 1 1 1 0 0 0 1 = 23409 - // hue = 73710 / 4095 = 21.538462 - // sat = 3213 / 255 = 12.6 - // lum = 1836 / 255 = 7.2 - // Solution: 18, 64.3, 69.2 - - for row, pix := range slices.Collect(slices.Chunk(enabledVertices, 5)) { - for col, painted := range pix { - if painted { - x := col * pw - y := row * ph - - dc.DrawRectangle(float64(x), float64(y), float64(pw), float64(ph)) - dc.Fill() - } - } - } -} - -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) -} - -func Map[T any, M any](a []T, f func(T) M) []M { - n := make([]M, len(a)) - for i, e := range a { - n[i] = f(e) - } - return n -} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..c3735d1 --- /dev/null +++ b/utils.go @@ -0,0 +1,26 @@ +package main + +import ( + "crypto/sha1" + "fmt" + "strconv" +) + +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) +} diff --git a/xBitPolygons.go b/xBitPolygons.go new file mode 100644 index 0000000..c8ccd5d --- /dev/null +++ b/xBitPolygons.go @@ -0,0 +1,138 @@ +package main + +import ( + "slices" + "strconv" + + "github.com/fogleman/gg" +) + +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() + } + } +}