dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

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 }