package main import ( "bytes" "flag" "fmt" "image" "image/color" "image/draw" "image/png" "math" "math/rand" "os" ) var palette = map[byte][3]uint8{ '0': {0, 0, 0}, '1': {0, 0, 128}, '2': {0, 128, 0}, '3': {0, 128, 128}, '4': {128, 0, 0}, '5': {128, 0, 128}, '6': {128, 128, 0}, '7': {192, 192, 192}, '8': {128, 128, 128}, '9': {0, 0, 255}, 'a': {0, 255, 0}, 'b': {0, 255, 255}, 'c': {255, 0, 0}, 'd': {255, 0, 255}, 'e': {255, 255, 0}, 'f': {255, 255, 255}, } var ( bright = []byte("9abcdef") dark = []byte("012345") mid = []byte("6789abcd") all = []byte("0123456789abcdef") ) func u4(n int) byte { return "0123456789abcdef"[n&0xF] } func randColor(pool []byte) byte { if pool == nil { pool = all } return pool[rand.Intn(len(pool))] } func hexToRGB(c byte) [3]uint8 { if v, ok := palette[c]; ok { return v } return [3]uint8{0, 0, 0} } func effToPixels(eff map[int]string) [][]color.RGBA { pixels := make([][]color.RGBA, 31) for i := 0; i < 31; i++ { row := make([]color.RGBA, 88) rowStr := eff[i+1] for j := 0; j < 88; j++ { if j < len(rowStr) { rgb := hexToRGB(rowStr[j]) row[j] = color.RGBA{rgb[0], rgb[1], rgb[2], 255} } else { row[j] = color.RGBA{0, 0, 0, 255} } } pixels[i] = row } return pixels } var sin = []byte("01122334455666777888889999999999998888777666554433221100") var sinAltInt = []int{ 6, 6, 7, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 8, 8, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, } func arrayRandomize(ref []byte, colorSet string) []byte { mapping := make(map[byte]byte) hexChars := []byte("0123456789abcdef") if colorSet != "" { colors := []byte{} for i := 0; i < len(colorSet); i++ { if colorSet[i] != ' ' { colors = append(colors, colorSet[i]) } } for _, h := range hexChars { mapping[h] = colors[rand.Intn(len(colors))] } } else { for _, h := range hexChars { mapping[h] = u4(rand.Intn(16)) } } result := make([]byte, len(ref)) for i, x := range ref { if v, ok := mapping[x]; ok { result[i] = v } else { result[i] = x } } return result } func effectSinRand() map[int]string { eff := make(map[int]string) s := []string{"f a", "a b d", "a b", "a f", "c d", "e 5", "b c f"} meow := arrayRandomize(sin, s[rand.Intn(len(s))]) a := 0 for i := 1; i < 32; i += 2 { eff[i] = "" eff[i+1] = "" for j := 1; j < 45; j++ { idx := (a * 2) % len(meow) l := meow[idx] eff[i] += string([]byte{l, l}) eff[i+1] += string([]byte{l, l}) a++ if a >= len(meow) { a = 0 } } } return eff } func effectSinRandWorse() map[int]string { eff := make(map[int]string) length := rand.Intn(99) meow := make([]byte, length) for i := range meow { meow[i] = '0' } meow = arrayRandomize(meow, "a b c d e f") a := 0 for i := 1; i < 32; i += 2 { eff[i+1] = "0" eff[i] = "" for j := 1; j < 45; j++ { var idx int if len(meow) > 0 { idx = (a * 2) % len(meow) } var l byte = '0' if len(meow) > 0 { l = meow[idx] } eff[i] += string([]byte{l, l}) eff[i+1] += string([]byte{l, l}) a++ if a >= length { a = 0 } } } return eff } func effectSin2() map[int]string { eff := make(map[int]string) c := []string{"a f", "e 5", "d c", "d b"} randa := c[rand.Intn(len(c))] randb := c[rand.Intn(len(c))] randc := c[rand.Intn(len(c))] randd := c[rand.Intn(len(c))] rd := []byte{randd[0], randd[2]} ra := []byte{randa[0], randa[2]} rb := []byte{randb[0], randb[2]} rc := []byte{randc[0], randc[2]} for i := 1; i < 32; i++ { eff[i] = "" for j := 1; j < 89; j++ { x := 15 if j-1 < len(sinAltInt) { x = sinAltInt[j-1] + 15 } switch { case x == i-10: eff[i] += string(rd[0]) case x == i-9: eff[i] += string(rd[1]) case x == i-8: eff[i] += string(rd[0]) case x == i: eff[i] += string(ra[0]) case x == i+1: eff[i] += string(ra[1]) case x == i+2: eff[i] += string(ra[0]) case x == i+10: eff[i] += string(rb[0]) case x == i+11: eff[i] += string(rb[1]) case x == i+12: eff[i] += string(rb[0]) case x == i+20: eff[i] += string(rc[0]) case x == i+21: eff[i] += string(rc[1]) case x == i+22: eff[i] += string(rc[0]) default: eff[i] += "0" } } } return eff } func effectRand() map[int]string { eff := make(map[int]string) for i := 1; i < 32; i += 2 { eff[i] = "" eff[i+1] = "" for j := 1; j < 45; j++ { a := u4(rand.Intn(5) + 10) eff[i] += string([]byte{a, a}) eff[i+1] += string([]byte{a, a}) } } return eff } func effectSpeccy() map[int]string { eff := make(map[int]string) b := rand.Intn(3) + 3 for i := 1; i < 32; i++ { eff[i] = "" for j := 1; j < 11; j++ { eff[i] += "0" } a := 10 + i j := 11 for ; j < 89; j++ { if a == j { break } eff[i] += "0" } for ; j < 89; j++ { if i < 6 && j < 40 { eff[i] += "0" } else { eff[i] += string(u4(((j - a) % b) + 10)) } } } return eff } func effectSpeccy2x() map[int]string { eff := make(map[int]string) b := rand.Intn(3) + 3 for i := 1; i < 32; i++ { eff[i] = "" for j := 1; j < 11; j++ { eff[i] += "0" } a := 10 + i j := 11 for ; j < 89; j++ { if a == j { break } eff[i] += "0" } for ; j < 89; j += 2 { if i < 6 && j < 40 { eff[i] += "00" } else { c := u4(((j - a) % b) + 10) eff[i] += string([]byte{c, c}) } } } return eff } func effectSpeccy2xPride() map[int]string { eff := make(map[int]string) c := []string{"e d a 2 6 b", "5 9 5 c", "0 e 9 2", "0e cc 5b"} bStr := c[rand.Intn(len(c))] b := []string{} for i := 0; i < len(bStr); { if bStr[i] == ' ' { i++ continue } if i+1 < len(bStr) && bStr[i+1] != ' ' { b = append(b, bStr[i:i+2]) i += 2 } else { b = append(b, bStr[i:i+1]) i++ } } w := []int{4, 6, 8, 10, 12, 16, 24} width := w[rand.Intn(len(w))] for i := 1; i < 32; i++ { eff[i] = "" for j := 1; j < 11; j++ { eff[i] += "0" } a := 10 + i j := 11 for ; j < 89; j++ { if a == j { break } eff[i] += "0" } for ; j < 89; j += 2 { if i < 6 && j < 40 { eff[i] += "00" } else { idx := ((i - j) / width) % len(b) if idx < 0 { idx = -idx } d := b[idx] if len(d) == 2 { eff[i] += d } else { eff[i] += d + d } } } } return eff } func effectCheckerboard() map[int]string { eff := make(map[int]string) s := []byte("abcdef5") c := s[rand.Intn(len(s))] for i := 1; i < 32; i++ { eff[i] = "" if (i%4)/2 == 0 { eff[i] += "00" } for j := 1; j < 89; j++ { if j%2 == 0 { eff[i] += "00" } else { eff[i] += string([]byte{c, c}) } } } return eff } func effectHorizontalStripes() map[int]string { eff := make(map[int]string) colors := make([]byte, rand.Intn(5)+2) for i := range colors { colors[i] = randColor(bright) } thickness := rand.Intn(4) + 1 for i := 1; i < 32; i++ { c := colors[(i/thickness)%len(colors)] eff[i] = string(bytes.Repeat([]byte{c}, 88)) } return eff } func effectVerticalStripes() map[int]string { eff := make(map[int]string) colors := make([]byte, rand.Intn(7)+2) for i := range colors { colors[i] = randColor(bright) } thickness := rand.Intn(7) + 2 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { row[j-1] = colors[(j/thickness)%len(colors)] } eff[i] = string(row) } return eff } func effectDiagonalStripes() map[int]string { eff := make(map[int]string) colors := make([]byte, rand.Intn(4)+2) for i := range colors { colors[i] = randColor(bright) } slope := rand.Intn(4) + 1 div := rand.Intn(6) + 3 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { idx := ((i + j*slope) / div) % len(colors) row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectGradientHorizontal() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if j < 44 { if rand.Float64() > (float64(j) / 44.0) { row[j-1] = c1 } else { row[j-1] = c2 } } else { if rand.Float64() > (float64(j-44) / 44.0) { row[j-1] = c2 } else { row[j-1] = c1 } } } eff[i] = string(row) } return eff } func effectGradientVertical() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) for i := 1; i < 32; i++ { row := make([]byte, 88) t := float64(i-1) / 30.0 for j := 1; j < 89; j++ { if rand.Float64() > t { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectPlasma() map[int]string { eff := make(map[int]string) colors := make([]byte, 4) for i := range colors { colors[i] = randColor(bright) } scale1 := rand.Float64()*0.3 + 0.1 scale2 := rand.Float64()*0.3 + 0.1 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { v := math.Sin(float64(i)*scale1) + math.Cos(float64(j)*scale2) + math.Sin(float64(i+j)*0.1) idx := int((v+2)*float64(len(colors))/4.0) % len(colors) if idx < 0 { idx = -idx } row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectNoise() map[int]string { eff := make(map[int]string) pool := append([]byte{}, bright...) pool = append(pool, mid...) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { row[j-1] = randColor(pool) } eff[i] = string(row) } return eff } func effectDitheredNoise() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) threshold := rand.Float64()*0.4 + 0.3 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if rand.Float64() > threshold { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectScanlines() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if i%2 == 0 { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectCrosshatch() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) period := rand.Intn(6) + 3 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if i%period == 0 || j%period == 0 { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectZigzag() map[int]string { eff := make(map[int]string) colors := make([]byte, 3) for i := range colors { colors[i] = randColor(bright) } period := rand.Intn(7) + 4 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { z := (i + (j % (period * 2))) / period row[j-1] = colors[z%len(colors)] } eff[i] = string(row) } return eff } func effectRainbow() map[int]string { eff := make(map[int]string) rainbow := []byte("ce a9d5b") thickness := rand.Intn(4) + 2 for i := 1; i < 32; i++ { c := rainbow[(i/thickness)%len(rainbow)] eff[i] = string(bytes.Repeat([]byte{c}, 88)) } return eff } func effectRainbowVertical() map[int]string { eff := make(map[int]string) rainbow := []byte("ce a9d5b") thickness := rand.Intn(9) + 4 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { row[j-1] = rainbow[(j/thickness)%len(rainbow)] } eff[i] = string(row) } return eff } func effectWaveHorizontal() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) freq := rand.Float64()*0.3 + 0.1 amp := rand.Intn(6) + 3 for i := 1; i < 32; i++ { row := make([]byte, 88) waveCenter := 15 + int(float64(amp)*math.Sin(float64(i)*freq)) for j := 1; j < 89; j++ { dist := abs(j - waveCenter) if dist < 3 { row[j-1] = c1 } else if dist < 6 { row[j-1] = c2 } else { row[j-1] = '0' } } eff[i] = string(row) } return eff } func effectWaveVertical() map[int]string { eff := make(map[int]string) colors := make([]byte, 4) for i := range colors { colors[i] = randColor(bright) } freq := rand.Float64()*0.2 + 0.1 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { v := int(2*math.Sin(float64(j)*freq) + 2) row[j-1] = colors[v%len(colors)] } eff[i] = string(row) } return eff } func effectCircles() map[int]string { eff := make(map[int]string) colors := make([]byte, 5) for i := range colors { colors[i] = randColor(bright) } cx, cy := 44.0, 15.0 div := rand.Float64()*3.0 + 3.0 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2)) idx := int(dist/div) % len(colors) row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectRadialGradient() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) cx, cy := 44.0, 15.0 maxDist := math.Sqrt(44*44 + 15*15) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2)) t := dist / maxDist if rand.Float64() > t { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectDiamond() map[int]string { eff := make(map[int]string) colors := make([]byte, 3) for i := range colors { colors[i] = randColor(bright) } size := rand.Intn(7) + 4 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { d := (abs(i-16) + abs(j-44)) / size row[j-1] = colors[d%len(colors)] } eff[i] = string(row) } return eff } func effectTriangles() map[int]string { eff := make(map[int]string) colors := make([]byte, 3) for i := range colors { colors[i] = randColor(bright) } period := rand.Intn(9) + 6 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { t := float64(j%period) / float64(period) if t < 0.33 { row[j-1] = colors[0] } else if t < 0.66 { row[j-1] = colors[1] } else { row[j-1] = colors[2] } } eff[i] = string(row) } return eff } func effectBorder() map[int]string { eff := make(map[int]string) border := randColor(bright) fill := randColor(dark) bw := rand.Intn(4) + 2 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if i <= bw || i > 31-bw || j <= bw || j > 88-bw { row[j-1] = border } else { row[j-1] = fill } } eff[i] = string(row) } return eff } func effectDots() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) spacing := rand.Intn(6) + 5 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if (i%spacing) == (spacing/2) && (j%spacing) == (spacing/2) { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectMaze() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) block := rand.Intn(7) + 4 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { bx := (j / block) % 2 by := (i / block) % 2 if bx^by == 1 { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectInterference() map[int]string { eff := make(map[int]string) colors := make([]byte, 3) for i := range colors { colors[i] = randColor(bright) } f1 := rand.Float64()*0.2 + 0.1 f2 := rand.Float64()*0.2 + 0.1 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { v := math.Sin(float64(i)*f1) * math.Sin(float64(j)*f2) idx := 0 if v > 0.3 { idx = 0 } else if v > -0.3 { idx = 1 } else { idx = 2 } row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectVoronoi() map[int]string { eff := make(map[int]string) colors := make([]byte, 4) for i := range colors { colors[i] = randColor(bright) } points := make([][2]int, 4) for i := range points { points[i] = [2]int{rand.Intn(69) + 10, rand.Intn(22) + 5} } for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { minDist := 1<<30 nearest := 0 for idx, p := range points { d := (j-p[0])*(j-p[0]) + (i-p[1])*(i-p[1]) if d < minDist { minDist = d nearest = idx } } row[j-1] = colors[nearest] } eff[i] = string(row) } return eff } func effectSpiral() map[int]string { eff := make(map[int]string) colors := make([]byte, 4) for i := range colors { colors[i] = randColor(bright) } cx, cy := 44.0, 15.0 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { dx := float64(j) - cx dy := float64(i) - cy angle := math.Atan2(dy, dx) dist := math.Sqrt(dx*dx + dy*dy) spiral := (dist + angle*5) / 8 idx := int(spiral) % len(colors) if idx < 0 { idx = -idx } row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectTartan() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) c3 := randColor(bright) hPeriod := rand.Intn(9) + 6 vPeriod := rand.Intn(9) + 6 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { h := (i/(hPeriod/2))%2 == 0 v := (j/(vPeriod/2))%2 == 0 if h && v { row[j-1] = c3 } else if h || v { row[j-1] = c2 } else { row[j-1] = c1 } } eff[i] = string(row) } return eff } func effectBricks() map[int]string { eff := make(map[int]string) brick := randColor(bright) mortar := randColor(dark) h := rand.Intn(4) + 3 w := rand.Intn(9) + 8 for i := 1; i < 32; i++ { row := make([]byte, 88) offset := (i / h) % 2 * (w / 2) for j := 1; j < 89; j++ { bx := (j + offset) % w by := i % h if bx == 0 || by == 0 { row[j-1] = mortar } else { row[j-1] = brick } } eff[i] = string(row) } return eff } func effectRipple() map[int]string { eff := make(map[int]string) colors := make([]byte, 4) for i := range colors { colors[i] = randColor(bright) } cx, cy := 44.0, 15.0 div := rand.Float64()*3.0 + 2.0 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { dist := math.Sqrt(math.Pow(float64(j)-cx, 2) + math.Pow(float64(i)-cy, 2)) idx := int(dist/div) % len(colors) row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectHeatMap() map[int]string { eff := make(map[int]string) colors := []byte("046ec") for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { v := (float64(i) / 31.0) * (float64(j) / 88.0) idx := int(v*float64(len(colors))) % len(colors) row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectPixelSort() map[int]string { eff := make(map[int]string) colors := make([]byte, 5) for i := range colors { colors[i] = randColor(bright) } for i := 1; i < 32; i++ { row := make([]byte, 0, 88) band := rand.Intn(9) + 4 pos := 0 for pos < 88 { c := colors[rand.Intn(len(colors))] w := rand.Intn(band-1) + 2 if pos+w > 88 { w = 88 - pos } for k := 0; k < w; k++ { row = append(row, c) } pos += w } eff[i] = string(row) } return eff } func effectLissajous() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) a := rand.Intn(4) + 2 b := rand.Intn(4) + 2 delta := rand.Float64() * math.Pi curve := make(map[[2]int]bool) for t := 0; t < 1000; t++ { tt := float64(t) * 0.01 x := int(44 + 35*math.Sin(float64(a)*tt+delta)) y := int(15 + 10*math.Sin(float64(b)*tt)) if y >= 1 && y <= 31 && x >= 1 && x <= 88 { curve[[2]int{x, y}] = true } } for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if curve[[2]int{j, i}] { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectTextured() map[int]string { eff := make(map[int]string) base := randColor(dark) accent := randColor(bright) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if rand.Float64() < 0.15 { row[j-1] = accent } else { row[j-1] = base } } eff[i] = string(row) } return eff } func effectHalftone() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { dist := math.Sqrt(math.Pow(float64(j)-44, 2) + math.Pow(float64(i)-15, 2)) threshold := dist / 50.0 if rand.Float64() > threshold { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectPinstripe() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { if j%2 == 0 { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectSunburst() map[int]string { eff := make(map[int]string) colors := make([]byte, 6) for i := range colors { colors[i] = randColor(bright) } cx, cy := 44.0, 15.0 rays := rand.Intn(11) + 6 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { angle := math.Atan2(float64(i)-cy, float64(j)-cx) idx := int((angle+math.Pi)/(2*math.Pi)*float64(rays)) % len(colors) if idx < 0 { idx = -idx } row[j-1] = colors[idx] } eff[i] = string(row) } return eff } func effectBayer() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(dark) bayer := [4][4]int{ {0, 8, 2, 10}, {12, 4, 14, 6}, {3, 11, 1, 9}, {15, 7, 13, 5}, } for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { threshold := float64(bayer[(i-1)%4][(j-1)%4]) / 16.0 if threshold > 0.5 { row[j-1] = c1 } else { row[j-1] = c2 } } eff[i] = string(row) } return eff } func effectWoven() map[int]string { eff := make(map[int]string) c1 := randColor(bright) c2 := randColor(bright) c3 := randColor(dark) period := rand.Intn(5) + 4 for i := 1; i < 32; i++ { row := make([]byte, 88) for j := 1; j < 89; j++ { h := (i/period)%2 == 0 v := (j/period)%2 == 0 if h == v { if h { row[j-1] = c1 } else { row[j-1] = c2 } } else { row[j-1] = c3 } } eff[i] = string(row) } return eff } var effects = []func() map[int]string{ effectSinRand, effectSinRandWorse, effectSin2, effectSin2, effectSin2, effectRand, effectSpeccy2x, effectSpeccy2xPride, effectSpeccy2xPride, effectCheckerboard, effectHorizontalStripes, effectVerticalStripes, effectDiagonalStripes, effectGradientHorizontal, effectGradientVertical, effectPlasma, effectNoise, effectDitheredNoise, effectScanlines, effectCrosshatch, effectZigzag, effectRainbow, effectRainbowVertical, effectWaveHorizontal, effectWaveVertical, effectCircles, effectRadialGradient, effectDiamond, effectTriangles, effectBorder, effectDots, effectMaze, effectInterference, effectVoronoi, effectSpiral, effectTartan, effectBricks, effectRipple, effectHeatMap, effectPixelSort, effectLissajous, effectTextured, effectHalftone, effectPinstripe, effectSunburst, effectBayer, effectWoven, } func compositeWithOverlay(basePixels [][]color.RGBA, overlayPath string) (image.Image, error) { base := image.NewRGBA(image.Rect(0, 0, 88, 31)) for y, row := range basePixels { for x, c := range row { base.SetRGBA(x, y, c) } } overlayFile, err := os.Open(overlayPath) if err != nil { return nil, err } defer overlayFile.Close() overlay, err := png.Decode(overlayFile) if err != nil { return nil, err } if overlay.Bounds().Dx() != 88 || overlay.Bounds().Dy() != 31 { resized := image.NewRGBA(image.Rect(0, 0, 88, 31)) for y := 0; y < 31; y++ { for x := 0; x < 88; x++ { sx := x * overlay.Bounds().Dx() / 88 sy := y * overlay.Bounds().Dy() / 31 resized.Set(x, y, overlay.At(sx+overlay.Bounds().Min.X, sy+overlay.Bounds().Min.Y)) } } overlay = resized } result := image.NewRGBA(image.Rect(0, 0, 88, 31)) draw.Draw(result, result.Bounds(), base, image.Point{}, draw.Src) draw.Draw(result, result.Bounds(), overlay, image.Point{}, draw.Over) return result, nil } func abs(a int) int { if a < 0 { return -a } return a } func main() { var overlayPath, outputPath string flag.StringVar(&overlayPath, "overlay", "overlay.png", "Absolute path to the overlay PNG file") flag.StringVar(&outputPath, "output", "button.png", "Absolute path for the output PNG file") flag.Parse() effectFunc := effects[rand.Intn(len(effects))] eff := effectFunc() pixels := effToPixels(eff) result, err := compositeWithOverlay(pixels, overlayPath) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } out, err := os.Create(outputPath) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } defer out.Close() if err := png.Encode(out, result); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } fmt.Printf("Generated %s\n", outputPath) }