Removed standard colors 0-15 for portability. Removed pygments dep. Fixed setup.py
This commit is contained in:
parent
76579920ef
commit
5e763123f8
11 changed files with 109 additions and 117 deletions
36
pixelterm
36
pixelterm
|
|
@ -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)
|
|
||||||
47
pixelterm.py
47
pixelterm.py
|
|
@ -1,13 +1,8 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
|
|
||||||
#NOTE: This script uses pygments for RGB->X256 conversion since pygments is
|
import xtermcolors
|
||||||
#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
|
|
||||||
|
|
||||||
formatter = terminal256.Terminal256Formatter()
|
reset_sequence = '\033[39;49m'
|
||||||
reset_sequence = terminal256.EscapeSequence(fg=formatter._closest_color(0,0,0), bg=formatter._closest_color(0,0,0)).reset_string()
|
|
||||||
|
|
||||||
def termify_pixels(img):
|
def termify_pixels(img):
|
||||||
sx, sy = img.size
|
sx, sy = img.size
|
||||||
|
|
@ -25,7 +20,7 @@ def termify_pixels(img):
|
||||||
if color in bgd:
|
if color in bgd:
|
||||||
return bgd[color]
|
return bgd[color]
|
||||||
r,g,b,_ = 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]
|
return bgd[color]
|
||||||
|
|
||||||
def fgescape(color):
|
def fgescape(color):
|
||||||
|
|
@ -34,7 +29,7 @@ def termify_pixels(img):
|
||||||
return ''
|
return ''
|
||||||
fg=color
|
fg=color
|
||||||
r,g,b,_ = 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]
|
return fgd[color]
|
||||||
|
|
||||||
def balloon(x,y):
|
def balloon(x,y):
|
||||||
|
|
@ -74,3 +69,37 @@ def termify_pixels(img):
|
||||||
out = (out.rstrip() if bg == (0,0,0,0) else out) + '\n'
|
out = (out.rstrip() if bg == (0,0,0,0) else out) + '\n'
|
||||||
return out[:-1] + reset_sequence + '\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)
|
||||||
|
|
|
||||||
15
resolvecolor
15
resolvecolor
|
|
@ -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()]))
|
|
||||||
|
|
||||||
13
resolvecolor.py
Executable file
13
resolvecolor.py
Executable file
|
|
@ -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()]))
|
||||||
|
|
||||||
17
setup.py
17
setup.py
|
|
@ -4,7 +4,7 @@ from setuptools import setup
|
||||||
import os, os.path
|
import os, os.path
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
ver = "1.0"
|
ver = "1.1"
|
||||||
|
|
||||||
def read(filename):
|
def read(filename):
|
||||||
return open(os.path.join(os.path.dirname(__file__), filename)).read()
|
return open(os.path.join(os.path.dirname(__file__), filename)).read()
|
||||||
|
|
@ -22,13 +22,14 @@ setup(name = 'pixelterm',
|
||||||
author = 'jaseg',
|
author = 'jaseg',
|
||||||
author_email = 'pixelterm@jaseg.net',
|
author_email = 'pixelterm@jaseg.net',
|
||||||
url = 'https://github.com/jaseg/pixelterm',
|
url = 'https://github.com/jaseg/pixelterm',
|
||||||
py_modules = ['pixelterm', 'unpixelterm'],
|
py_modules = ['pixelterm', 'unpixelterm', 'xtermcolors'],
|
||||||
scripts = ['pixelterm',
|
install_requires=['pillow'],
|
||||||
'unpixelterm',
|
scripts = ['pixelterm.py',
|
||||||
'colorcube',
|
'unpixelterm.py',
|
||||||
'gifterm',
|
'colorcube.py',
|
||||||
'resolvecolor',
|
'gifterm.py',
|
||||||
'pngmeta'],
|
'resolvecolor.py',
|
||||||
|
'pngmeta.py'],
|
||||||
zip_safe = True,
|
zip_safe = True,
|
||||||
classifiers = [
|
classifiers = [
|
||||||
'Development Status :: 5 - Production/Stable',
|
'Development Status :: 5 - Production/Stable',
|
||||||
|
|
|
||||||
38
unpixelterm
38
unpixelterm
|
|
@ -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)
|
|
||||||
|
|
@ -2,22 +2,13 @@
|
||||||
|
|
||||||
import os, sys, os.path
|
import os, sys, os.path
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
#NOTE: This script uses pygments for X256->RGB conversion since pygments is
|
import xtermcolors
|
||||||
#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
|
from PIL import Image, PngImagePlugin
|
||||||
try:
|
try:
|
||||||
import re2 as re
|
import re2 as re
|
||||||
except:
|
except:
|
||||||
import re
|
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):
|
def parse_escape_sequence(seq):
|
||||||
codes = list(map(int, seq[2:-1].split(';')))
|
codes = list(map(int, seq[2:-1].split(';')))
|
||||||
fg, bg = None, None
|
fg, bg = None, None
|
||||||
|
|
@ -25,7 +16,7 @@ def parse_escape_sequence(seq):
|
||||||
while i<len(codes):
|
while i<len(codes):
|
||||||
if codes[i] in [38, 48]:
|
if codes[i] in [38, 48]:
|
||||||
if codes[i+1] == 5:
|
if codes[i+1] == 5:
|
||||||
c = formatter.xterm_colors[codes[i+2]]
|
c = xtermcolors.xterm_colors[codes[i+2]]
|
||||||
fg, bg = (c, bg) if codes[i] == 38 else (fg, c)
|
fg, bg = (c, bg) if codes[i] == 38 else (fg, c)
|
||||||
i += 2
|
i += 2
|
||||||
elif codes[i] == 39:
|
elif codes[i] == 39:
|
||||||
|
|
@ -99,3 +90,29 @@ def unpixelterm(text):
|
||||||
x, y = 0, y+2
|
x, y = 0, y+2
|
||||||
return img, metadata
|
return img, metadata
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import argparse, json
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
|
||||||
21
xtermcolors.py
Normal file
21
xtermcolors.py
Normal file
|
|
@ -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]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue