chromatic-python 0.1.0__tar.gz
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_python-0.1.0/LICENSE +21 -0
- chromatic_python-0.1.0/PKG-INFO +39 -0
- chromatic_python-0.1.0/README.md +0 -0
- chromatic_python-0.1.0/chromatic/__init__.py +26 -0
- chromatic_python-0.1.0/chromatic/_typing.py +168 -0
- chromatic_python-0.1.0/chromatic/ascii/__init__.py +5 -0
- chromatic_python-0.1.0/chromatic/ascii/_array.py +1059 -0
- chromatic_python-0.1.0/chromatic/ascii/_curses.py +153 -0
- chromatic_python-0.1.0/chromatic/ascii/_glyph_proc.py +107 -0
- chromatic_python-0.1.0/chromatic/color/__init__.py +6 -0
- chromatic_python-0.1.0/chromatic/color/colorconv.py +316 -0
- chromatic_python-0.1.0/chromatic/color/core.py +1677 -0
- chromatic_python-0.1.0/chromatic/color/core.pyi +421 -0
- chromatic_python-0.1.0/chromatic/color/palette.py +693 -0
- chromatic_python-0.1.0/chromatic/color/palette.pyi +330 -0
- chromatic_python-0.1.0/chromatic/data/__init__.py +189 -0
- chromatic_python-0.1.0/chromatic/data/__init__.pyi +15 -0
- chromatic_python-0.1.0/chromatic/data/fonts/IBM_VGA_437_8x16.ttf +0 -0
- chromatic_python-0.1.0/chromatic/data/fonts/consolas.ttf +0 -0
- chromatic_python-0.1.0/chromatic/data/images/butterfly.jpg +0 -0
- chromatic_python-0.1.0/chromatic/data/images/escher.png +0 -0
- chromatic_python-0.1.0/chromatic/data/images/goblin_virus.png +0 -0
- chromatic_python-0.1.0/chromatic/data/images/hotdog.jpg +0 -0
- chromatic_python-0.1.0/chromatic/demo.py +417 -0
- chromatic_python-0.1.0/chromatic_python.egg-info/PKG-INFO +39 -0
- chromatic_python-0.1.0/chromatic_python.egg-info/SOURCES.txt +51 -0
- chromatic_python-0.1.0/chromatic_python.egg-info/dependency_links.txt +1 -0
- chromatic_python-0.1.0/chromatic_python.egg-info/requires.txt +8 -0
- chromatic_python-0.1.0/chromatic_python.egg-info/top_level.txt +1 -0
- chromatic_python-0.1.0/pyproject.toml +36 -0
- chromatic_python-0.1.0/setup.cfg +4 -0
- chromatic_python-0.1.0/tests/test_color_str.py +332 -0
|
@@ -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
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from . import ascii, color, data
|
|
2
|
+
from .ascii import (
|
|
3
|
+
ansi2img,
|
|
4
|
+
ansi_quantize,
|
|
5
|
+
ascii2img,
|
|
6
|
+
ascii_printable,
|
|
7
|
+
contrast_stretch,
|
|
8
|
+
cp437_printable,
|
|
9
|
+
equalize_white_point,
|
|
10
|
+
get_font_key,
|
|
11
|
+
get_font_object,
|
|
12
|
+
img2ansi,
|
|
13
|
+
img2ascii,
|
|
14
|
+
read_ans,
|
|
15
|
+
render_ans,
|
|
16
|
+
reshape_ansi,
|
|
17
|
+
to_sgr_array
|
|
18
|
+
)
|
|
19
|
+
from .ascii._glyph_proc import get_glyph_masks
|
|
20
|
+
from .color import (
|
|
21
|
+
ansicolor24Bit, ansicolor4Bit, ansicolor8Bit, Back, Color, colorbytes, ColorStr, Fore,
|
|
22
|
+
SgrParameter, Style
|
|
23
|
+
)
|
|
24
|
+
from .data import register_user_font
|
|
25
|
+
|
|
26
|
+
__all__ = []
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from functools import reduce
|
|
5
|
+
from numbers import Number
|
|
6
|
+
from types import UnionType
|
|
7
|
+
from typing import (
|
|
8
|
+
Any, Callable, Concatenate, get_args, get_origin, get_type_hints, Iterable, Literal, ParamSpec,
|
|
9
|
+
Protocol, Sequence, SupportsRound, TYPE_CHECKING, TypeVar, Union
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from numpy import dtype, float64, generic, ndarray, number, uint8
|
|
13
|
+
from numpy._typing import _ArrayLike, NDArray
|
|
14
|
+
from PIL.Image import Image
|
|
15
|
+
from PIL.ImageFont import FreeTypeFont
|
|
16
|
+
|
|
17
|
+
from chromatic.data import UserFont
|
|
18
|
+
|
|
19
|
+
_P = ParamSpec('_P')
|
|
20
|
+
_T = TypeVar('_T')
|
|
21
|
+
_T_co = TypeVar('_T_co', covariant=True)
|
|
22
|
+
_T_contra = TypeVar('_T_contra', contravariant=True)
|
|
23
|
+
_AnyNumber_co = TypeVar('_AnyNumber_co', number, Number, covariant=True)
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
from _typeshed import SupportsRichComparison, SupportsDivMod
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SupportsRoundAndDivMod(
|
|
30
|
+
SupportsRound[_T_co],
|
|
31
|
+
SupportsDivMod[Any, _T_co],
|
|
32
|
+
Protocol
|
|
33
|
+
):
|
|
34
|
+
...
|
|
35
|
+
|
|
36
|
+
type ArrayReducerFunc[_SCT: generic] = Callable[Concatenate[_ArrayLike[_SCT], _P], NDArray[_SCT]]
|
|
37
|
+
type KeyFunction[_T] = Callable[[_T], SupportsRichComparison]
|
|
38
|
+
type ShapedNDArray[_Shape: tuple[int, ...], _SCT: generic] = ndarray[_Shape, dtype[_SCT]]
|
|
39
|
+
type MatrixLike[_SCT: generic] = ShapedNDArray[TupleOf2[int], _SCT]
|
|
40
|
+
type SquareMatrix[_I: int, _SCT: generic] = ShapedNDArray[TupleOf2[_I], _SCT]
|
|
41
|
+
type GlyphArray[_SCT: generic] = SquareMatrix[Literal[24], _SCT]
|
|
42
|
+
type TupleOf2[_T] = tuple[_T, _T]
|
|
43
|
+
type TupleOf3[_T] = tuple[_T, _T, _T]
|
|
44
|
+
Float3Tuple = TupleOf3[float]
|
|
45
|
+
Int3Tuple = TupleOf3[int]
|
|
46
|
+
FloatSequence = Sequence[float]
|
|
47
|
+
IntSequence = Sequence[int]
|
|
48
|
+
GlyphBitmask = GlyphArray[bool]
|
|
49
|
+
Bitmask = MatrixLike[bool]
|
|
50
|
+
GreyscaleGlyphArray = GlyphArray[float64]
|
|
51
|
+
GreyscaleArray = MatrixLike[float64]
|
|
52
|
+
RGBArray = ShapedNDArray[tuple[int, int, Literal[3]], uint8]
|
|
53
|
+
RGBPixel = ShapedNDArray[tuple[Literal[3]], uint8]
|
|
54
|
+
|
|
55
|
+
RGBImageLike = Union[Image, RGBArray]
|
|
56
|
+
RGBVectorLike = Union[Int3Tuple, IntSequence, RGBPixel]
|
|
57
|
+
ColorDictKeys = Literal['fg', 'bg']
|
|
58
|
+
Ansi4BitAlias = Literal['4b']
|
|
59
|
+
Ansi8BitAlias = Literal['8b']
|
|
60
|
+
Ansi24BitAlias = Literal['24b']
|
|
61
|
+
AnsiColorAlias = Ansi4BitAlias | Ansi8BitAlias | Ansi24BitAlias
|
|
62
|
+
FontArgType = Union[FreeTypeFont | UserFont, str, int]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def is_matching_type(value, typ):
|
|
66
|
+
if typ is Any:
|
|
67
|
+
return True
|
|
68
|
+
origin, args = deconstruct_type(typ)
|
|
69
|
+
if origin is Union:
|
|
70
|
+
return any(is_matching_type(value, arg) for arg in args)
|
|
71
|
+
elif origin is Literal:
|
|
72
|
+
return value in args
|
|
73
|
+
elif isinstance(typ, TypeVar):
|
|
74
|
+
if typ.__constraints__:
|
|
75
|
+
return any(
|
|
76
|
+
is_matching_type(value, constraint) for constraint in typ.__constraints__)
|
|
77
|
+
else:
|
|
78
|
+
return True
|
|
79
|
+
elif origin is type:
|
|
80
|
+
if not isinstance(value, type):
|
|
81
|
+
return False
|
|
82
|
+
target_type = args[0]
|
|
83
|
+
target_origin = get_origin(target_type)
|
|
84
|
+
target_args = get_args(target_type)
|
|
85
|
+
if target_origin is Union:
|
|
86
|
+
return any(issubclass(value, t) for t in target_args)
|
|
87
|
+
else:
|
|
88
|
+
return issubclass(value, target_type)
|
|
89
|
+
elif origin is Callable:
|
|
90
|
+
return is_matching_callable(value, typ)
|
|
91
|
+
elif origin is list:
|
|
92
|
+
if not isinstance(value, list):
|
|
93
|
+
return False
|
|
94
|
+
if not args:
|
|
95
|
+
return True
|
|
96
|
+
return all(is_matching_type(item, args[0]) for item in value)
|
|
97
|
+
elif origin is dict:
|
|
98
|
+
if not isinstance(value, dict):
|
|
99
|
+
return False
|
|
100
|
+
if not args:
|
|
101
|
+
return True
|
|
102
|
+
key_type, val_type = args
|
|
103
|
+
return all(
|
|
104
|
+
is_matching_type(k, key_type) and is_matching_type(v, val_type) for k, v in
|
|
105
|
+
value.items())
|
|
106
|
+
elif origin is tuple:
|
|
107
|
+
if not isinstance(value, tuple):
|
|
108
|
+
return False
|
|
109
|
+
if len(args) == 2 and args[1] is ...:
|
|
110
|
+
return all(is_matching_type(item, args[0]) for item in value)
|
|
111
|
+
if len(value) != len(args):
|
|
112
|
+
return False
|
|
113
|
+
return all(is_matching_type(v, t) for v, t in zip(value, args))
|
|
114
|
+
else:
|
|
115
|
+
try:
|
|
116
|
+
return isinstance(value, typ)
|
|
117
|
+
except TypeError:
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def deconstruct_type(tp):
|
|
122
|
+
origin = get_origin(tp) or tp
|
|
123
|
+
args = get_args(tp)
|
|
124
|
+
return origin, args
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def is_matching_callable(value, expected_type):
|
|
128
|
+
if not callable(value):
|
|
129
|
+
return False
|
|
130
|
+
return id(value) == id(expected_type)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def pseudo_union(ts: Iterable[type]) -> Union[type, UnionType]:
|
|
134
|
+
return reduce(lambda x, y: x | y, ts)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def type_error_msg(err_obj, *expected, context: str = '', obj_repr=False):
|
|
138
|
+
n_expected = len(expected)
|
|
139
|
+
name_slots = [f"{{{n}.__qualname__!r}}" for n in range(n_expected)]
|
|
140
|
+
if name_slots and n_expected > 1:
|
|
141
|
+
name_slots[-1] = f"or {name_slots[-1]}"
|
|
142
|
+
names = (', ' if n_expected > 2 else ' ').join(
|
|
143
|
+
[context.strip()] + name_slots).format(*expected)
|
|
144
|
+
if not obj_repr:
|
|
145
|
+
if not isinstance(err_obj, type):
|
|
146
|
+
err_obj = type(err_obj)
|
|
147
|
+
oops = repr(err_obj.__qualname__)
|
|
148
|
+
elif not isinstance(err_obj, str):
|
|
149
|
+
oops = repr(err_obj)
|
|
150
|
+
else:
|
|
151
|
+
oops = err_obj
|
|
152
|
+
return f"expected {names}, got {oops} instead"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def is_matching_typed_dict(__d: dict, typed_dict: type[dict]) -> tuple[bool, str]:
|
|
156
|
+
if not isinstance(__d, dict):
|
|
157
|
+
return False, type_error_msg(__d, dict)
|
|
158
|
+
expected = get_type_hints(typed_dict)
|
|
159
|
+
if unexpected := __d.keys() - expected:
|
|
160
|
+
return False, f"unexpected keyword arguments: {unexpected}"
|
|
161
|
+
if missing := set(getattr(typed_dict, '__required_keys__', expected)) - __d.keys():
|
|
162
|
+
return False, f"missing required keys: {missing}"
|
|
163
|
+
for name, typ in expected.items():
|
|
164
|
+
if ((field := __d.get(name)) is not None) and not is_matching_type(field, typ):
|
|
165
|
+
return False, type_error_msg(
|
|
166
|
+
field, typ,
|
|
167
|
+
context=f'keyword argument {name!r} of type')
|
|
168
|
+
return True, ''
|