-
Notifications
You must be signed in to change notification settings - Fork 0
/
lolcat.py
95 lines (77 loc) · 2.81 KB
/
lolcat.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#
# "THE BEER-WARE LICENSE" (Revision 43~maze)
#
# <[email protected]> wrote these files. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return.
import atexit
import math
import os
import random
import re
import sys
import time
PY3 = sys.version_info >= (3,)
STRIP_ANSI = re.compile(r'\x1b\[(\d+)(;\d+)?(;\d+)?[m|K]')
COLOR_ANSI = (
(0x00, 0x00, 0x00), (0xcd, 0x00, 0x00),
(0x00, 0xcd, 0x00), (0xcd, 0xcd, 0x00),
(0x00, 0x00, 0xee), (0xcd, 0x00, 0xcd),
(0x00, 0xcd, 0xcd), (0xe5, 0xe5, 0xe5),
(0x7f, 0x7f, 0x7f), (0xff, 0x00, 0x00),
(0x00, 0xff, 0x00), (0xff, 0xff, 0x00),
(0x5c, 0x5c, 0xff), (0xff, 0x00, 0xff),
(0x00, 0xff, 0xff), (0xff, 0xff, 0xff),
)
class LolCat(object):
def __init__(self, spread=3.0, freq=0.1, seed=0, mode=256, charset_py2='utf8'):
self.spread = spread
self.freq = freq
self.seed = 0
self.os = random.randint(0, 256) if self.seed == 0 else self.seed
self.mode = mode
self.charset_py2 = charset_py2
def _distance(self, rgb1, rgb2):
return sum(map(lambda c: (c[0] - c[1]) ** 2,
zip(rgb1, rgb2)))
def ansi(self, rgb):
r, g, b = rgb
if self.mode in (8, 16):
colors = COLOR_ANSI[:self.mode]
matches = [(self._distance(c, map(int, rgb)), i) for i, c in enumerate(colors)]
matches.sort()
color = matches[0][1]
return '3%d' % (color,)
else:
gray_possible = True
sep = 2.5
while gray_possible:
if r < sep or g < sep or b < sep:
gray = r < sep and g < sep and b < sep
gray_possible = False
sep += 42.5
if gray:
color = 232 + int(float(sum(rgb) / 33.0))
else:
color = sum([16]+[int(6 * float(val)/256) * mod
for val, mod in zip(rgb, [36, 6, 1])])
return '38;5;%d' % (color,)
def wrap(self, *codes):
return '\x1b[%sm' % (''.join(codes),)
def rainbow(self, freq, i):
r = math.sin(freq * i) * 127 + 128
g = math.sin(freq * i + 2 * math.pi / 3) * 127 + 128
b = math.sin(freq * i + 4 * math.pi / 3) * 127 + 128
return [r, g, b]
def transform(self, text):
output = ''
for s in text:
self.os += 1
for i, c in enumerate(s if PY3 else s.decode(self.charset_py2)):
rgb = self.rainbow(self.freq, self.os + i / self.spread)
output += ''.join([
self.wrap(self.ansi(rgb)),
c if PY3 else c.encode(self.charset_py2),
])
output += '\x1b[0m'
return output