Created
April 6, 2017 00:08
-
-
Save gbromios/df3fe9b15e8dcde987ea1033d40f4181 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/python3 | |
''' | |
usage: $ ./rainbower.py [-t [FRAMES FPS]] [-v] [-f FORMAT] [-o OUTFILE] your text here | |
outputs html by default. | |
''' | |
import math | |
debug = False | |
__all__ = ['Colorizer'] | |
class Colorizer: | |
def __init__(self, char_format, color_format, post_format = '{0}'): | |
self.char_format = char_format | |
self.color_format = color_format | |
self.post_format = post_format | |
def __call__(self, text): | |
# strip spaces TODO all whitespace/nonprint | |
n = len(text.replace(" ", "")) | |
out = "" | |
x = 0 | |
for r, g, b in smooth_rgb(n): | |
color = "#{:02X}{:02X}{:02X}".format(r, g, b) | |
# skip whitespace TODO all ws/non printing | |
while text[x] == " ": | |
out += text[x] | |
x+= 1 | |
out += self.char_format.format(COLOR=color, CHAR=text[x]) | |
x += 1 | |
return self.post_format.format(out) | |
def smooth_rgb(n): | |
assert(n > 1) | |
# sample cos from 0 to 2π inclusive, at n equally-spaced inputs, ensuring that | |
# the first and last values have equal inputs | |
dx = 2 * math.pi / (n - 1) | |
if debug: print("{} samples [0..2π], {} apart", n, dx) | |
for i in (float(i) for i in range(n)): | |
if debug: print(" {}: fancy_cos({:.4f}) = {:.4f}".format( | |
int(i), | |
(i * dx) / (2 * math.pi), | |
(math.cos(dx * i) + 1) / 2) | |
) | |
# sample cos(dx * i) three times, offset by 0, 1/3 and 2/3 of the period | |
r, g, b = ( | |
(math.cos(dx * i) + 1) / 2, | |
(math.cos((dx * i) + 2 * math.pi / 3) + 1) / 2, | |
(math.cos((dx * i) + 4 * math.pi / 3) + 1) / 2, | |
) | |
# scale rgb values linearly such that at least one is at full blast | |
scale = 255 / max(r, g, b) | |
# clamp each value between 0..255 and cast to int | |
yield ( | |
int(max(0, min(255, r * scale))), | |
int(max(0, min(255, g * scale))), | |
int(max(0, min(255, b * scale))), | |
) | |
def pygame_test(n, fps): | |
print("running test: {} frames at {} fps ({}s)".format(n, fps, n/fps)) | |
import pygame | |
screen = pygame.display.set_mode((500, 500)) | |
clock = pygame.time.Clock() | |
pygame.display.flip() | |
pls = None | |
for color in smooth_rgb(n): | |
screen.fill(color) | |
if debug: print ('\t', color) | |
if debug: print () | |
pygame.display.flip() | |
if any(pygame.event.get(pygame.QUIT)): | |
raise SystemExit | |
clock.tick(fps) | |
# pause for a second at the end. | |
pygame.time.wait(1000) | |
def print_usage_and_exit(): | |
print (__doc__) | |
raise SystemExit | |
def main(args): | |
global debug | |
run_test = False | |
frames, fps = 60, 1000 | |
text = '' | |
format = None | |
outfile = None | |
while args: | |
arg = args[0] | |
if arg == '-v': | |
debug = True | |
args = args[1:] | |
elif arg == '-t': | |
run_test = True | |
try: | |
frames, fps = int(args[1]), float(args[2]) | |
args = args[3:] | |
except IndexError: | |
args = args[1:] | |
elif arg == '-f': | |
try: | |
format = args[1] | |
args = args[2:] | |
except IndexError: | |
print_usage_and_exit() | |
elif arg == '-o': | |
try: | |
outfile = args[1] | |
args = args[2:] | |
except IndexError: | |
print_usage_and_exit() | |
else: | |
# out of options, combine the rest of the args | |
text = ' '.join(args) | |
break | |
if run_test: | |
pygame_test(frames, fps) | |
elif text: | |
#print(Colorizer(format='{{color:{COLOR}}}{CHAR}{{color}}', color_format="#{:02X}{:02X}{:02X}")(text)) # < jira | |
colorizer = Colorizer( | |
char_format = '<span style="color: {COLOR}">{CHAR}</span>', | |
color_format = '#{:02X}{:02X}{:02X}', | |
post_format = '<html><body style="background-color: #666; font-family: sans-serif; font-weight: bold;">{0}</body></html>' | |
) | |
output = colorizer(text) | |
if outfile: | |
with open(outfile, 'w') as of: | |
of.write(output) | |
else: | |
print(output) | |
else: | |
print_usage_and_exit() | |
if __name__ == '__main__': | |
import sys | |
main(sys.argv[1:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment