chromatic-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chromatic/__init__.py +26 -0
- chromatic/_typing.py +168 -0
- chromatic/ascii/__init__.py +5 -0
- chromatic/ascii/_array.py +1059 -0
- chromatic/ascii/_curses.py +153 -0
- chromatic/ascii/_glyph_proc.py +107 -0
- chromatic/color/__init__.py +6 -0
- chromatic/color/colorconv.py +316 -0
- chromatic/color/core.py +1677 -0
- chromatic/color/core.pyi +421 -0
- chromatic/color/palette.py +693 -0
- chromatic/color/palette.pyi +330 -0
- chromatic/data/__init__.py +189 -0
- chromatic/data/__init__.pyi +15 -0
- chromatic/data/fonts/IBM_VGA_437_8x16.ttf +0 -0
- chromatic/data/fonts/consolas.ttf +0 -0
- chromatic/data/images/butterfly.jpg +0 -0
- chromatic/data/images/escher.png +0 -0
- chromatic/data/images/goblin_virus.png +0 -0
- chromatic/data/images/hotdog.jpg +0 -0
- chromatic/demo.py +417 -0
- chromatic_python-0.1.0.dist-info/LICENSE +21 -0
- chromatic_python-0.1.0.dist-info/METADATA +39 -0
- chromatic_python-0.1.0.dist-info/RECORD +26 -0
- chromatic_python-0.1.0.dist-info/WHEEL +5 -0
- chromatic_python-0.1.0.dist-info/top_level.txt +1 -0
chromatic/demo.py
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import math
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
from os import PathLike
|
|
7
|
+
from pathlib import PurePath
|
|
8
|
+
from types import FunctionType
|
|
9
|
+
from typing import Callable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def escher_dragon_ascii():
|
|
13
|
+
"""Displays the image-to-ASCII transform of 'Dragon' by M.C. Escher."""
|
|
14
|
+
from chromatic.ascii import ascii2img, img2ascii
|
|
15
|
+
from chromatic.data import UserFont, escher
|
|
16
|
+
|
|
17
|
+
input_img = escher()
|
|
18
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
19
|
+
char_set = r" ._-~+<vX♦'^Vx>|πΦ0Ω#$║╫"
|
|
20
|
+
|
|
21
|
+
ascii_str = img2ascii(
|
|
22
|
+
input_img,
|
|
23
|
+
font,
|
|
24
|
+
factor=240,
|
|
25
|
+
char_set=char_set,
|
|
26
|
+
sort_glyphs=True)
|
|
27
|
+
|
|
28
|
+
ascii_img = ascii2img(
|
|
29
|
+
ascii_str,
|
|
30
|
+
font,
|
|
31
|
+
font_size=16,
|
|
32
|
+
fg='white',
|
|
33
|
+
bg='black')
|
|
34
|
+
|
|
35
|
+
ascii_img.show()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def escher_dragon_256color():
|
|
39
|
+
"""Displays the image-to-ANSI transform of 'Dragon' by M.C. Escher in 8-bit color."""
|
|
40
|
+
from chromatic.ascii import ansi2img, img2ansi
|
|
41
|
+
from chromatic.data import UserFont, escher
|
|
42
|
+
|
|
43
|
+
input_img = escher()
|
|
44
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
45
|
+
|
|
46
|
+
ansi_array = img2ansi(
|
|
47
|
+
input_img,
|
|
48
|
+
font,
|
|
49
|
+
factor=240,
|
|
50
|
+
ansi_type='8b',
|
|
51
|
+
equalize=True)
|
|
52
|
+
|
|
53
|
+
ansi_img = ansi2img(
|
|
54
|
+
ansi_array,
|
|
55
|
+
font,
|
|
56
|
+
font_size=16)
|
|
57
|
+
|
|
58
|
+
ansi_img.show()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def butterfly_16color():
|
|
62
|
+
"""Displays image-to-ANSI transform of 'Spider Lily & Papilio xuthus' in 4-bit color.
|
|
63
|
+
|
|
64
|
+
Good ol' C-x M-c M-butterfly...
|
|
65
|
+
"""
|
|
66
|
+
from chromatic.color import ansicolor4Bit
|
|
67
|
+
from chromatic.ascii import ansi2img, img2ansi
|
|
68
|
+
from chromatic.data import UserFont, butterfly
|
|
69
|
+
|
|
70
|
+
input_img = butterfly()
|
|
71
|
+
|
|
72
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
73
|
+
|
|
74
|
+
char_set = r"'·,•-_→+<>ⁿ*%⌂7√Iï∞πbz£9yîU{}1αHSw♥æ?GX╕╒éà⌡MF╝╩ΘûǃQ½☻Ŷ┤▄╪║▒█"
|
|
75
|
+
|
|
76
|
+
ansi_array = img2ansi(
|
|
77
|
+
input_img,
|
|
78
|
+
font,
|
|
79
|
+
factor=200,
|
|
80
|
+
char_set=char_set,
|
|
81
|
+
ansi_type=ansicolor4Bit)
|
|
82
|
+
|
|
83
|
+
ansi_img = ansi2img(
|
|
84
|
+
ansi_array,
|
|
85
|
+
font,
|
|
86
|
+
font_size=16)
|
|
87
|
+
|
|
88
|
+
ansi_img.show()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def butterfly_truecolor():
|
|
92
|
+
"""Displays the image-to-ANSI transform of 'Spider Lily & Papilio xuthus' in 24-bit color."""
|
|
93
|
+
from chromatic.ascii import ansi2img, img2ansi
|
|
94
|
+
from chromatic.data import UserFont, butterfly
|
|
95
|
+
|
|
96
|
+
input_img = butterfly()
|
|
97
|
+
|
|
98
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
99
|
+
|
|
100
|
+
ansi_array = img2ansi(
|
|
101
|
+
input_img,
|
|
102
|
+
font,
|
|
103
|
+
factor=200,
|
|
104
|
+
ansi_type='24b',
|
|
105
|
+
equalize='white_point')
|
|
106
|
+
|
|
107
|
+
ansi_img = ansi2img(
|
|
108
|
+
ansi_array,
|
|
109
|
+
font,
|
|
110
|
+
font_size=16)
|
|
111
|
+
|
|
112
|
+
ansi_img.show()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def butterfly_randcolor():
|
|
116
|
+
from chromatic.ascii import ansi2img, img2ansi
|
|
117
|
+
from chromatic.color import randcolor, rgb2hsv, hsv2rgb, Color
|
|
118
|
+
from chromatic.data import UserFont, butterfly
|
|
119
|
+
|
|
120
|
+
input_img = butterfly()
|
|
121
|
+
|
|
122
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
123
|
+
|
|
124
|
+
ansi_array = img2ansi(
|
|
125
|
+
input_img,
|
|
126
|
+
font,
|
|
127
|
+
factor=200,
|
|
128
|
+
ansi_type='8b',
|
|
129
|
+
equalize='white_point')
|
|
130
|
+
|
|
131
|
+
for row in range(len(ansi_array)):
|
|
132
|
+
for idx, cs in enumerate(ansi_array[row]):
|
|
133
|
+
if (fg := cs.fg) is not None:
|
|
134
|
+
_, _, v = rgb2hsv(fg.rgb)
|
|
135
|
+
h, s, _ = rgb2hsv(randcolor().rgb)
|
|
136
|
+
ansi_array[row][idx] = cs.recolor(fg=Color.from_rgb(hsv2rgb((h, s, v))))
|
|
137
|
+
|
|
138
|
+
ansi_img = ansi2img(
|
|
139
|
+
ansi_array,
|
|
140
|
+
font,
|
|
141
|
+
font_size=16)
|
|
142
|
+
|
|
143
|
+
ansi_img.show()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def goblin_virus_truecolor():
|
|
147
|
+
"""`G-O-B-L-I-N VIRUS <https://imgur.com/n0Mng2P>`__"""
|
|
148
|
+
from chromatic.ascii import ansi2img, img2ansi
|
|
149
|
+
from chromatic.data import UserFont, goblin_virus
|
|
150
|
+
|
|
151
|
+
input_img = goblin_virus()
|
|
152
|
+
|
|
153
|
+
font = UserFont.IBM_VGA_437_8X16
|
|
154
|
+
|
|
155
|
+
char_set = r' .-|_⌐¬^:()═+<>v≥≤«*»x└┘π╛╘┴┐┌┬╧╚╙X╒╜╨#0╓╝╩╤╥│╔┤├╞╗╦┼╪║╟╠╫╣╬░▒▓█▄▌▐▀'
|
|
156
|
+
|
|
157
|
+
ansi_array = img2ansi(
|
|
158
|
+
input_img,
|
|
159
|
+
font,
|
|
160
|
+
factor=200,
|
|
161
|
+
char_set=char_set,
|
|
162
|
+
ansi_type='24b',
|
|
163
|
+
equalize=False)
|
|
164
|
+
|
|
165
|
+
ansi_img = ansi2img(
|
|
166
|
+
ansi_array,
|
|
167
|
+
font,
|
|
168
|
+
font_size=16)
|
|
169
|
+
|
|
170
|
+
ansi_img.show()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def named_colors():
|
|
174
|
+
from chromatic.color.palette import display_named_colors, ColorNamespace
|
|
175
|
+
from chromatic.color.colorconv import rgb2hsv, rgb2lab
|
|
176
|
+
|
|
177
|
+
print(f"{'.'.join([ColorNamespace.__module__, ColorNamespace.__name__])}:")
|
|
178
|
+
named = display_named_colors()
|
|
179
|
+
whites = [0]
|
|
180
|
+
for idx, n in enumerate(named):
|
|
181
|
+
hsv = rgb2hsv(n.fg.rgb)
|
|
182
|
+
if all(
|
|
183
|
+
map(
|
|
184
|
+
lambda i, x: math.isclose(hsv[i], x, abs_tol=.16),
|
|
185
|
+
(-1, 1), (1, 0))):
|
|
186
|
+
if idx - whites[-1] < 4:
|
|
187
|
+
whites.pop()
|
|
188
|
+
whites.append(idx)
|
|
189
|
+
whites.append(-1)
|
|
190
|
+
buffer = []
|
|
191
|
+
for start, stop in zip(whites, whites[1:]):
|
|
192
|
+
xs = sorted(
|
|
193
|
+
named[start + 1 if start else None:stop + 1 if ~stop else None],
|
|
194
|
+
key=lambda x: rgb2lab(x.fg.rgb))
|
|
195
|
+
buffer.append(xs)
|
|
196
|
+
for ln in buffer:
|
|
197
|
+
print(' | '.join(ln))
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def color_table():
|
|
201
|
+
"""Print foreground / background combinations in each ANSI format.
|
|
202
|
+
|
|
203
|
+
A handful of stylistic SGR parameters are displayed as well.
|
|
204
|
+
"""
|
|
205
|
+
from chromatic.color import (
|
|
206
|
+
ColorStr,
|
|
207
|
+
SgrParameter,
|
|
208
|
+
ansicolor24Bit,
|
|
209
|
+
ansicolor4Bit,
|
|
210
|
+
ansicolor8Bit
|
|
211
|
+
)
|
|
212
|
+
from chromatic.color.palette import ColorNamespace
|
|
213
|
+
|
|
214
|
+
color_ns = ColorNamespace()
|
|
215
|
+
ansi_types = [ansicolor4Bit, ansicolor8Bit, ansicolor24Bit]
|
|
216
|
+
colors = [
|
|
217
|
+
color_ns.BLACK,
|
|
218
|
+
color_ns.WHITE,
|
|
219
|
+
color_ns.RED,
|
|
220
|
+
color_ns.ORANGE,
|
|
221
|
+
color_ns.YELLOW,
|
|
222
|
+
color_ns.GREEN,
|
|
223
|
+
color_ns.BLUE,
|
|
224
|
+
color_ns.INDIGO,
|
|
225
|
+
color_ns.PURPLE]
|
|
226
|
+
colors_dict = {v.name.title(): v for v in colors}
|
|
227
|
+
spacing = max(map(len, colors_dict)) + 1
|
|
228
|
+
fg_colors = [ColorStr(
|
|
229
|
+
f"{c.name.title(): ^{spacing}}",
|
|
230
|
+
color_spec=dict(fg=c),
|
|
231
|
+
ansi_type=ansicolor24Bit)
|
|
232
|
+
for c in colors]
|
|
233
|
+
bg_colors = [
|
|
234
|
+
ColorStr().recolor(bg=None)
|
|
235
|
+
] + [c.recolor(fg=None, bg=c.fg) for c in fg_colors]
|
|
236
|
+
pad = spacing - 1
|
|
237
|
+
print(
|
|
238
|
+
'|'.join(
|
|
239
|
+
[f"{'4bit': ^{pad}}",
|
|
240
|
+
f"{'8bit': ^{pad}}",
|
|
241
|
+
f"{'24bit': >{pad}}"]))
|
|
242
|
+
for row in fg_colors:
|
|
243
|
+
for col in bg_colors:
|
|
244
|
+
for typ in ansi_types:
|
|
245
|
+
print(row.as_ansi_type(typ).recolor(bg=col.bg), end='\x1b[0m')
|
|
246
|
+
print()
|
|
247
|
+
print('\nstyles:')
|
|
248
|
+
print()
|
|
249
|
+
style_params = [
|
|
250
|
+
SgrParameter.BOLD,
|
|
251
|
+
SgrParameter.ITALICS,
|
|
252
|
+
SgrParameter.CROSSED_OUT,
|
|
253
|
+
SgrParameter.ENCIRCLED,
|
|
254
|
+
SgrParameter.SINGLE_UNDERLINE,
|
|
255
|
+
SgrParameter.DOUBLE_UNDERLINE,
|
|
256
|
+
SgrParameter.NEGATIVE]
|
|
257
|
+
for style in style_params:
|
|
258
|
+
print(
|
|
259
|
+
ColorStr('.'.join([SgrParameter.__qualname__, style.name]))
|
|
260
|
+
.update_sgr(style),
|
|
261
|
+
end='\x1b[0m' + (' ' * 4))
|
|
262
|
+
print()
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def glyph_comparisons(__output_dir: str | PathLike[str] = None):
|
|
266
|
+
from skimage.metrics import mean_squared_error
|
|
267
|
+
from numpy import ndarray
|
|
268
|
+
from chromatic.ascii import cp437_printable
|
|
269
|
+
from chromatic import get_glyph_masks
|
|
270
|
+
from chromatic.data import UserFont
|
|
271
|
+
from random import choices as get_random
|
|
272
|
+
|
|
273
|
+
def _find_best_matches(glyph_masks1: dict[str, ndarray],
|
|
274
|
+
glyph_masks2: dict[str, ndarray]) -> dict[str, str]:
|
|
275
|
+
best_matches = {}
|
|
276
|
+
for char1, mask1 in glyph_masks1.items():
|
|
277
|
+
best_char = None
|
|
278
|
+
best_score = float('inf')
|
|
279
|
+
for char2, mask2 in glyph_masks2.items():
|
|
280
|
+
score = mean_squared_error(mask1, mask2)
|
|
281
|
+
if score < best_score:
|
|
282
|
+
best_score = score
|
|
283
|
+
best_char = char2
|
|
284
|
+
best_matches[char1] = best_char
|
|
285
|
+
return best_matches
|
|
286
|
+
|
|
287
|
+
if __output_dir and not os.path.isdir(__output_dir):
|
|
288
|
+
raise NotADirectoryError(
|
|
289
|
+
__output_dir)
|
|
290
|
+
user_fonts = [pair := (UserFont.IBM_VGA_437_8X16, UserFont.CONSOLAS), pair[::-1]]
|
|
291
|
+
trans_table = str.maketrans({']': None, '0': ' ', '[': ' '})
|
|
292
|
+
char_set = cp437_printable()
|
|
293
|
+
separator = '#' * 100
|
|
294
|
+
for font1, font2 in user_fonts:
|
|
295
|
+
glyph_masks_1 = get_glyph_masks(font1, char_set, dist_transform=True)
|
|
296
|
+
glyph_masks_2 = get_glyph_masks(font2, char_set, dist_transform=True)
|
|
297
|
+
best_matches_ = _find_best_matches(glyph_masks_1, glyph_masks_2)
|
|
298
|
+
txt = ''.join(
|
|
299
|
+
'->'.center(32, ' ').join(['{}'] * 2).format(
|
|
300
|
+
f"{font1.name}"
|
|
301
|
+
f"[{input_char!r}, {input_char.encode('unicode_escape').decode()!r}]",
|
|
302
|
+
f"{font2.name}"
|
|
303
|
+
f"[{matched_char!r}, {matched_char.encode('unicode_escape').decode()!r}]")
|
|
304
|
+
.center(100, ' ')
|
|
305
|
+
+ '\n\n'
|
|
306
|
+
+ '\n'.join(
|
|
307
|
+
''.join
|
|
308
|
+
(z).translate(trans_table)
|
|
309
|
+
for z in zip(
|
|
310
|
+
f'{glyph_masks_1[input_char].astype(int)}\n'.splitlines(),
|
|
311
|
+
f'{glyph_masks_2[matched_char].astype(int)}\n'.splitlines()[1:]))
|
|
312
|
+
+ separator.join(['\n'] * 2) for input_char, matched_char in best_matches_.items())
|
|
313
|
+
if __output_dir is not None:
|
|
314
|
+
fname = (PurePath(__output_dir) /
|
|
315
|
+
f"{'_to_'.join(font.name.lower() for font in (font1, font2))}.txt")
|
|
316
|
+
with open(fname, 'w', encoding='utf-8') as f:
|
|
317
|
+
f.write(txt)
|
|
318
|
+
else:
|
|
319
|
+
for glyph in get_random(txt.split(separator), k=len(char_set) // 2):
|
|
320
|
+
print(separator + glyph)
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class _time_wrapper[** P, R]:
|
|
324
|
+
|
|
325
|
+
def __init__(
|
|
326
|
+
self,
|
|
327
|
+
func: Callable[P, R] | FunctionType | type = None
|
|
328
|
+
):
|
|
329
|
+
self.func = func
|
|
330
|
+
if self.func is not None:
|
|
331
|
+
functools.update_wrapper(self, self.func)
|
|
332
|
+
|
|
333
|
+
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> R:
|
|
334
|
+
if self.func is not None:
|
|
335
|
+
start = time.perf_counter()
|
|
336
|
+
result = self.func(*args, **kwargs)
|
|
337
|
+
stop = time.perf_counter()
|
|
338
|
+
print(f"Total execution time: {self._delta(start, stop)}")
|
|
339
|
+
return result
|
|
340
|
+
else:
|
|
341
|
+
self.func = args[0]
|
|
342
|
+
functools.update_wrapper(self, self.func)
|
|
343
|
+
return self
|
|
344
|
+
|
|
345
|
+
@staticmethod
|
|
346
|
+
def _delta(start: float, stop: float) -> str:
|
|
347
|
+
delta = stop - start
|
|
348
|
+
mag, fmt = min(
|
|
349
|
+
[(1, 's'), (1e-3, 'ms'), (1e-6, 'μs'), (1e-9, 'ns'), (1e-12, 'ps')],
|
|
350
|
+
key=lambda x: abs(math.log10(x[0]) - math.log10(delta)))
|
|
351
|
+
delta *= 1 / mag
|
|
352
|
+
return f"{delta:.3f} {fmt}"
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def main():
|
|
356
|
+
demo_globals = dict(globals())
|
|
357
|
+
demo_globals.pop('main')
|
|
358
|
+
from inspect import getargs
|
|
359
|
+
|
|
360
|
+
global_func_enum = dict(
|
|
361
|
+
enumerate(
|
|
362
|
+
sorted(
|
|
363
|
+
k for k, v in demo_globals.items() if
|
|
364
|
+
isinstance(v, FunctionType) and not v.__name__.startswith('_'))))
|
|
365
|
+
safe_funcs = {-1: exit}
|
|
366
|
+
choices = [f'[{x[0]}]: {x[1].name}' for x in safe_funcs.items()]
|
|
367
|
+
names = []
|
|
368
|
+
for k, v in global_func_enum.items():
|
|
369
|
+
if not any(getargs(demo_globals[v].__code__)):
|
|
370
|
+
if safe_funcs.get(k - 1) is None:
|
|
371
|
+
k_val = list(safe_funcs).pop() + 1
|
|
372
|
+
else:
|
|
373
|
+
k_val = k
|
|
374
|
+
safe_funcs[k_val] = globals()[v]
|
|
375
|
+
choices.append(f"[{k_val}]: {v}")
|
|
376
|
+
names.append(v)
|
|
377
|
+
|
|
378
|
+
def _check_user_input(user_key: str):
|
|
379
|
+
if user_key.strip('-').isdigit():
|
|
380
|
+
if (k := int(user_key)) in safe_funcs:
|
|
381
|
+
return k
|
|
382
|
+
if (s := user_key.strip().replace(' ', '_').casefold()) in names:
|
|
383
|
+
return next(i for i, v in enumerate(names) if v == s)
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
selection = None
|
|
387
|
+
if len(sys.argv) > 1:
|
|
388
|
+
key = sys.argv[1]
|
|
389
|
+
if key.casefold() == '-h'.casefold():
|
|
390
|
+
xs = ['Run one of the following demo functions:',
|
|
391
|
+
*('{}:\n\t{}'.format(
|
|
392
|
+
n, '\n'.join(
|
|
393
|
+
filter(None, (globals()[n].__doc__ or '...').splitlines())).strip())
|
|
394
|
+
for n in names)]
|
|
395
|
+
print(f'\n{'\n\n'.join(xs)}')
|
|
396
|
+
exit()
|
|
397
|
+
selection = _check_user_input(key)
|
|
398
|
+
if selection is None:
|
|
399
|
+
print('\n'.join(choices))
|
|
400
|
+
while selection not in safe_funcs:
|
|
401
|
+
try:
|
|
402
|
+
selection = _check_user_input(input(f"Select a demo function:\t"))
|
|
403
|
+
except ValueError:
|
|
404
|
+
pass
|
|
405
|
+
except KeyboardInterrupt:
|
|
406
|
+
exit()
|
|
407
|
+
try:
|
|
408
|
+
if selection == -1:
|
|
409
|
+
exit()
|
|
410
|
+
print(f"Running {names[selection]!r}...\n")
|
|
411
|
+
except KeyError:
|
|
412
|
+
pass
|
|
413
|
+
_time_wrapper(safe_funcs[selection])()
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
if __name__ == '__main__':
|
|
417
|
+
main()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 crypt0lith
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: chromatic-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ANSI art image processing and colored terminal text
|
|
5
|
+
Author: crypt0lith
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2024 crypt0lith
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
Keywords: ansi,ascii,art,font,image,terminal,parser
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
29
|
+
Requires-Python: >=3.12
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Dist: fonttools~=4.51.0
|
|
33
|
+
Requires-Dist: networkx~=3.4.2
|
|
34
|
+
Requires-Dist: numpy~=2.1.1
|
|
35
|
+
Requires-Dist: opencv-python~=4.10.0.84
|
|
36
|
+
Requires-Dist: pillow~=10.4.0
|
|
37
|
+
Requires-Dist: scikit-image~=0.25.0rc1
|
|
38
|
+
Requires-Dist: scikit-learn~=1.5.2
|
|
39
|
+
Requires-Dist: scipy~=1.14.1
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
chromatic/__init__.py,sha256=0wwCYq16TA-FUJTMt9KxcaA09owmh5yrtfNXCB1fg3s,589
|
|
2
|
+
chromatic/_typing.py,sha256=6AYJx2dsRhLOtOwy3TTLSYLcBdCGaqKwR46Z41u9bbY,6085
|
|
3
|
+
chromatic/demo.py,sha256=Vi-TFpw1ARnZRbfaCca1bT4-FbtrjXejTOspycr8eU8,13151
|
|
4
|
+
chromatic/ascii/__init__.py,sha256=Ic3bqfqr0uAJd6vB4kToDookvZVr8Nrkyy3speiH5oM,164
|
|
5
|
+
chromatic/ascii/_array.py,sha256=1vR_LsGvQrAUmwIBBeFfmyEKciI7chdV_0kr2Q-gAdw,36197
|
|
6
|
+
chromatic/ascii/_curses.py,sha256=9zUeBrylcMXD-R0n5KBVqafAecd6lrQX1Yxjp-BrN98,3719
|
|
7
|
+
chromatic/ascii/_glyph_proc.py,sha256=rqtx6zLxwqqHa1YzuBhL-zhr3LptaHZBnL6ow9W3eI0,2840
|
|
8
|
+
chromatic/color/__init__.py,sha256=8dnpWqbmEciFgJrQpUC0gV9M5D1bKIF7d9Sl4mj0x7g,185
|
|
9
|
+
chromatic/color/colorconv.py,sha256=Ie6P_MUIXk6KcxyIJMw7HuGZWg9sBZVzgGYX4XRMDfA,8581
|
|
10
|
+
chromatic/color/core.py,sha256=K3JpWxsenRqd2IoNRnJRSxK6cpSpGV_M8wVqaQxJfmI,58488
|
|
11
|
+
chromatic/color/core.pyi,sha256=0bREo8eV5LNiA-a014w0C1yML7F3MG3_Vj_XcC6bYAs,11310
|
|
12
|
+
chromatic/color/palette.py,sha256=RTEj-YO20ZlVP2D9lhlge2v-ef5ENUyxHubAo0Ji5Og,23450
|
|
13
|
+
chromatic/color/palette.pyi,sha256=cj9Lmgw6MVCDY8Ew7wc9CvyWP6G4ZqRZnXJgOizBAO8,8780
|
|
14
|
+
chromatic/data/__init__.py,sha256=TCSacSbkvVExjufkNxarEYCSpKYnybm-gljfA_eumG4,6581
|
|
15
|
+
chromatic/data/__init__.pyi,sha256=AZGa46n1Hck3xHN91Mmm7Qibg--CYweKJMMFPHH6yY8,556
|
|
16
|
+
chromatic/data/fonts/IBM_VGA_437_8x16.ttf,sha256=qMdn-pJWJNKNmHnDoDqGIE94vOTezaCiBv0VK92QbJQ,50124
|
|
17
|
+
chromatic/data/fonts/consolas.ttf,sha256=xubOgRn91H7GpUSaCOLSrX9B6gMUOq4ZMGjtn6WOrrw,459180
|
|
18
|
+
chromatic/data/images/butterfly.jpg,sha256=rnSfMVotSgpTNRPQ9CzYpDp8S8lkCAJ5ZySRrvyDe7I,448399
|
|
19
|
+
chromatic/data/images/escher.png,sha256=FvAC-WOkUVIqHBxasfgCJbH1CN1IwLE-JyMiATOEKFc,132667
|
|
20
|
+
chromatic/data/images/goblin_virus.png,sha256=ygs19t4ZeZYsbiRFXjRyEz8OtgC9Zyl8owX0O-5n40o,8849
|
|
21
|
+
chromatic/data/images/hotdog.jpg,sha256=b0vnoQCarhq-gFu3df512qPTvauvF1Oa0oXVO9msEFc,60823
|
|
22
|
+
chromatic_python-0.1.0.dist-info/LICENSE,sha256=e7GjzmO7L12JDai3XRWHD8PgZvFmzNceEztB6d-9kuA,1086
|
|
23
|
+
chromatic_python-0.1.0.dist-info/METADATA,sha256=VhHfYHh_7GjWE67GYyCQOOuny1tvlgyup780MAC72e8,1869
|
|
24
|
+
chromatic_python-0.1.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
25
|
+
chromatic_python-0.1.0.dist-info/top_level.txt,sha256=wjzxcxfjO8I4u22BS8wL67Bq64c59kbZCqQ--Fc_Mqw,10
|
|
26
|
+
chromatic_python-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
chromatic
|