diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rwxr-xr-x | colorcube (renamed from colorcube.py) | 0 | ||||
-rwxr-xr-x | gifterm | 55 | ||||
-rwxr-xr-x | gifterm.py | 123 | ||||
-rwxr-xr-x | pixelterm | 28 | ||||
-rwxr-xr-x | pixelterm.py | 25 | ||||
-rwxr-xr-x | pngmeta (renamed from pngmeta.py) | 0 | ||||
-rwxr-xr-x | resolvecolor (renamed from resolvecolor.py) | 0 | ||||
-rwxr-xr-x | setup.py | 50 | ||||
-rwxr-xr-x | unpixelterm | 38 | ||||
-rwxr-xr-x | unpixelterm.py | 26 |
11 files changed, 176 insertions, 173 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d7bfbb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build +dist +pixelterm.egg-info +__pycache__ @@ -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/gifterm.py b/gifterm.py deleted file mode 100755 index cef85b9..0000000 --- a/gifterm.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python - -import os, sys, argparse, os.path, json, time, signal, atexit -#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' - -formatter = terminal256.Terminal256Formatter() -reset_sequence = terminal256.EscapeSequence(fg=formatter._closest_color(0,0,0), bg=formatter._closest_color(0,0,0)).reset_string() - -def termify_pixels(img): - sx, sy = img.size - out = '' - - fg,bg = None,None - fgd,bgd = {},{} - def bgescape(color): - nonlocal bg, bgd - if bg == color: - return '' - bg=color - if color == (0,0,0,0): - return '\033[49m' - if color in bgd: - return bgd[color] - r,g,b,_ = color - bgd[color] = '\033[48;5;'+str(formatter._closest_color(r,g,b))+'m' - return bgd[color] - - def fgescape(color): - nonlocal fg, fgd - if fg == color: - return '' - fg=color - r,g,b,_ = color - fgd[color] = '\033[38;5;'+str(formatter._closest_color(r,g,b))+'m' - return fgd[color] - - def balloon(x,y): - if x+1 == img.size[0] or img.im.getpixel((x+1, y)) != (0,255,0,127): - w = 1 - while x-w >= 0 and img.im.getpixel((x-w, y)) == (0,255,0,127): - w += 1 - return '$balloon{}$'.format(w) - return '' - - for y in range(0, sy, 2): - for x in range(sx): - coltop = img.im.getpixel((x, y)) - colbot = img.im.getpixel((x, y+1)) if y+1 < img.size[1] else (0,0,0,0) - - if coltop[3] == 127: #Control colors - out += reset_sequence - out += {(255, 0, 0, 127): lambda x,y:'$\\$', - (0, 0, 255, 127): lambda x,y:'$/$', - (0, 255, 0, 127): balloon - }.get(coltop, lambda x,y:' ')(x,y) - continue - - if coltop[3] != 255: - coltop = (0,0,0,0) - if colbot[3] != 255: - colbot = (0,0,0,0) - - #Da magicks: ▀█▄ - c,cf = '▀','█' - te,be = fgescape,bgescape - if coltop == (0,0,0,0) or ((coltop == bg or colbot == fg) and not colbot == (0,0,0,0)): - c,cf,te,be = '▄',' ',be,te - if colbot == coltop: - c,te,be = cf,te,te - out += te(coltop) + be(colbot) + c - out = (out.rstrip() if bg == (0,0,0,0) else out) + '\n' - return out[:-1] + reset_sequence + '\n' - -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(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, reset_sequence) - print(frame) - time.sleep(img.info['duration']/1000.0) - diff --git a/pixelterm b/pixelterm new file mode 100755 index 0000000..f893875 --- /dev/null +++ b/pixelterm @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +import os, sys, argparse, os.path, json, pixelterm +from PIL import Image, PngImagePlugin + +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() + for f in args.image: + 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['_comment'] + del metadata['_comment'] + metadataarea = '$$$\n' +\ + '\n'.join([ '\n'.join([ k.upper() + ': ' + v for v in metadata[k] ]) for k in sorted(metadata.keys()) ]) +\ + '\n' + comment +\ + '\n$$$\n' + with open(output, 'w') as of: + of.write(metadataarea) + of.write(pixelterm.termify_pixels(img)) + else: + print(pixelterm.termify_pixels(img)) diff --git a/pixelterm.py b/pixelterm.py index ab4409c..1543663 100755 --- a/pixelterm.py +++ b/pixelterm.py @@ -1,12 +1,10 @@ #!/usr/bin/env python -import os, sys, argparse, os.path, json #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, PngImagePlugin formatter = terminal256.Terminal256Formatter() reset_sequence = terminal256.EscapeSequence(fg=formatter._closest_color(0,0,0), bg=formatter._closest_color(0,0,0)).reset_string() @@ -76,26 +74,3 @@ 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__': - 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() - for f in args.image: - 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['_comment'] - del metadata['_comment'] - metadataarea = '$$$\n' +\ - '\n'.join([ '\n'.join([ k.upper() + ': ' + v for v in metadata[k] ]) for k in sorted(metadata.keys()) ]) +\ - '\n' + comment +\ - '\n$$$\n' - with open(output, 'w') as of: - of.write(metadataarea) - of.write(termify_pixels(img)) - else: - print(termify_pixels(img)) diff --git a/resolvecolor.py b/resolvecolor index 7dc6537..7dc6537 100755 --- a/resolvecolor.py +++ b/resolvecolor diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..983d45a --- /dev/null +++ b/setup.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +from setuptools import setup + +import os, os.path +import sys + +ver = "1.0" + +def read(filename): + return open(os.path.join(os.path.dirname(__file__), filename)).read() + + + +if sys.version_info < (3,0): + print('Oops, only python >= 3.0 supported!') + sys.exit() + +setup(name = 'pixelterm', + version = ver, + description = 'Render pixely images on your terminal. Now also with animated GIF support.', + license = 'BSD', + author = 'jaseg', + author_email = 'pixelterm@jaseg.net', + url = 'https://github.com/jaseg/pixelterm', + py_modules = ['pixelterm', 'unpixelterm'], + scripts = ['pixelterm', + 'unpixelterm', + 'colorcube', + 'gifterm', + 'resolvecolor', + 'pngmeta'], + zip_safe = True, + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: Information Technology', + 'Intended Audience :: Intended Audience :: End Users/Desktop', + 'License :: Freely Distributable', + 'License :: OSI Approved :: BSD License', + 'Programming Language :: Python :: 3', + 'Topic :: Internet', + 'Topic :: Graphics', + 'Topic :: System :: Networking' + 'Topic :: Text Processing :: Filters', + 'Topic :: Utilities', + ], + + long_description = read('README.md'), + dependency_links = [], +) diff --git a/unpixelterm b/unpixelterm new file mode 100755 index 0000000..4556d07 --- /dev/null +++ b/unpixelterm @@ -0,0 +1,38 @@ +#!/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 416a057..234d3d1 100755 --- a/unpixelterm.py +++ b/unpixelterm.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -import os, sys, argparse, os.path, json +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), @@ -99,27 +99,3 @@ def unpixelterm(text): x, y = 0, y+2 return img, metadata -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(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) |