chromatic-python 0.3.3__tar.gz → 0.4.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.
Files changed (51) hide show
  1. chromatic_python-0.4.0/.github/workflows/publish.yml +22 -0
  2. chromatic_python-0.4.0/.github/workflows/tag-to-release.yml +17 -0
  3. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/.gitignore +2 -7
  4. {chromatic_python-0.3.3/chromatic_python.egg-info → chromatic_python-0.4.0}/PKG-INFO +66 -44
  5. chromatic_python-0.4.0/README.md +124 -0
  6. chromatic_python-0.4.0/banner.png +0 -0
  7. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/__init__.pyi +1 -1
  8. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/_version.py +3 -3
  9. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/colorconv.py +4 -2
  10. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/core.py +440 -445
  11. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/core.pyi +34 -24
  12. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/palette.py +69 -63
  13. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/palette.pyi +2 -4
  14. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/userfont.py +17 -2
  15. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/demo.py +79 -135
  16. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/image/__init__.py +2 -2
  17. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/image/__init__.pyi +1 -1
  18. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/image/_array.py +15 -15
  19. {chromatic_python-0.3.3 → chromatic_python-0.4.0/chromatic_python.egg-info}/PKG-INFO +66 -44
  20. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic_python.egg-info/SOURCES.txt +4 -3
  21. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/tests/test_color_str.py +1 -1
  22. chromatic_python-0.3.3/README.md +0 -102
  23. chromatic_python-0.3.3/logo/logo.ANS +0 -25
  24. chromatic_python-0.3.3/logo/logo.PNG +0 -0
  25. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/.gitattributes +0 -0
  26. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/LICENSE +0 -0
  27. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/__init__.py +0 -0
  28. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/_typing.py +0 -0
  29. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/__init__.py +0 -0
  30. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/__init__.pyi +0 -0
  31. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/color/iterators.py +0 -0
  32. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/__init__.py +0 -0
  33. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/__init__.pyi +0 -0
  34. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/_fetchers.py +0 -0
  35. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/butterfly.jpg +0 -0
  36. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/escher.png +0 -0
  37. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/fonts/consolas.ttf +0 -0
  38. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/fonts/vga437.ttf +0 -0
  39. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/goblin_virus.png +0 -0
  40. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/registry.json +0 -0
  41. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/userfont.pyi +0 -0
  42. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/data/userfont.schema.json +0 -0
  43. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic/image/_curses.py +0 -0
  44. /chromatic_python-0.3.3/chromatic/image/_glyph_proc.py → /chromatic_python-0.4.0/chromatic/image/_glyph.py +0 -0
  45. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic_python.egg-info/dependency_links.txt +0 -0
  46. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic_python.egg-info/requires.txt +0 -0
  47. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/chromatic_python.egg-info/top_level.txt +0 -0
  48. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/pyproject.toml +0 -0
  49. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/requirements.txt +0 -0
  50. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/setup.cfg +0 -0
  51. {chromatic_python-0.3.3 → chromatic_python-0.4.0}/tests/__init__.py +0 -0
@@ -0,0 +1,22 @@
1
+ on:
2
+ release:
3
+ types: [published]
4
+
5
+ jobs:
6
+ build-and-publish:
7
+ if: ${{ !github.event.release.draft && !github.event.release.prerelease }}
8
+ runs-on: ubuntu-latest
9
+ environment: pypi
10
+ permissions:
11
+ id-token: write
12
+ contents: read
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.x"
18
+ - run: python -m pip install --upgrade pip build
19
+ - run: python -m build
20
+ - uses: pypa/gh-action-pypi-publish@release/v1
21
+ with:
22
+ print-hash: true
@@ -0,0 +1,17 @@
1
+ on:
2
+ push:
3
+ tags:
4
+ - "v*.*.*"
5
+
6
+ jobs:
7
+ release:
8
+ runs-on: ubuntu-latest
9
+ permissions:
10
+ contents: write
11
+ steps:
12
+ - uses: softprops/action-gh-release@v2
13
+ with:
14
+ tag_name: ${{ github.ref_name }}
15
+ name: ${{ github.ref_name }}
16
+ generate_release_notes: true
17
+ prerelease: ${{ contains(github.ref_name, '-') }}
@@ -1,11 +1,6 @@
1
1
  *.pyc
2
2
  *.pyo
3
3
  __pycache__/
4
- /.idea/
5
- /dist/
6
- /docs/
7
- /tests/_*
8
- /chromatic/data/userfont.json
9
4
  /chromatic/_version.py
10
- /*.egg-info/
11
- /build/
5
+ /chromatic/data/userfont.json
6
+ /tests/_*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chromatic-python
3
- Version: 0.3.3
3
+ Version: 0.4.0
4
4
  Summary: ANSI art image processing and colored terminal text
5
5
  Author: crypt0lith
6
6
  Project-URL: Homepage, https://github.com/crypt0lith/chromatic
@@ -23,7 +23,7 @@ Requires-Dist: fonttools
23
23
  Requires-Dist: lazy_loader
24
24
  Dynamic: license-file
25
25
 
26
- ![image](/logo/logo.PNG)
26
+ ![image](https://raw.githubusercontent.com/crypt0lith/chromatic/master/banner.png)
27
27
 
28
28
  [![image](https://img.shields.io/pypi/v/chromatic-python)](https://pypi.org/project/chromatic-python/)
29
29
  ![image](https://img.shields.io/pypi/pyversions/chromatic-python)
@@ -35,89 +35,108 @@ Chromatic is a library for processing and transforming ANSI escape sequences (co
35
35
  It offers a collection of algorithms and types for a variety of use cases:
36
36
  - Image-to-ASCII / Image-to-ANSI conversions.
37
37
  - ANSI art rendering, with support for user-defined fonts.
38
- - A `ColorStr` type which enables precise low-level control over ANSI-escaped strings through a convenient interface.
38
+ - A `ColorStr` type for low-level control over ANSI SGR strings.
39
39
  - [colorama](https://github.com/tartley/colorama/)-style wrappers (`Fore`, `Back`, `Style`).
40
- - Parametrization of ANSI color bit formats, allowing arbitrary conversion between 16-color, 256-color, and true-color (RGB) colorspace on any object implementing a `colorbytes` buffer.
40
+ - Conversion between 16-color, 256-color, and true-color (RGB) ANSI colorspace via the `colorbytes` type.
41
41
  - Et Cetera 😲
42
42
 
43
43
  ### Usage
44
+ #### Image-to-ANSI conversion
45
+
46
+ Convert an image into a 2d ANSI string array, and render the ANSI array as image:
47
+ ```python
48
+ from chromatic.color import ansicolor4Bit
49
+ from chromatic.image import ansi2img, img2ansi
50
+ from chromatic.data import userfont, butterfly
51
+
52
+ input_img = butterfly()
53
+ font = userfont['vga437']
54
+
55
+ # `char_set` is used to translate luminance to characters
56
+ # | <- index 0 is the 'darkest'
57
+ char_set = r"'·,•-_→+<>ⁿ*%⌂7√Iï∞πbz£9yîU{}1αHSw♥æ?GX╕╒éà⌡MF╝╩ΘûǃQ½☻Ŷ┤▄╪║▒█"
58
+ # index -1 is the 'brightest' -> |
59
+
60
+ # returns list[list[ColorStr]]
61
+ ansi_array = img2ansi(
62
+ input_img,
63
+ font,
64
+ sort_glyphs=False, # map `char_set` as-is
65
+ char_set=char_set,
66
+ ansi_type=ansicolor4Bit,
67
+ factor=200,
68
+ )
69
+
70
+ # print your image to stdout
71
+ print(*map(''.join, ansi_array), sep="\x1b[0m\n")
72
+
73
+ # returns a PIL.Image.Image object
74
+ ansi_img = ansi2img(ansi_array, font, font_size=16)
75
+ ansi_img.show()
76
+ ```
77
+
44
78
  #### ColorStr
45
79
  ```python
46
80
  from chromatic import ColorStr
47
81
 
48
82
  base_str = 'hello world'
49
83
 
50
- red_fg = ColorStr(base_str, 0xFF0000)
84
+ red_fg = ColorStr(base_str, 0xFF0000, ansi_type='8b')
51
85
 
52
86
  assert red_fg.base_str == base_str
53
87
  assert red_fg.rgb_dict == {'fg': (0xFF, 0, 0)}
54
88
  assert red_fg.ansi == b'\x1b[38;5;196m'
55
89
  ```
56
90
 
57
- `ColorStr` can handle different signatures for `color_spec`:
91
+ `ColorStr` will parse raw SGR sequences, and accepts different types for `fg` and `bg`:
58
92
  ```python
59
93
  from chromatic import ColorStr
60
94
 
61
- assert all(
62
- ColorStr('*', cs) == ColorStr('*', 0xFF0000)
63
- for cs in [b'\x1b[38;5;196m', b'\xff\x00\x00', (0xFF, 0, 0), {'fg': 0xFF0000}]
64
- )
95
+ red_fg = ColorStr('[*]', 0xFF0000, ansi_type='8b')
96
+
97
+ assert red_fg == ColorStr(b"\x1b[38;5;196m[*]")
98
+ assert red_fg == ColorStr('[*]', fg=(0xFF, 0, 0), ansi_type='8b')
65
99
  ```
66
100
 
67
- The ANSI color format can be given as an argument, or returned by `ColorStr.as_ansi_type()` as a new instance.
101
+ ANSI color format can be specified with `ColorStr(ansi_type=...)`, or as a new object via `ColorStr.as_ansi_type()`:
68
102
  ```python
69
- from chromatic import ColorStr, ansicolor24Bit, ansicolor4Bit
103
+ from chromatic import ColorStr, ansicolor4Bit, ansicolor24Bit, ansicolor8Bit
104
+
105
+ # each colorbytes type has an alias that you can use
106
+ assert all(
107
+ ansi_type.alias == alias
108
+ for ansi_type, alias in [
109
+ (ansicolor4Bit, '4b'),
110
+ (ansicolor8Bit, '8b'),
111
+ (ansicolor24Bit, '24b'),
112
+ ]
113
+ )
70
114
 
71
115
  truecolor = ColorStr('*', 0xFF0000, ansi_type=ansicolor24Bit)
72
116
  a_16color = truecolor.as_ansi_type(ansicolor4Bit)
73
117
 
74
- # each ansi color format has an alias that can be used in place of the type object
75
118
  assert a_16color == truecolor.as_ansi_type('4b')
76
-
77
119
  assert truecolor.ansi_format is ansicolor24Bit and truecolor.ansi == b'\x1b[38;2;255;0;0m'
78
120
  assert a_16color.ansi_format is ansicolor4Bit and a_16color.ansi == b'\x1b[31m'
79
121
  ```
80
122
 
81
- Adding and removing specific ANSI codes from the escape sequence:
123
+ Adding and removing SGR parameters from a `ColorStr`:
82
124
  ```python
83
125
  import chromatic as cm
84
126
 
85
- boring_str = cm.ColorStr('hello world')
127
+ regular_str = cm.ColorStr('hello world')
86
128
 
87
- assert boring_str.ansi == b''
129
+ assert regular_str.ansi == b''
130
+
131
+ bold_str = regular_str.bold()
88
132
 
89
- bold_str = boring_str + cm.SgrParameter.BOLD
90
133
  assert bold_str.ansi == b'\x1b[1m'
91
134
 
92
135
  # use ColorStr.update_sgr() to remove and add SGR values
93
136
  unbold_str = bold_str.update_sgr(cm.SgrParameter.BOLD)
94
- assert unbold_str == boring_str
95
- assert bold_str == unbold_str.update_sgr(cm.SgrParameter.BOLD)
96
- ```
97
-
98
- #### Image-to-ANSI conversion
99
-
100
- Converting an image into an array of ANSI-escaped characters, then rendering the ANSI array as another image:
101
- ```python
102
- from chromatic.color import ansicolor4Bit
103
- from chromatic.ascii import ansi2img, img2ansi
104
- from chromatic.data import UserFont, butterfly
105
137
 
106
- input_img = butterfly()
107
-
108
- font = UserFont.IBM_VGA_437_8X16
109
-
110
- # by default, `char_set` would be sorted based on the relative weight of glyphs in the font
111
- # but because `sort_glyphs` is set to False, `char_set` will be directly mapped to the image brightness
112
- # | <- index 0 is the 'darkest'
113
- char_set = r"'·,•-_→+<>ⁿ*%⌂7√Iï∞πbz£9yîU{}1αHSw♥æ?GX╕╒éà⌡MF╝╩ΘûǃQ½☻Ŷ┤▄╪║▒█"
114
- # index -1 is the 'brightest' -> |
115
-
116
- ansi_array = img2ansi(input_img, font, sort_glyphs=False, char_set=char_set, ansi_type=ansicolor4Bit, factor=200)
117
-
118
- # ansi2img() returns a PIL.Image.Image object
119
- ansi_img = ansi2img(ansi_array, font, font_size=16)
120
- ansi_img.show()
138
+ assert unbold_str == regular_str
139
+ assert bold_str == unbold_str + cm.SgrParameter.BOLD # __add__ can also be used
121
140
  ```
122
141
 
123
142
  ### Installation
@@ -125,3 +144,6 @@ Install the package using `pip`:
125
144
  ```bash
126
145
  pip install chromatic-python
127
146
  ```
147
+
148
+ ### Credits
149
+ Banner artwork: [main rules by Crasher (2002)](https://16colo.rs/pack/galza-14/CRS-MAIN.ANS)
@@ -0,0 +1,124 @@
1
+ ![image](https://raw.githubusercontent.com/crypt0lith/chromatic/master/banner.png)
2
+
3
+ [![image](https://img.shields.io/pypi/v/chromatic-python)](https://pypi.org/project/chromatic-python/)
4
+ ![image](https://img.shields.io/pypi/pyversions/chromatic-python)
5
+ [![image](https://static.pepy.tech/badge/chromatic-python)](https://pepy.tech/projects/chromatic-python)
6
+ [![image](https://mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/)
7
+
8
+ Chromatic is a library for processing and transforming ANSI escape sequences (colored terminal text).
9
+
10
+ It offers a collection of algorithms and types for a variety of use cases:
11
+ - Image-to-ASCII / Image-to-ANSI conversions.
12
+ - ANSI art rendering, with support for user-defined fonts.
13
+ - A `ColorStr` type for low-level control over ANSI SGR strings.
14
+ - [colorama](https://github.com/tartley/colorama/)-style wrappers (`Fore`, `Back`, `Style`).
15
+ - Conversion between 16-color, 256-color, and true-color (RGB) ANSI colorspace via the `colorbytes` type.
16
+ - Et Cetera 😲
17
+
18
+ ### Usage
19
+ #### Image-to-ANSI conversion
20
+
21
+ Convert an image into a 2d ANSI string array, and render the ANSI array as image:
22
+ ```python
23
+ from chromatic.color import ansicolor4Bit
24
+ from chromatic.image import ansi2img, img2ansi
25
+ from chromatic.data import userfont, butterfly
26
+
27
+ input_img = butterfly()
28
+ font = userfont['vga437']
29
+
30
+ # `char_set` is used to translate luminance to characters
31
+ # | <- index 0 is the 'darkest'
32
+ char_set = r"'·,•-_→+<>ⁿ*%⌂7√Iï∞πbz£9yîU{}1αHSw♥æ?GX╕╒éà⌡MF╝╩ΘûǃQ½☻Ŷ┤▄╪║▒█"
33
+ # index -1 is the 'brightest' -> |
34
+
35
+ # returns list[list[ColorStr]]
36
+ ansi_array = img2ansi(
37
+ input_img,
38
+ font,
39
+ sort_glyphs=False, # map `char_set` as-is
40
+ char_set=char_set,
41
+ ansi_type=ansicolor4Bit,
42
+ factor=200,
43
+ )
44
+
45
+ # print your image to stdout
46
+ print(*map(''.join, ansi_array), sep="\x1b[0m\n")
47
+
48
+ # returns a PIL.Image.Image object
49
+ ansi_img = ansi2img(ansi_array, font, font_size=16)
50
+ ansi_img.show()
51
+ ```
52
+
53
+ #### ColorStr
54
+ ```python
55
+ from chromatic import ColorStr
56
+
57
+ base_str = 'hello world'
58
+
59
+ red_fg = ColorStr(base_str, 0xFF0000, ansi_type='8b')
60
+
61
+ assert red_fg.base_str == base_str
62
+ assert red_fg.rgb_dict == {'fg': (0xFF, 0, 0)}
63
+ assert red_fg.ansi == b'\x1b[38;5;196m'
64
+ ```
65
+
66
+ `ColorStr` will parse raw SGR sequences, and accepts different types for `fg` and `bg`:
67
+ ```python
68
+ from chromatic import ColorStr
69
+
70
+ red_fg = ColorStr('[*]', 0xFF0000, ansi_type='8b')
71
+
72
+ assert red_fg == ColorStr(b"\x1b[38;5;196m[*]")
73
+ assert red_fg == ColorStr('[*]', fg=(0xFF, 0, 0), ansi_type='8b')
74
+ ```
75
+
76
+ ANSI color format can be specified with `ColorStr(ansi_type=...)`, or as a new object via `ColorStr.as_ansi_type()`:
77
+ ```python
78
+ from chromatic import ColorStr, ansicolor4Bit, ansicolor24Bit, ansicolor8Bit
79
+
80
+ # each colorbytes type has an alias that you can use
81
+ assert all(
82
+ ansi_type.alias == alias
83
+ for ansi_type, alias in [
84
+ (ansicolor4Bit, '4b'),
85
+ (ansicolor8Bit, '8b'),
86
+ (ansicolor24Bit, '24b'),
87
+ ]
88
+ )
89
+
90
+ truecolor = ColorStr('*', 0xFF0000, ansi_type=ansicolor24Bit)
91
+ a_16color = truecolor.as_ansi_type(ansicolor4Bit)
92
+
93
+ assert a_16color == truecolor.as_ansi_type('4b')
94
+ assert truecolor.ansi_format is ansicolor24Bit and truecolor.ansi == b'\x1b[38;2;255;0;0m'
95
+ assert a_16color.ansi_format is ansicolor4Bit and a_16color.ansi == b'\x1b[31m'
96
+ ```
97
+
98
+ Adding and removing SGR parameters from a `ColorStr`:
99
+ ```python
100
+ import chromatic as cm
101
+
102
+ regular_str = cm.ColorStr('hello world')
103
+
104
+ assert regular_str.ansi == b''
105
+
106
+ bold_str = regular_str.bold()
107
+
108
+ assert bold_str.ansi == b'\x1b[1m'
109
+
110
+ # use ColorStr.update_sgr() to remove and add SGR values
111
+ unbold_str = bold_str.update_sgr(cm.SgrParameter.BOLD)
112
+
113
+ assert unbold_str == regular_str
114
+ assert bold_str == unbold_str + cm.SgrParameter.BOLD # __add__ can also be used
115
+ ```
116
+
117
+ ### Installation
118
+ Install the package using `pip`:
119
+ ```bash
120
+ pip install chromatic-python
121
+ ```
122
+
123
+ ### Credits
124
+ Banner artwork: [main rules by Crasher (2002)](https://16colo.rs/pack/galza-14/CRS-MAIN.ANS)
Binary file
@@ -87,4 +87,4 @@ from .image import (
87
87
  reshape_ansi,
88
88
  to_sgr_array,
89
89
  )
90
- from .image._glyph_proc import get_glyph_masks, sort_glyphs, ttf_extract_codepoints
90
+ from .image._glyph import get_glyph_masks, sort_glyphs, ttf_extract_codepoints
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.3.3'
32
- __version_tuple__ = version_tuple = (0, 3, 3)
31
+ __version__ = version = '0.4.0'
32
+ __version_tuple__ = version_tuple = (0, 4, 0)
33
33
 
34
- __commit_id__ = commit_id = 'g23243f5d4'
34
+ __commit_id__ = commit_id = 'g2288358be'
@@ -59,7 +59,7 @@ def is_u24(value, *, strict: bool = False):
59
59
  ValueError
60
60
  Raised when `strict=True` and value is not u24
61
61
  """
62
- if _supports_int(type(value)):
62
+ if _supports_int(value.__class__):
63
63
  if 0 <= int(value) <= 0xFFFFFF:
64
64
  return True
65
65
  elif not strict:
@@ -92,7 +92,9 @@ def int2rgb(__x: int) -> Int3Tuple:
92
92
  try:
93
93
  return getattr(__x, 'rgb')
94
94
  except AttributeError:
95
- return (__x >> 16) & 0xFF, (__x >> 8) & 0xFF, __x & 0xFF
95
+ pass
96
+ x = int(__x) & 0xFFFFFF
97
+ return (x >> 16) & 0xFF, (x >> 8) & 0xFF, x & 0xFF
96
98
 
97
99
 
98
100
  def xyz2lab(xyz: FloatSequence) -> Float3Tuple: