Skip to content

Instantly share code, notes, and snippets.

@yoichi
Last active July 10, 2020 10:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoichi/4c5f90aacede9f84422da794e1a945a4 to your computer and use it in GitHub Desktop.
Save yoichi/4c5f90aacede9f84422da794e1a945a4 to your computer and use it in GitHub Desktop.
"""Convert truecolor escape sequence to 256 color escape sequence
* \x1b[38;2;{red};{green};{blue}m -> \x1b[38;5;{color}m (foreground)
* \x1b[48;2;{red};{green};{blue}m -> \x1b[48;5;{color}m (background)
where 0 <= red, green, blue <= 255 represents 24-bit color
and 16 <= color <= 231
The logic is based on the colour_find_rgb() in tmux/colour.c
Original copyright notice is:
Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
Copyright (c) 2016 Avi Halachmi <avihpit@yahoo.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""
import re
def to_6(n):
"256 color to 6"
if n < 48:
return 0
if n < 114:
return 1
return (n-35) // 40
def from_6(q):
"6 to 256"
q2c = [0, 95, 135, 175, 215, 255]
return q2c[q]
def dist_sq(a, b):
return sum((p-q)*(p-q) for p, q in zip(a, b))
def truecolor_to_256(s):
pattern = re.compile(r"\x1b\[([34]8);2;(\d+);(\d+);(\d+)((;\d+)*)m")
def repl(m):
r, g, b = map(int, (m[2], m[3], m[4]))
# 6x6x6
qr = to_6(r)
qg = to_6(g)
qb = to_6(b)
# grey
grey_avg = (r + g + b) // 3
if grey_avg > 238:
grey_idx = 23
else:
grey_idx = (grey_avg - 3) // 10
grey = grey_idx*10 + 8
# use closer one
d = dist_sq(map(from_6, (qr, qg, qb)), (r, g, b))
if dist_sq((grey, grey, grey), (r, g, b)) < d:
c = grey_idx + 232
else:
c = qr*36 + qg*6 + qb + 16
return f'\x1b[{m[1]};5;{c}{m[5]}m'
return re.sub(pattern, repl, s)
if __name__ == '__main__':
import sys
sys.stdout.write(truecolor_to_256(sys.stdin.read()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment