Merge remote-tracking branch 'zyx-i/improved-generate_gradients' into develop

This commit is contained in:
Kim Silkebækken 2013-04-20 16:58:07 +02:00
commit 51d64b76e9
1 changed files with 98 additions and 56 deletions

View File

@ -1,8 +1,13 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
'''Gradients generator
'''
from __future__ import division
import sys
import json
from powerline.colorscheme import cterm_to_hex
from itertools import groupby
import argparse
try:
from __builtin__ import unicode
@ -10,27 +15,38 @@ except ImportError:
unicode = str # NOQA
if len(sys.argv) == 1 or sys.argv[1] == '--help':
sys.stderr.write('''
Usage: generate_gradients.py colors itemnum[ "show" [ min max num]]
def num2(s):
try:
return (True, [int(v) for v in s.partition(' ')[::2]])
except TypeError:
return (False, [float(v) for v in s.partition(' ')[::2]])
colors: JSON list with either cterm ([200, 42, 6]) or RGB (["abcdef",
"feffef"]) colors.
itemnum: number of items in generated gradient.
def rgbint_to_rgb(rgbint):
return ((rgbint >> 16) & 0xFF, (rgbint >> 8) & 0xFF, rgbint & 0xFF)
"show": static string, determines whether gradient sample should be
printed to stdout as well.
min, max: floating point values.
num: integer
def color(s):
if len(s) <= 3:
return rgbint_to_rgb(cterm_to_hex[int(s)])
else:
return rgbint_to_rgb(int(s, 16))
all of the above are used to generate sample gradient for given
range (just like the above gradients shown with "show", but with
different scale (controlled by min and max) and, possibly,
different length (controlled by num)).
''')
sys.exit(1)
def nums(s):
return [int(i) for i in s.split()]
p = argparse.ArgumentParser(description=__doc__)
p.add_argument('gradient', nargs='*', metavar='COLOR', type=color, help='List of colors (either indexes from 8-bit palette or 24-bit RGB in hexadecimal notation)')
p.add_argument('-n', '--num_items', metavar='INT', type=int, help='Number of items in resulting list', default=101)
p.add_argument('-N', '--num_output', metavar='INT', type=int, help='Number of characters in sample', default=101)
p.add_argument('-r', '--range', metavar='V1 V2', type=num2, help='Use this range when outputting scale')
p.add_argument('-s', '--show', action='store_true', help='If present output gradient sample')
p.add_argument('-p', '--palette', choices=('16', '256'), help='Use this palette. Defaults to 240-color palette (256 colors without first 16)')
p.add_argument('-w', '--weights', metavar='INT INT ...', type=nums, help='Adjust weights of colors. Number of weights must be equal to number of colors')
args = p.parse_args()
def linear_gradient(start_value, stop_value, start_offset, stop_offset, offset):
@ -47,13 +63,6 @@ def gradient(DATA):
return gradient_function
def get_color(rgb):
if type(rgb) is unicode:
return int(rgb[:2], 16), int(rgb[2:4], 16), int(rgb[4:6], 16)
else:
return rgbint_to_rgb(cterm_to_hex[rgb])
def get_rgb(*args):
return "%02x%02x%02x" % args
@ -62,11 +71,7 @@ def col_distance(rgb1, rgb2):
return sum(((rgb1[i] - rgb2[i]) ** 2 for i in range(3)))
def rgbint_to_rgb(rgbint):
return ((rgbint >> 16) & 0xFF, (rgbint >> 8) & 0xFF, rgbint & 0xFF)
def find_color(urgb, colors):
def find_color(urgb, colors, ctrans):
cur_distance = 3 * (255 ** 2 + 1)
cur_color = None
i = 0
@ -75,7 +80,7 @@ def find_color(urgb, colors):
dist = col_distance(urgb, crgb)
if dist < cur_distance:
cur_distance = dist
cur_color = (i, crgb)
cur_color = (ctrans(i), crgb)
i += 1
return cur_color
@ -88,44 +93,81 @@ def print_color(color):
sys.stdout.write('\033[48;' + colstr + 'm ')
def print_colors(colors, num=100):
for i in range(num + 1):
def print_colors(colors, num):
for i in range(num):
color = colors[int(round(i * (len(colors) - 1) / num))]
print_color(color)
sys.stdout.write('\033[0m\n')
c = [get_color(color) for color in json.loads(sys.argv[1])]
m = int(sys.argv[2]) if len(sys.argv) > 2 else 100
m += m % (len(c) - 1)
step = m / (len(c) - 1)
data = [(i * step, c[i - 1], c[i]) for i in range(1, len(c))]
def dec_scale_generator(num):
j = 0
r = ''
while num:
r += '\033[{0}m'.format(j % 2)
for i in range(10):
r += str(i)
num -= 1
if not num:
break
j += 1
r += '\033[0m\n'
return r
m = args.num_items
maxweight = len(args.gradient) - 1
if args.weights:
weight_sum = sum(args.weights)
norm_weights = [100.0 * weight / weight_sum for weight in args.weights]
steps = [0]
for weight in norm_weights:
steps.append(steps[-1] + weight)
steps.pop(0)
steps.pop(0)
else:
step = m / maxweight
steps = [i * step for i in range(1, maxweight + 1)]
data = [(weight, args.gradient[i - 1], args.gradient[i]) for weight, i in zip(steps, range(1, len(args.gradient)))]
gr_func = gradient(data)
gradient = [gr_func(y) for y in range(0, m - 1)]
gradient = [gr_func(y) for y in range(0, m)]
palettes = {
'16': (cterm_to_hex[:16], lambda c: c),
'256': (cterm_to_hex, lambda c: c),
None: (cterm_to_hex[16:], lambda c: c + 16),
}
r = [get_rgb(*color) for color in gradient]
r2 = [find_color(color, cterm_to_hex)[0] for color in gradient]
r2 = [find_color(color, *palettes[args.palette])[0] for color in gradient]
r3 = [i[0] for i in groupby(r2)]
print(json.dumps(r))
print(json.dumps(r2))
print(json.dumps(r3))
if len(sys.argv) > 3 and sys.argv[3] == 'show':
print_colors(gradient)
print_colors(r2)
print_colors(r3)
sys.stdout.write('0')
sys.stdout.write(''.join(('%10u' % (i * 10) for i in range(1, 11))))
sys.stdout.write('\n')
nums = (''.join((str(i) for i in range(10))))
sys.stdout.write(''.join(((('\033[1m' if j % 2 else '\033[0m') + nums) for j in range(10))))
sys.stdout.write('\033[0m0\n')
if len(sys.argv) > 6:
vmin = float(sys.argv[4])
vmax = float(sys.argv[5])
num = int(sys.argv[6])
print_colors(gradient, num)
if args.show:
print_colors(args.gradient, args.num_output)
print_colors(gradient, args.num_output)
print_colors(r2, args.num_output)
print_colors(r3, args.num_output)
if not args.range and args.num_output >= 32 and (args.num_output - 1) // 10 >= 4 and (args.num_output - 1) % 10 == 0:
sys.stdout.write('0')
sys.stdout.write(''.join(('%*u' % (args.num_output // 10, i) for i in range(10, 101, 10))))
sys.stdout.write('\n')
else:
if args.range:
vmin, vmax = args.range[1]
isint = args.range[0]
else:
isint = True
vmin = 0
vmax = 100
s = ''
while len(s) < num:
lasts = ' ' + str(vmax)
while len(s) + len(lasts) < args.num_output:
curpc = len(s) + 1 if s else 0
curval = vmin + curpc * (vmax - vmin) / 100.0
curval = vmin + curpc * (vmax - vmin) / args.num_output
if isint:
curval = int(round(curval))
s += str(curval) + ' '
print(s)
sys.stdout.write(s[:-1] + lasts + '\n')
sys.stdout.write(dec_scale_generator(args.num_output) + '\n')