From: vunhat_minh Date: Fri, 6 Jun 2014 11:14:11 +0000 (+0900) Subject: pure python and c implement X-Git-Url: https://vcs.fsf.org/?p=rainbowstream.git;a=commitdiff_plain;h=60431c3bca32cf69f00f680dd5d4475d0a365ddc;ds=sidebyside pure python and c implement --- diff --git a/1.png b/1.png deleted file mode 100644 index 3e82812..0000000 Binary files a/1.png and /dev/null differ diff --git a/rainbowstream/c_image.py b/rainbowstream/c_image.py new file mode 100644 index 0000000..be3d52b --- /dev/null +++ b/rainbowstream/c_image.py @@ -0,0 +1,43 @@ +from PIL import Image,ImageFilter +from functools import partial +from os.path import join, dirname, getmtime, exists, expanduser + +import ctypes, sys, os + +def call_c(): + library = expanduser('~/.image.so') + sauce = join(dirname(__file__), 'image.c') + if not exists(library) or getmtime(sauce) > getmtime(library): + build = "gcc -fPIC -shared -o %s %s" % (library, sauce) + assert os.system(build + " >/dev/null 2>&1") == 0 + image_c= ctypes.cdll.LoadLibrary(library) + image_c.init() + return image_c.rgb_to_ansi + +rgb2short = call_c() + +def pixel_print(ansicolor): + sys.stdout.write('\033[48;5;%sm \033[0m' % (ansicolor)) + +def image_to_display(path): + i = Image.open(path) + i = i.convert('RGBA') + w,h = i.size + i.load() + rows, columns = os.popen('stty size', 'r').read().split() + width = min(w, int(columns)-2*6) + height = int(float(h) * (float(width) / float(w))) + height //= 2 + i = i.resize((width, height), Image.BICUBIC) + height = min(height,30) + + for y in xrange(height): + print ' '*6 , + for x in xrange(width): + p = i.getpixel((x,y)) + r, g, b = p[:3] + pixel_print(rgb2short(r,g,b)) + print '' + +if __name__ == '__main__': + image_to_display(sys.argv[1]) diff --git a/rainbowstream/image.c b/rainbowstream/image.c new file mode 100644 index 0000000..5de90b0 --- /dev/null +++ b/rainbowstream/image.c @@ -0,0 +1,57 @@ +typedef struct { + int r; + int g; + int b; +} rgb_t; +int CUBE_STEPS[] = { 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF }; +rgb_t BASIC16[] = + { { 0, 0, 0 }, { 205, 0, 0}, { 0, 205, 0 }, + { 205, 205, 0 }, { 0, 0, 238}, { 205, 0, 205 }, + { 0, 205, 205 }, { 229, 229, 229}, { 127, 127, 127 }, + { 255, 0, 0 }, { 0, 255, 0}, { 255, 255, 0 }, + { 92, 92, 255 }, { 255, 0, 255}, { 0, 255, 255 }, + { 255, 255, 255 } }; +rgb_t COLOR_TABLE[256]; + + +rgb_t xterm_to_rgb(int xcolor) +{ + rgb_t res; + if (xcolor < 16) { + res = BASIC16[xcolor]; + } else if (16 <= xcolor && xcolor <= 231) { + xcolor -= 16; + res.r = CUBE_STEPS[(xcolor / 36) % 6]; + res.g = CUBE_STEPS[(xcolor / 6) % 6]; + res.b = CUBE_STEPS[xcolor % 6]; + } else if (232 <= xcolor && xcolor <= 255) { + res.r = res.g = res.b = 8 + (xcolor - 232) * 0x0A; + } + return res; +} + +int init() +{ + int c; + for (c = 0; c < 256; c++) { + COLOR_TABLE[c] = xterm_to_rgb(c); + } + return 0; +} + +int rgb_to_ansi(int r, int g, int b) +{ + int best_match = 0; + int smallest_distance = 1000000000; + int c, d; + for (c = 16; c < 256; c++) { + d = (COLOR_TABLE[c].r - r)*(COLOR_TABLE[c].r - r) + + (COLOR_TABLE[c].g - g)*(COLOR_TABLE[c].g - g) + + (COLOR_TABLE[c].b - b)*(COLOR_TABLE[c].b - b); + if (d < smallest_distance) { + smallest_distance = d; + best_match = c; + } + } + return best_match; +} diff --git a/rainbowstream/image.py b/rainbowstream/pure_image.py similarity index 74% rename from rainbowstream/image.py rename to rainbowstream/pure_image.py index fa76f20..0a75d77 100644 --- a/rainbowstream/image.py +++ b/rainbowstream/pure_image.py @@ -1,29 +1,7 @@ from PIL import Image,ImageFilter -import sys,os from functools import partial -""" Convert values between RGB hex codes and xterm-256 color codes. - -Nice long listing of all 256 colors and their codes. Useful for -developing console color themes, or even script output schemes. - -Resources: -* http://en.wikipedia.org/wiki/8-bit_color -* http://en.wikipedia.org/wiki/ANSI_escape_code -* /usr/share/X11/rgb.txt - -I'm not sure where this script was inspired from. I think I must have -written it from scratch, though it's been several years now. -""" - -__author__ = 'Micah Elliott http://MicahElliott.com' -__version__ = '0.1' -__copyright__ = 'Copyright (C) 2011 Micah Elliott. All rights reserved.' -__license__ = 'WTFPL http://sam.zoy.org/wtfpl/' - -#--------------------------------------------------------------------- - -import sys, re +import sys,os CLUT = [ # color look-up table # 8-bit, RGB hex @@ -276,33 +254,23 @@ CLUT = [ # color look-up table ('238', '444444'), ('239', '4e4e4e'), ('240', '585858'), - ('241', '626262'), ('242', '6c6c6c'), ('243', '767676'), ('244', '808080'), - ('245', '8a8a8a'), ('246', '949494'), ('247', '9e9e9e'), ('248', 'a8a8a8'), - ('249', 'b2b2b2'), ('250', 'bcbcbc'), ('251', 'c6c6c6'), ('252', 'd0d0d0'), ('253', 'dadada'), - ('254', 'e4e4e4'), ('255', 'eeeeee'), ] -def _strip_hash(rgb): - # Strip leading `#` if exists. - if rgb.startswith('#'): - rgb = rgb.lstrip('#') - return rgb - def _create_dicts(): short2rgb_dict = dict(CLUT) rgb2short_dict = {} @@ -310,72 +278,32 @@ def _create_dicts(): rgb2short_dict[v] = k return rgb2short_dict, short2rgb_dict +RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts() + + def short2rgb(short): return SHORT2RGB_DICT[short] + def pixel_print(ansicolor): sys.stdout.write('\033[48;5;%sm \033[0m' % (ansicolor)) + def hex_to_rgb(value): value = value.lstrip('#') lv = len(value) return tuple(int(value[i:i+lv/3], 16) for i in range(0, lv, lv/3)) + def rgb_to_hex(rgb): - return '#%02x%02x%02x' % rgb + return '%02x%02x%02x' % rgb -def binary_search(ary,(r,g,b)): - ary.sort() - if len(ary) == 1 : return ary[0] - mid = len(ary)//2 - left = binary_search(ary[:mid],(r,g,b)) - right = binary_search(ary[mid:],(r,g,b)) - ld = (left[0]-r)**2 + (left[1]-g)**2 + (left[2]-b)**2 - rd = (right[0]-r)**2 + (right[1]-g)**2 + (right[2]-b)**2 - if ld < rd : - return left - else: - return right - -def rgb2short(rgb): - """ Find the closest xterm-256 approximation to the given RGB value. - @param rgb: Hex code representing an RGB value, eg, 'abcdef' - @returns: String between 0 and 255, compatible with xterm. - """ - rgb = _strip_hash(rgb) - r = int(rgb[:2],16) - g = int(rgb[2:4],16) - b = int(rgb[4:],16) +def rgb2short(r, g, b): dist = lambda s,d: (s[0]-d[0])**2+(s[1]-d[1])**2+(s[2]-d[2])**2 ary = [hex_to_rgb(hex) for hex in RGB2SHORT_DICT] - m = binary_search(ary,(r,g,b)) m = min(ary, key=partial(dist, (r,g,b))) - return RGB2SHORT_DICT[_strip_hash(rgb_to_hex(m))] - - -# incs = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) -# parts = [ int(h, 16) for h in re.split(r'(..)(..)(..)', rgb)[1:4] ] -# res = [] -# for part in parts: -# i = 0 -# while i < len(incs)-1: -# s, b = incs[i], incs[i+1] # smaller, bigger -# if s <= part <= b: -# s1 = abs(s - part) -# b1 = abs(b - part) -# if s1 < b1: closest = s -# else: closest = b -# res.append(closest) -# break -# i += 1 -# #print '***', res -# res = ''.join([ ('%02.x' % i) for i in res ]) -# equiv = RGB2SHORT_DICT[ res ] -# #print '***', res, equiv -# return equiv -# -RGB2SHORT_DICT, SHORT2RGB_DICT = _create_dicts() + return RGB2SHORT_DICT[rgb_to_hex(m)] def image_to_display(path): i = Image.open(path) @@ -387,19 +315,16 @@ def image_to_display(path): height = int(float(h) * (float(width) / float(w))) height //= 2 i = i.resize((width, height), Image.BICUBIC) + height = min(height,30) for y in xrange(height): print ' '*6 , for x in xrange(width): p = i.getpixel((x,y)) r, g, b = p[:3] - hex = rgb_to_hex((r,g,b)) - pixel_print(rgb2short(hex)) + pixel_print(rgb2short(r,g,b)) print '' -#--------------------------------------------------------------------- - if __name__ == '__main__': - path = sys.argv[1] - image_to_display(path) + image_to_display(sys.argv[1])