main.go (5318B)
1 package main 2 3 import ( 4 "fmt" 5 "image/color" 6 "image/png" 7 "os" 8 "sort" 9 "strings" 10 ) 11 12 func main() { 13 14 in := `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` 61 maskFile := "mask.png" 62 outFile := "out.html" 63 64 f, _ := os.Open(maskFile) 65 im, _ := png.Decode(f) 66 67 lines := strings.Split(in, "\n") 68 w := len(lines[0]) 69 h := len(lines) 70 71 classPrefix := "gpg_" 72 prevClass := "" 73 colorsMap := make(map[string]string) 74 colorsArr := [][]string{} 75 for y := 0; y < h; y++ { 76 for x := 0; x < w; x++ { 77 c := im.At(x, y) 78 hex := HexFromRgbColor(c.(color.NRGBA)) 79 if _, ok := colorsMap[hex]; ok { 80 continue 81 } 82 prevClass = getNextClassNameStr(prevClass) 83 className := classPrefix + prevClass 84 colorsMap[hex] = className 85 colorsArr = append(colorsArr, []string{className, hex}) 86 } 87 } 88 sort.Slice(colorsArr, func(i, j int) bool { 89 return colorsArr[i][0] < colorsArr[j][0] 90 }) 91 92 out := "" 93 out += "<style>\n" 94 for _, v := range colorsArr { 95 out += fmt.Sprintf(".%s{color:%s}\n", v[0], v[1]) 96 } 97 out += "</style>\n" 98 out += "<div style=\"font-family: monospace; background-color: #222;\">\n" 99 out += "<pre>\n" 100 spanOpen := false 101 prevClass = "" 102 for y := 0; y < h; y++ { 103 for x := 0; x < w; x++ { 104 c := im.At(x, y) 105 if len(lines[y]) <= x { 106 break 107 } 108 char := lines[y][x] 109 hex := HexFromRgbColor(c.(color.NRGBA)) 110 class := colorsMap[hex] 111 if class != prevClass { 112 prevClass = class 113 if spanOpen { 114 out += "</span>" 115 } 116 out += fmt.Sprintf(`<span class="%s">`, class) 117 spanOpen = true 118 } 119 out += string(char) 120 } 121 out += "\n" 122 } 123 if spanOpen { 124 out += "</span>" 125 } 126 out += "</pre>\n" 127 out += "</div>" 128 129 _ = os.WriteFile(outFile, []byte(out), 0644) 130 } 131 132 func HexFromRgbColor(color color.NRGBA) string { 133 return fmt.Sprintf("#%X%X%X", color.R, color.G, color.B) 134 } 135 136 const firstRune = 'a' 137 const lastRune = 'z' 138 139 func getNextClassNameStr(in string) string { 140 return string(getNextClassName([]rune(in))) 141 } 142 143 func getNextClassName(in []rune) (out []rune) { 144 out = in 145 for i := len(out) - 1; i >= 0; i-- { 146 if out[i] < lastRune { 147 out[i]++ 148 return 149 } 150 out[i] = firstRune 151 } 152 return append([]rune{firstRune}, out...) 153 } 154 155 func getClassName(idx int) string { 156 out := []rune{firstRune} 157 for counter := 0; counter < idx; counter++ { 158 out = getNextClassName(out) 159 } 160 return string(out) 161 }