From 5e763123f87422e00810bacc0346936a2ae52d3d Mon Sep 17 00:00:00 2001 From: jaseg Date: Tue, 30 Jul 2013 13:33:07 +0200 Subject: Removed standard colors 0-15 for portability. Removed pygments dep. Fixed setup.py --- colorcube | 23 ----------------------- colorcube.py | 23 +++++++++++++++++++++++ gifterm | 55 ------------------------------------------------------- gifterm.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ pixelterm | 36 ------------------------------------ pixelterm.py | 47 ++++++++++++++++++++++++++++++++++++++--------- pngmeta | 11 ----------- pngmeta.py | 11 +++++++++++ resolvecolor | 15 --------------- resolvecolor.py | 13 +++++++++++++ setup.py | 17 +++++++++-------- unpixelterm | 38 -------------------------------------- unpixelterm.py | 39 ++++++++++++++++++++++++++++----------- xtermcolors.py | 21 +++++++++++++++++++++ 14 files changed, 198 insertions(+), 206 deletions(-) delete mode 100755 colorcube create mode 100755 colorcube.py delete mode 100755 gifterm create mode 100755 gifterm.py delete mode 100755 pixelterm delete mode 100755 pngmeta create mode 100755 pngmeta.py delete mode 100755 resolvecolor create mode 100755 resolvecolor.py delete mode 100755 unpixelterm create mode 100644 xtermcolors.py diff --git a/colorcube b/colorcube deleted file mode 100755 index ebf36b9..0000000 --- a/colorcube +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json - -# Display an xterm-256color color palette on the terminal, including color ids - -reset_sequence = '\033[39;49m' - -def esc(i): - return '\033[48;5;'+str(i)+'m' - -print(''.join([str(i).ljust(4) for i in range(16)])) -print(' '.join([esc(i) for i in range(16)])+' ' + reset_sequence) - -for j in range(6): - for k in range(6): - c = 16+j*6+k*6*6 - print(''.join([str(c+i).ljust(4) for i in range(6)])) - print(' '.join([esc(c+i) for i in range(6)])+' ' + reset_sequence) - -print(''.join([str(i).ljust(4) for i in range(16+6*6*6, 16+6*6*6+24)])) -print(' '.join([esc(i) for i in range(16+6*6*6, 16+6*6*6+24)])+' ' + reset_sequence) - diff --git a/colorcube.py b/colorcube.py new file mode 100755 index 0000000..ebf36b9 --- /dev/null +++ b/colorcube.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +import os, sys, argparse, os.path, json + +# Display an xterm-256color color palette on the terminal, including color ids + +reset_sequence = '\033[39;49m' + +def esc(i): + return '\033[48;5;'+str(i)+'m' + +print(''.join([str(i).ljust(4) for i in range(16)])) +print(' '.join([esc(i) for i in range(16)])+' ' + reset_sequence) + +for j in range(6): + for k in range(6): + c = 16+j*6+k*6*6 + print(''.join([str(c+i).ljust(4) for i in range(6)])) + print(' '.join([esc(c+i) for i in range(6)])+' ' + reset_sequence) + +print(''.join([str(i).ljust(4) for i in range(16+6*6*6, 16+6*6*6+24)])) +print(' '.join([esc(i) for i in range(16+6*6*6, 16+6*6*6+24)])+' ' + reset_sequence) + diff --git a/gifterm b/gifterm deleted file mode 100755 index 99cbb5f..0000000 --- a/gifterm +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json, time, signal, atexit, pixelterm -#NOTE: This script uses pygments for RGB->X256 conversion since pygments is -#readily available. If you do not like pygments (e.g. because it is large), -#you could patch in something like https://github.com/magarcia/python-x256 -#(but don't forget to send me a pull request ;) -from pygments.formatters import terminal256 -from PIL import Image, GifImagePlugin, ImageSequence - -clear_screen = '\033[H\033[2J' -cursor_invisible = '\033[?25l' -cursor_visible = '\033[?25h' - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Render pixel images on 256-color ANSI terminals') - parser.add_argument('image', type=str) - parser.add_argument('-s', '--size', type=str, help='Terminal size, [W]x[H]') - args = parser.parse_args() - - tw, th = os.get_terminal_size() - th = th*2 - if args.size: - tw, th = map(int, args.size.split('x')) - - img = Image.open(args.image) - palette = img.getpalette() - last_frame = Image.new("RGBA", img.size) - frames = [] - - for frame in ImageSequence.Iterator(img): - #This works around a known bug in Pillow - #See also: http://stackoverflow.com/questions/4904940/python-converting-gif-frames-to-png - frame.putpalette(palette) - c = frame.convert("RGBA") - - if img.info['background'] != img.info['transparency']: - last_frame.paste(c, c) - else: - last_frame = c - - im = last_frame.copy() - im.thumbnail((tw, th), Image.NEAREST) - frames.append(pixelterm.termify_pixels(im)) - - print(cursor_invisible) - atexit.register(lambda:print(cursor_visible)) - signal.signal(signal.SIGTERM, lambda signum, stack_frame: exit(1)) - - while True: - for frame in frames: - print(clear_screen, pixelterm.reset_sequence) - print(frame) - time.sleep(img.info['duration']/1000.0) - diff --git a/gifterm.py b/gifterm.py new file mode 100755 index 0000000..99cbb5f --- /dev/null +++ b/gifterm.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +import os, sys, argparse, os.path, json, time, signal, atexit, pixelterm +#NOTE: This script uses pygments for RGB->X256 conversion since pygments is +#readily available. If you do not like pygments (e.g. because it is large), +#you could patch in something like https://github.com/magarcia/python-x256 +#(but don't forget to send me a pull request ;) +from pygments.formatters import terminal256 +from PIL import Image, GifImagePlugin, ImageSequence + +clear_screen = '\033[H\033[2J' +cursor_invisible = '\033[?25l' +cursor_visible = '\033[?25h' + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Render pixel images on 256-color ANSI terminals') + parser.add_argument('image', type=str) + parser.add_argument('-s', '--size', type=str, help='Terminal size, [W]x[H]') + args = parser.parse_args() + + tw, th = os.get_terminal_size() + th = th*2 + if args.size: + tw, th = map(int, args.size.split('x')) + + img = Image.open(args.image) + palette = img.getpalette() + last_frame = Image.new("RGBA", img.size) + frames = [] + + for frame in ImageSequence.Iterator(img): + #This works around a known bug in Pillow + #See also: http://stackoverflow.com/questions/4904940/python-converting-gif-frames-to-png + frame.putpalette(palette) + c = frame.convert("RGBA") + + if img.info['background'] != img.info['transparency']: + last_frame.paste(c, c) + else: + last_frame = c + + im = last_frame.copy() + im.thumbnail((tw, th), Image.NEAREST) + frames.append(pixelterm.termify_pixels(im)) + + print(cursor_invisible) + atexit.register(lambda:print(cursor_visible)) + signal.signal(signal.SIGTERM, lambda signum, stack_frame: exit(1)) + + while True: + for frame in frames: + print(clear_screen, pixelterm.reset_sequence) + print(frame) + time.sleep(img.info['duration']/1000.0) + diff --git a/pixelterm b/pixelterm deleted file mode 100755 index 79c9cd2..0000000 --- a/pixelterm +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json -import pixelterm -from multiprocessing import Pool -from PIL import Image, PngImagePlugin - -def convert(f): - img = Image.open(f).convert("RGBA") - if args.output_dir: - print(f) - foo, _, _ = f.rpartition('.png') - output = os.path.join(args.output_dir, os.path.basename(foo)+'.pony') - metadata = json.loads(img.info.get('pixelterm-metadata')) - comment = metadata.get('_comment') - if comment is not None: - del metadata['_comment'] - comment = '\n'+comment - else: - comment = '' - metadataarea = '$$$\n' +\ - '\n'.join([ '\n'.join([ k.upper() + ': ' + v for v in metadata[k] ]) for k in sorted(metadata.keys()) ]) +\ - comment + '\n$$$\n' - with open(output, 'w') as of: - of.write(metadataarea) - of.write(pixelterm.termify_pixels(img)) - else: - print(pixelterm.termify_pixels(img)) - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Render pixel images on 256-color ANSI terminals') - parser.add_argument('image', type=str, nargs='*') - parser.add_argument('-d', '--output-dir', type=str, help='Output directory (if not given, output to stdout)') - args = parser.parse_args() - p = Pool() - p.map(convert, args.image) diff --git a/pixelterm.py b/pixelterm.py index 1543663..8b4fabf 100644 --- a/pixelterm.py +++ b/pixelterm.py @@ -1,13 +1,8 @@ #!/usr/bin/env python -#NOTE: This script uses pygments for RGB->X256 conversion since pygments is -#readily available. If you do not like pygments (e.g. because it is large), -#you could patch in something like https://github.com/magarcia/python-x256 -#(but don't forget to send me a pull request ;) -from pygments.formatters import terminal256 +import xtermcolors -formatter = terminal256.Terminal256Formatter() -reset_sequence = terminal256.EscapeSequence(fg=formatter._closest_color(0,0,0), bg=formatter._closest_color(0,0,0)).reset_string() +reset_sequence = '\033[39;49m' def termify_pixels(img): sx, sy = img.size @@ -25,7 +20,7 @@ def termify_pixels(img): if color in bgd: return bgd[color] r,g,b,_ = color - bgd[color] = '\033[48;5;'+str(formatter._closest_color(r,g,b))+'m' + bgd[color] = '\033[48;5;'+str(xtermcolors.closest_color(r,g,b))+'m' return bgd[color] def fgescape(color): @@ -34,7 +29,7 @@ def termify_pixels(img): return '' fg=color r,g,b,_ = color - fgd[color] = '\033[38;5;'+str(formatter._closest_color(r,g,b))+'m' + fgd[color] = '\033[38;5;'+str(xtermcolors.closest_color(r,g,b))+'m' return fgd[color] def balloon(x,y): @@ -74,3 +69,37 @@ def termify_pixels(img): out = (out.rstrip() if bg == (0,0,0,0) else out) + '\n' return out[:-1] + reset_sequence + '\n' +if __name__ == '__main__': + import os, sys, argparse, os.path, json + from multiprocessing import Pool + from PIL import Image, PngImagePlugin + + parser = argparse.ArgumentParser(description='Render pixel images on 256-color ANSI terminals') + parser.add_argument('image', type=str, nargs='*') + parser.add_argument('-d', '--output-dir', type=str, help='Output directory (if not given, output to stdout)') + args = parser.parse_args() + + def convert(f): + img = Image.open(f).convert("RGBA") + if args.output_dir: + print(f) + foo, _, _ = f.rpartition('.png') + output = os.path.join(args.output_dir, os.path.basename(foo)+'.pony') + metadata = json.loads(img.info.get('pixelterm-metadata')) + comment = metadata.get('_comment') + if comment is not None: + del metadata['_comment'] + comment = '\n'+comment + else: + comment = '' + metadataarea = '$$$\n' +\ + '\n'.join([ '\n'.join([ k.upper() + ': ' + v for v in metadata[k] ]) for k in sorted(metadata.keys()) ]) +\ + comment + '\n$$$\n' + with open(output, 'w') as of: + of.write(metadataarea) + of.write(termify_pixels(img)) + else: + print(termify_pixels(img)) + + p = Pool() + p.map(convert, args.image) diff --git a/pngmeta b/pngmeta deleted file mode 100755 index e6d9b6b..0000000 --- a/pngmeta +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse -from PIL import Image, PngImagePlugin - -parser = argparse.ArgumentParser(description='Print PNG metadata') -parser.add_argument('image', type=str) -args = parser.parse_args() -img = Image.open(args.image) -for k, v in img.info.items(): - print('{:15}: {}'.format(k, v)) diff --git a/pngmeta.py b/pngmeta.py new file mode 100755 index 0000000..e6d9b6b --- /dev/null +++ b/pngmeta.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python + +import os, sys, argparse +from PIL import Image, PngImagePlugin + +parser = argparse.ArgumentParser(description='Print PNG metadata') +parser.add_argument('image', type=str) +args = parser.parse_args() +img = Image.open(args.image) +for k, v in img.info.items(): + print('{:15}: {}'.format(k, v)) diff --git a/resolvecolor b/resolvecolor deleted file mode 100755 index 7dc6537..0000000 --- a/resolvecolor +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json, re -from pygments.formatters import terminal256 - -formatter = terminal256.Terminal256Formatter() - -# Resolve HTML-style hex RGB color codes to xterm-256color color numbers - -if len(sys.argv) != 2: - print('Usage: resolvecolor.py #RRGGBB') - exit() - -print(formatter._closest_color(*[int(s, 16) for s in re.match('#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})', sys.argv[1]).groups()])) - diff --git a/resolvecolor.py b/resolvecolor.py new file mode 100755 index 0000000..988b5cd --- /dev/null +++ b/resolvecolor.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python + +import os, sys, argparse, os.path, json, re +import xtermcolors + +# Resolve HTML-style hex RGB color codes to xterm-256color color numbers + +if len(sys.argv) != 2: + print('Usage: resolvecolor.py #RRGGBB') + exit() + +print(xtermcolors.closest_color(*[int(s, 16) for s in re.match('#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})', sys.argv[1]).groups()])) + diff --git a/setup.py b/setup.py index 983d45a..14213e5 100755 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools import setup import os, os.path import sys -ver = "1.0" +ver = "1.1" def read(filename): return open(os.path.join(os.path.dirname(__file__), filename)).read() @@ -22,13 +22,14 @@ setup(name = 'pixelterm', author = 'jaseg', author_email = 'pixelterm@jaseg.net', url = 'https://github.com/jaseg/pixelterm', - py_modules = ['pixelterm', 'unpixelterm'], - scripts = ['pixelterm', - 'unpixelterm', - 'colorcube', - 'gifterm', - 'resolvecolor', - 'pngmeta'], + py_modules = ['pixelterm', 'unpixelterm', 'xtermcolors'], + install_requires=['pillow'], + scripts = ['pixelterm.py', + 'unpixelterm.py', + 'colorcube.py', + 'gifterm.py', + 'resolvecolor.py', + 'pngmeta.py'], zip_safe = True, classifiers = [ 'Development Status :: 5 - Production/Stable', diff --git a/unpixelterm b/unpixelterm deleted file mode 100755 index 4556d07..0000000 --- a/unpixelterm +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json, unpixelterm -#NOTE: This script uses pygments for X256->RGB conversion since pygments is -#readily available. If you do not like pygments (e.g. because it is large), -#you could patch in something like https://github.com/magarcia/python-x256 -#(but don't forget to send me a pull request ;) -from pygments.formatters import terminal256 -from PIL import Image, PngImagePlugin -try: - import re2 as re -except: - import re - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Convert images rendered by pixelterm-like utilities back to PNG') - parser.add_argument('-v', '--verbose', action='store_true') - output_group = parser.add_mutually_exclusive_group() - output_group.add_argument('-o', '--output', type=str, help='Output file name, defaults to ${input%.pony}.png') - output_group.add_argument('-d', '--output-dir', type=str, help='Place output files here') - parser.add_argument('input', type=argparse.FileType('r'), nargs='+') - args = parser.parse_args() - if len(args.input) > 1 and args.output: - parser.print_help() - print('You probably do not want to overwrite the given output file {} times.'.format(len(args.input))) - sys.exit(1) - - for f in args.input: - if len(args.input) > 1: - print(f.name) - img, metadata = unpixelterm.unpixelterm(f.read()) - pnginfo = PngImagePlugin.PngInfo() - pnginfo.add_text('pixelterm-metadata', json.dumps(metadata)) - foo, _, _ = f.name.rpartition('.pony') - output = args.output or foo+'.png' - if args.output_dir: - output = os.path.join(args.output_dir, os.path.basename(output)) - img.save(output, 'PNG', pnginfo=pnginfo) diff --git a/unpixelterm.py b/unpixelterm.py index 234d3d1..d9b1498 100644 --- a/unpixelterm.py +++ b/unpixelterm.py @@ -2,22 +2,13 @@ import os, sys, os.path from collections import defaultdict -#NOTE: This script uses pygments for X256->RGB conversion since pygments is -#readily available. If you do not like pygments (e.g. because it is large), -#you could patch in something like https://github.com/magarcia/python-x256 -#(but don't forget to send me a pull request ;) -from pygments.formatters import terminal256 +import xtermcolors from PIL import Image, PngImagePlugin try: import re2 as re except: import re -formatter = terminal256.Terminal256Formatter() -#HACK this adds two missing entries to pygment's color table -formatter.xterm_colors.append((0xe4, 0xe4, 0xe4)) -formatter.xterm_colors.append((0xee, 0xee, 0xee)) - def parse_escape_sequence(seq): codes = list(map(int, seq[2:-1].split(';'))) fg, bg = None, None @@ -25,7 +16,7 @@ def parse_escape_sequence(seq): while i 1 and args.output: + parser.print_help() + print('You probably do not want to overwrite the given output file {} times.'.format(len(args.input))) + sys.exit(1) + + for f in args.input: + if len(args.input) > 1: + print(f.name) + img, metadata = unpixelterm(f.read()) + pnginfo = PngImagePlugin.PngInfo() + pnginfo.add_text('pixelterm-metadata', json.dumps(metadata)) + foo, _, _ = f.name.rpartition('.pony') + output = args.output or foo+'.png' + if args.output_dir: + output = os.path.join(args.output_dir, os.path.basename(output)) + img.save(output, 'PNG', pnginfo=pnginfo) diff --git a/xtermcolors.py b/xtermcolors.py new file mode 100644 index 0000000..36cddc6 --- /dev/null +++ b/xtermcolors.py @@ -0,0 +1,21 @@ + +xterm_colors = [] + +# This is ripped out of pygments +# I leave out the 16 standard colors since people tend to re-define them to their liking. + +# colors 16..232: the 6x6x6 color cube +_valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) +for i in range(217): + r = _valuerange[(i // 36) % 6] + g = _valuerange[(i // 6) % 6] + b = _valuerange[i % 6] + xterm_colors.append((r, g, b)) + +# colors 233..253: grayscale +for i in range(1, 24): + v = 8 + i * 10 + xterm_colors.append((v, v, v)) + +def closest_color(r, g, b): + return 16+min([ ((r-rt)**2+(g-gt)**2+(b-bt)**2, i) for i,(rt,gt,bt) in enumerate(xterm_colors) ])[1] -- cgit