From 5d8d8a34060dead1feed352af245e161f8ffd9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Wed, 22 Mar 2023 19:16:28 +0200 Subject: [PATCH] Improve ANSI escape code support in process_wallpaper.py --- process_wallpaper.py | 86 +++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/process_wallpaper.py b/process_wallpaper.py index a104fc2..f92ab47 100644 --- a/process_wallpaper.py +++ b/process_wallpaper.py @@ -1,5 +1,9 @@ import sys +from collections import namedtuple + +Attribute = namedtuple('Attribute', ['fg', 'bg', 'bold']) + WIDTH = 80 HEIGHT = 25 # ANSI orders the colours black, red, green, yellow, blue, magenta, cyan, white @@ -24,7 +28,7 @@ origin_y = int(sys.argv[6]) assert 0 <= origin_y < HEIGHT chars = [bytearray([0]*HEIGHT) for _ in range(WIDTH)] -attributes = [[(default_fgcolor, default_bgcolor)]*HEIGHT for _ in range(WIDTH)] +attributes = [[(Attribute(default_fgcolor, default_bgcolor, False))]*HEIGHT for _ in range(WIDTH)] with open(infile, 'rb') as f: ansitext = f.read() @@ -33,6 +37,9 @@ x = origin_x y = origin_y fgcolor = default_fgcolor bgcolor = default_bgcolor +bold = False + +error = False line = 1 line_start = 0 @@ -40,31 +47,59 @@ index = 0 while index < len(ansitext): if ansitext[index:].startswith(b'\x1b['): index += len(b'\x1b[') - escape_length = ansitext[index:].index(b'm') - escape = ansitext[index:index+escape_length] - for color_parameter in escape.split(b';'): - color_parameter = int(color_parameter) - if color_parameter == 39: - fgcolor = default_fgcolor - elif color_parameter == 49: - bgcolor = default_bgcolor - elif 30 <= color_parameter <= 37: - fgcolor = color_map[color_parameter - 30] - elif 40 <= color_parameter <= 47: - bgcolor = color_map[color_parameter - 40] - elif 90 <= color_parameter <= 97: - fgcolor = color_map[color_parameter - 90] + 8 - elif 100 <= color_parameter <= 107: - bgcolor = color_map[color_parameter - 100] + 8 - else: - print(f'{line},{index-line_start+1}: Unknown colour escape {color_parameter}') - index += escape_length + len(b'm') + escape_start = index + while index < len(ansitext) and ansitext[index] not in b'CDHJhm': + index += 1 + escape_params = ansitext[escape_start:index] + escape_type = ansitext[index:index+1] + index += 1 + if escape_type == b'C': + x += int(escape_params) + elif escape_type == b'D': + x -= int(escape_params) + elif escape_type == b'H': + row, column = escape_params.split(b';') + y = int(row) - 1 + x = int(column) - 1 + elif escape_type == b'J': + # Erase display + # We just ignore this, because why would you have + # erase command anywhere but at the start + pass + elif escape_type == b'h': + # Something nonstandard, ignore + pass + elif escape_type == b'm': + for color_parameter in escape_params.split(b';'): + color_parameter = int(color_parameter) + if color_parameter == 0: + bold = False + elif color_parameter == 1: + bold = True + elif color_parameter == 39: + fgcolor = default_fgcolor + elif color_parameter == 49: + bgcolor = default_bgcolor + elif 30 <= color_parameter <= 37: + fgcolor = color_map[color_parameter - 30] + elif 40 <= color_parameter <= 47: + bgcolor = color_map[color_parameter - 40] + elif 90 <= color_parameter <= 97: + fgcolor = color_map[color_parameter - 90] + 8 + elif 100 <= color_parameter <= 107: + bgcolor = color_map[color_parameter - 100] + 8 + else: + print(f'{line},{escape_start-line_start+1}: Unknown colour escape {color_parameter}') + error = True + else: + print(f'{line},{escape_start-line_start+1}: Unknown escape ^[[{escape_params.decode()}{escape_type.decode()}') + error = True elif ansitext[index] == 13: x = origin_x index += 1 elif ansitext[index] == 10: for i in range(x, WIDTH): - attributes[i][y] = (fgcolor, bgcolor) + attributes[i][y] = Attribute(fgcolor, bgcolor, bold) x = origin_x y += 1 index += 1 @@ -72,13 +107,16 @@ while index < len(ansitext): line_start = index else: chars[x][y] = ansitext[index] - attributes[x][y] = (fgcolor, bgcolor) + attributes[x][y] = Attribute(fgcolor, bgcolor, bold) index += 1 x += 1 +if error: + sys.exit(1) + with open(outfile, 'wb') as f: for y in range(HEIGHT): for x in range(WIDTH): - fgcolor, bgcolor = attributes[x][y] + fgcolor, bgcolor, bold = attributes[x][y] char = chars[x][y] - f.write(bytes([char, (bgcolor<<4) | fgcolor])) + f.write(bytes([char, (bgcolor<<4) | fgcolor | (8 if bold else 0)]))