From 13dde0b4e9c2dfa32f29e10b19c4636c9073dd1c Mon Sep 17 00:00:00 2001 From: Jan Bessler Date: Sat, 28 Feb 2026 16:24:32 +0100 Subject: [PATCH] feat: github implementation working; cleanup needed --- main.go | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- out.png | Bin 13365 -> 3735 bytes 2 files changed, 170 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 9bd223f..9e8f78d 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,10 @@ package main import ( + "crypto/md5" "crypto/sha1" "fmt" + "math" "slices" "strconv" @@ -12,11 +14,170 @@ import ( func main() { dc := gg.NewContext(800, 800) - XBitPolygons(dc, "Jaybee18", 8, 8) + GitHub(dc, "64578396") + // XBitPolygons(dc, "BigBor14", 6, 6) + // FourBitSquares(dc, "Jaybee18") dc.SavePNG("out.png") } +// 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) @@ -208,3 +369,11 @@ 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/out.png b/out.png index 80388ca6426c4b8b50058edcfdffdd342baf7a71..9e40f2f41fea7ccc789ced2d05acdbdd7e98dc9b 100644 GIT binary patch literal 3735 zcmeAS@N?(olHy`uVBq!ia0y~yU{(NO4kn;Th|olP1_r)3PZ!6KiaBp?9OP_vU~svp zQnA&vd!s=2#!al!9?X^}r?-BHV=ex3#^_iDBg2KCXXF?dKIF5AF*x`nFftq&WsC;G z&`k-`ZZbFgUiW#1Z6o{I+jiAV1(Vsi85GnuFfb%BjWR|9VKgO-=7P~&Fq#WSbHQjX zpn5L&CYOBX-hpON^MkQL{#x#QU@N3@wCOS0{u(B2&-=hW=Kuepoq|sUIBtgnISihz KelF{r5}E)o3xfIp literal 13365 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 Ar~m)}