diff options
Diffstat (limited to 'chart.go')
| -rw-r--r-- | chart.go | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/chart.go b/chart.go new file mode 100644 index 0000000..dd4ac10 --- /dev/null +++ b/chart.go @@ -0,0 +1,409 @@ +package main + +import ( + "fmt" + "math" + + "github.com/kutuluk/xterm-color-chart/color" + "github.com/nsf/termbox-go" +) + +// обертка над termbox'ом +type Screen struct { + Buffer []termbox.Cell + Width int + Height int +} + +func (s *Screen) reScreen() { + s.Buffer = termbox.CellBuffer() + s.Width, s.Height = termbox.Size() +} + +func (s *Screen) Init() error { + err := termbox.Init() + if err == nil { + s.reScreen() + } + return err +} + +func (s *Screen) Flush() { + termbox.Flush() + s.reScreen() +} + +func (s *Screen) Clear(fg, bg termbox.Attribute) { + termbox.Clear(fg, bg) + s.reScreen() +} + +var screen Screen + +func termNative(c int) termbox.Attribute { + return termbox.Attribute(c + 1) +} + +func printString(x, y int, s string) { + // TODO срабатывает перенос на следующую строку при достижении правого края + // и ошибка при выходе из границ буфера снизу + offsetX := 0 + offsetY := 0 + for _, char := range s { + if char == '\n' { + offsetX = 0 + offsetY++ + } else { + screen.Buffer[x+offsetX+(y+offsetY)*screen.Width].Ch = char + offsetX++ + } + } +} + +func printLine(x, y int, s string) { + printLineAttr(x, y, s, termbox.ColorWhite, background) +} + +func printLineAttr(x, y int, s string, fg, bg termbox.Attribute) { + offsetX := 0 + offsetY := 0 + for _, char := range s { + if char == '\n' { + offsetX = 0 + offsetY++ + } else { + termbox.SetCell(x+offsetX, y+offsetY, char, fg, bg) + offsetX++ + } + } +} + +func DrawColor(x, y int, c int) { + + Grayscale := []byte{ + 16, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 231, + } + + for xx := 0; xx < 13; xx++ { + termbox.SetCell(x+xx, y, ' ', termbox.ColorBlack, termbox.Attribute(c)) + } + + // round(36 * (r * 5) + 6 * (g * 5) + (b * 5) + 16) + // https://gist.github.com/MicahElliott/719710 + + v := int(0.2125*float64(color.XtermRGBPalette[c].R) + 0.7154*float64(color.XtermRGBPalette[c].G) + 0.0721*float64(color.XtermRGBPalette[c].B)) + + fg := termbox.ColorRed + // if v < 128 { + // fg = termbox.ColorWhite + //fg = termbox.Attribute(231) + delta := 64 + center := 128 + if (v > (center - delta)) && (v <= center) { + fg = termbox.Attribute(Grayscale[25]) + } else if (v > center) && (v < (center + delta)) { + fg = termbox.Attribute(Grayscale[0]) + } else { + //fg = termbox.Attribute(Grayscale[12]) + fg = termbox.Attribute(Grayscale[25-int(v/11)]) + } + + printLineAttr(x+1, y, fmt.Sprintf("%03d #%s", int(c), color.XtermRGBPalette[c]), fg, termbox.Attribute(c)) +} + +func DrawBox(left, top, d, l int) { + var approxer string + switch currentComparer { + case 0: + approxer = "CIE76" + case 1: + approxer = "CIE94" + case 2: + approxer = "CIE2000" + } + + r := d / 2 + for y := 0; y < d; y++ { + for x := 0; x < d; x++ { + a := 100.0 * float64(x-r) / float64(r) + b := -100.0 * float64(y-r) / float64(r) + _, c := color.Approximate(color.LabColor{float64(l), a, b}, comparers[currentComparer]) + //termbox.SetCell(x*2+left, y+top, ' ', background, termbox.Attribute(color)) + //termbox.SetCell(x*2+left+1, y+top, ' ', background, termbox.Attribute(color)) + fg := int(background) + if y == 1 || y == 2 || y == d-2 { + fgLab := color.XtermRGBPalette[c-17].Lab() + if l > 50 { + fgLab.L -= 50 + //fgLab.L = 20 + } else { + fgLab.L += 50 + //fgLab.L = 70 + } + _, fg = color.Approximate(fgLab, color.DeltaCIE2000{}) + } + termbox.SetCell(x*2+left, y+top, ' ', termbox.Attribute(fg), termbox.Attribute(c)) + termbox.SetCell(x*2+left+1, y+top, ' ', termbox.Attribute(fg), termbox.Attribute(c)) + } + + } + + labLabel := "CIE L*a*b color space" + if len(labLabel)+4 < d*2 { + printString(left+2, top+1, labLabel) + printString(left+2, top+2, fmt.Sprintf("Lightness = %d%%", l)) + } + //printString(left+2, top+4, fmt.Sprintln("Press Up/Down key for change")) + + approxerLabel := fmt.Sprintf("Approximate by %s algorithm", approxer) + if len(approxerLabel)+4 <= d*2 { + printString(left+2, top+d-2, approxerLabel) + } + //printString(left+2, top+7, fmt.Sprintln("Press Left/Right key for change")) +} + +func DrawCircle(left, top, r int, l float64) { + + var ch [2]rune + point := func(xb, yb int) { + xl := xb / r + yl := yb / r + distance, color := color.Approximate(color.LChColor{l, math.Sqrt(float64(xl*xl) + float64(yl*yl)), 180.0 * math.Atan2(float64(xl), float64(yl))}, comparers[currentComparer]) + //distance, color := color.Palette(color.LabColor{l, float64(xb * 120.0 / r), float64(-yb * 120.0 / r)}, color.DeltaCIE94{}) + if distance < 50 { + ch[0] = ' ' + ch[1] = ' ' + } else { + //ch[0] = '¤' + //ch[1] = '¤' + ch[0] = '(' + ch[1] = ')' + } + termbox.SetCell((xb+r)*2+left, yb+r+top, ch[0], termbox.Attribute(0), termbox.Attribute(color)) + termbox.SetCell((xb+r)*2+left+1, yb+r+top, ch[1], termbox.Attribute(0), termbox.Attribute(color)) + } + + // алгоритм Брезенхэма + line := func(x, y1, y2 int) { + for yf := y1; yf <= y2; yf++ { + point(x, yf) + } + } + + x := 0 + y := r + d := 3 - 2*r + for x <= y { + line(x, -y, y) + line(-x, -y, y) + line(y, -x, x) + line(-y, -x, x) + if d < 0 { + d += 4*x + 6 + } else { + d += 4*(x-y) + 10 + y-- + } + x++ + } +} + +func DrawColorCell(x, y, c int) { + termbox.SetCell(x, y, ' ', termbox.Attribute(1), termbox.Attribute(c)) + termbox.SetCell(x+1, y, ' ', termbox.Attribute(1), termbox.Attribute(c)) +} + +// left, top - левый верхний угол отрисовки палитры +// row - количество кубов 6x6 по горизонтали +// num - признак отрисовки номеров цветов +func DrawPalette(left, top, row int, num bool) { + var numOffset int + if num { + numOffset = 4 + } + + //bh := [2]termbox.Attribute{237, background} + bh := [2]termbox.Attribute{236, background} + //th := [2]termbox.Attribute{232, 241} + th := [2]termbox.Attribute{243, 243} + + cc := 1 + + printLineAttr(left, top, fmt.Sprintln("16 system colors"), text, background) + + printLineAttr(left, top+2, fmt.Sprintf("%3d ", cc-1), th[1], bh[1]) + printLineAttr(left+numOffset+16*2, top+2, fmt.Sprintf(" %-3d", cc+14), th[1], bh[1]) + + for x := 0; x < 16; x++ { + DrawColorCell(left+numOffset+x*2, top+2, cc) + cc++ + } + + padding := 1 + if num { + // padding = 0 + } + + printLineAttr(left, top+4, fmt.Sprintln("216 colors of color cube 6x6x6"), text, background) + col := int(6 / row) // ширина + for l := 0; l < row; l++ { // l - вертикальный счетчик + for k := 0; k < col; k++ { // k - горизонтальный счетчик + for y := 0; y < 6; y++ { + h := y % 2 + if h != 0 { + h = 1 + } + printLineAttr(left+k*numOffset*2+k*(6+padding)*2, top+l*(6+padding)+y+6, fmt.Sprintf("%3d ", cc-1), th[h], bh[h]) + printLineAttr(left+k*numOffset*2+k*(6+padding)*2+16, top+l*(6+padding)+y+6, fmt.Sprintf(" %-3d", cc+4), th[h], bh[h]) + for x := 0; x < 6; x++ { + DrawColorCell(left+numOffset+k*(6+padding)*2+k*numOffset*2+x*2, top+l*(6+padding)+y+6, cc) + cc++ + } + } + } + } + + printLineAttr(left, top+row*7+6, fmt.Sprintln("24 grayscale colors"), text, background) + for y := 0; y < 2; y++ { + for x := 0; x < 12; x++ { + DrawColorCell(left+numOffset+x*2, top+row*7+y+8, cc) + cc++ + } + } + + printLineAttr(left, top+row*7+8, fmt.Sprintf("%3d ", 232), th[1], bh[1]) + printLineAttr(left+28, top+row*7+8, fmt.Sprintf(" %-3d", 243), th[1], bh[1]) + printLineAttr(left, top+row*7+9, fmt.Sprintf("%3d ", 244), th[1], bh[1]) + printLineAttr(left+28, top+row*7+9, fmt.Sprintf(" %-3d ", 255), th[1], bh[1]) +} + +func Fill(x1, y1, x2, y2 int, fg, bg termbox.Attribute) { + for y := y1; y <= y2; y++ { + for x := x1; x <= x2; x++ { + termbox.SetCell(x, y, ' ', fg, bg) + } + } +} + +var ( + text, background termbox.Attribute + lightness int + helpVisible bool +) + +func DrawChart() { + screen.Clear(text, background) + //Fill(0, 0, screen.Width-1, screen.Height-1, text, background) + + Fill(0, 0, screen.Width-1, 0, background, background+8) + printString(2, 0, "XTerm 256 color palette chart") + printString(screen.Width-19, 0, "F1 Help F10 Exit") + printLineAttr(screen.Width-19, 0, "F1", background+20, background+8) + printLineAttr(screen.Width-10, 0, "F10", background+20, background+8) + + paletteSize := 42 + + boxSize := screen.Height - 3 + w := int((screen.Width - paletteSize - 6) / 2) + if w < boxSize { + boxSize = w + } + + DrawBox(2, 2, boxSize, lightness) + // http://snag.gy/XMro8.jpg - картинка для сравнения + + helpText := []string{ + "Control keys:", + "", + "F1 - show/hide this help", + "Up/Down - change lightness", + "Left/Right - change approximation method", + "", + "CIE76 - fastest", + "CIE94 - middle", + "CIE2000 - slowest", + "", + "", + } + + xc := boxSize*2 + 4 + if xc < 2 { + xc = 2 + } + yc := 2 + + if helpVisible { + for i, line := range helpText { + printString(xc, yc+i, line) + } + } else { + DrawPalette(xc, yc, 3, true) + } + + screen.Flush() +} + +var comparers []color.Comparer +var currentComparer int + +func main() { + + err := screen.Init() + if err != nil { + panic(err) + } + defer termbox.Close() + termbox.SetOutputMode(termbox.Output256) + //termbox.SetInputMode(termbox.InputEsc) + + background = termNative(234) + text = background + 12 + lightness = 100 + + comparers = append(comparers, color.DeltaCIE76{}, color.DeltaCIE94{}, color.DeltaCIE2000{}) + + //size := int(h/2 - 3) + //DrawCircle(2, 1, size, 1.0) + + DrawChart() + + for loop := true; loop; { + switch ev := termbox.PollEvent(); ev.Type { + case termbox.EventKey: + switch ev.Key { + case termbox.KeyCtrlQ, termbox.KeyF10: + loop = false + case termbox.KeyCtrlH, termbox.KeyF1: + helpVisible = !helpVisible + DrawChart() + case termbox.KeyArrowUp: + if lightness < 100 { + lightness = lightness + 10.0 + DrawChart() + } + case termbox.KeyArrowDown: + if lightness > 0 { + lightness = lightness - 10.0 + DrawChart() + } + case termbox.KeyArrowLeft: + if currentComparer > 0 { + currentComparer-- + } else { + currentComparer = len(comparers) - 1 + } + DrawChart() + case termbox.KeyArrowRight: + if currentComparer < 2 { + currentComparer++ + } else { + currentComparer = 0 + } + DrawChart() + } + case termbox.EventResize: + DrawChart() + } + } +} |
