├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .pylintrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── assets
│ ├── css
│ │ └── mkdocstrings.css
│ ├── images
│ │ ├── diagrams
│ │ │ ├── formats
│ │ │ │ └── overview
│ │ │ │ │ └── colorization.webp
│ │ │ └── styles
│ │ │ │ ├── braille
│ │ │ │ └── processing.webp
│ │ │ │ ├── gradient
│ │ │ │ └── processing.webp
│ │ │ │ └── overview
│ │ │ │ ├── processing.webp
│ │ │ │ └── resizing.webp
│ │ ├── favicon.webp
│ │ ├── logo.png
│ │ ├── logo.webp
│ │ ├── outputs
│ │ │ ├── demo
│ │ │ │ ├── apple-braille.webp
│ │ │ │ └── apple-gradient.webp
│ │ │ ├── draw
│ │ │ │ ├── dimensions
│ │ │ │ │ ├── zima-h32.webp
│ │ │ │ │ ├── zima-term-h.webp
│ │ │ │ │ ├── zima-term-w.webp
│ │ │ │ │ └── zima-w32.webp
│ │ │ │ ├── resample
│ │ │ │ │ ├── starry-night-resample-bicubic.webp
│ │ │ │ │ ├── starry-night-resample-bilinear.webp
│ │ │ │ │ ├── starry-night-resample-box.webp
│ │ │ │ │ ├── starry-night-resample-hamming.webp
│ │ │ │ │ ├── starry-night-resample-lanczos.webp
│ │ │ │ │ └── starry-night-resample-nearest.webp
│ │ │ │ └── styles
│ │ │ │ │ ├── braille
│ │ │ │ │ └── threshold
│ │ │ │ │ │ ├── contributions-braille-t0.webp
│ │ │ │ │ │ ├── contributions-braille-t108.webp
│ │ │ │ │ │ ├── contributions-braille-t168.webp
│ │ │ │ │ │ ├── contributions-braille-t210.webp
│ │ │ │ │ │ └── contributions-braille-t70.webp
│ │ │ │ │ └── gradient
│ │ │ │ │ ├── charset
│ │ │ │ │ ├── slack-gradient-charset-block.webp
│ │ │ │ │ ├── slack-gradient-charset-default.webp
│ │ │ │ │ ├── slack-gradient-charset-dot.webp
│ │ │ │ │ └── slack-gradient-charset-hash.webp
│ │ │ │ │ └── negative
│ │ │ │ │ ├── github-gradient-negative.webp
│ │ │ │ │ └── github-gradient-normal.webp
│ │ │ ├── examples
│ │ │ │ ├── 01-image
│ │ │ │ │ └── hackerman-gradient.webp
│ │ │ │ └── 02-gif
│ │ │ │ │ ├── nyan-braille.webp
│ │ │ │ │ └── nyan-gradient.webp
│ │ │ └── format
│ │ │ │ └── colorize
│ │ │ │ ├── instagram-color.webp
│ │ │ │ └── instagram-gray.webp
│ │ └── subjects
│ │ │ ├── apple.webp
│ │ │ ├── contributions.webp
│ │ │ ├── github.webp
│ │ │ ├── instagram.webp
│ │ │ ├── slack.webp
│ │ │ ├── starry-night.webp
│ │ │ └── zima.webp
│ └── js
│ │ └── config.js
├── commands
│ ├── draw
│ │ ├── braille.md
│ │ ├── gradient.md
│ │ └── index.md
│ ├── index.md
│ └── info.md
├── contributing.md
├── examples
│ ├── 01-image
│ │ ├── hackerman.webp
│ │ ├── index.md
│ │ └── main.py
│ ├── 02-gif
│ │ ├── index.md
│ │ ├── main.py
│ │ └── nyan.webp
│ └── 03-web
│ │ ├── index.md
│ │ └── main.py
├── formats
│ ├── ansi.md
│ ├── html.md
│ └── index.md
├── index.md
├── library
│ ├── draw
│ │ ├── base.md
│ │ ├── braille.md
│ │ ├── gradient.md
│ │ └── index.md
│ ├── format
│ │ ├── ansi.md
│ │ ├── base.md
│ │ ├── html.md
│ │ └── index.md
│ ├── meta.md
│ └── utils.md
├── license.md
├── overrides
│ ├── main.html
│ └── partials
│ │ └── footer.html
├── snippets
│ └── cli
│ │ ├── draw
│ │ ├── braille
│ │ │ └── help.txt
│ │ ├── gradient
│ │ │ └── help.txt
│ │ └── help.txt
│ │ ├── help.txt
│ │ └── info
│ │ └── help.txt
└── styles
│ ├── braille.md
│ ├── gradient.md
│ └── index.md
├── mkdocs.yml
├── requirements.txt
├── setup.py
└── src
├── __init__.py
├── __main__.py
├── cli
├── __init__.py
├── draw
│ ├── __init__.py
│ ├── braille.py
│ └── gradient.py
└── info.py
├── data
└── logo.txt
├── draw
├── __init__.py
├── base.py
├── braille.py
└── gradient.py
├── format
├── __init__.py
├── ansi.py
├── base.py
└── html.py
├── meta.py
└── utils.py
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 | on:
3 | push:
4 | branches:
5 | - master
6 |
7 | # Environment
8 | env:
9 | CI: true
10 | PYTHON_VERSION: 3.x
11 |
12 | # Jobs to run
13 | jobs:
14 | # Deploy documentation
15 | deploy:
16 | runs-on: ubuntu-latest
17 | steps:
18 | # Checkout source form GitHub
19 | - uses: actions/checkout@v2
20 |
21 | # Install Python runtime and dependencies
22 | - uses: actions/setup-python@v1
23 | with:
24 | python-version: ${{ env.PYTHON_VERSION }}
25 |
26 | # Install package and dependencies
27 | - run: |
28 | pip install -r requirements.txt
29 | pip install .
30 |
31 | # Build documentation
32 | - env:
33 | GOOGLE_ANALYTICS_KEY: ${{ secrets.GOOGLE_ANALYTICS_KEY }}
34 | run: |
35 | mkdocs gh-deploy --force
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python
2 | __pycache__/
3 | build
4 | dist
5 | *.egg-info
6 |
7 | # MkDocs
8 | site/
9 |
--------------------------------------------------------------------------------
/.pylintrc:
--------------------------------------------------------------------------------
1 | [TYPECHECK]
2 | disable=
3 | arguments-differ,
4 | bad-continuation,
5 | too-many-arguments
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Thank you for your interest in contributing to Picharsso!
4 |
5 | For someone unfamiliar with the code base,
6 | the most efficient way to contribute is
7 | to submit a [feature request](#feature-requests) or [bug report](#bug-reports).
8 |
9 | If you want to dive into the source code,
10 | you can submit a [patch](#patches) as well,
11 | either working on your own ideas or [existing issues][issues].
12 |
13 | ## Feature Requests
14 |
15 | Do you have an idea for an awesome new feature for Picharsso?
16 | Please [submit a feature request][issue].
17 | It's great to hear about new ideas!
18 |
19 | If you are inclined to do so,
20 | you're welcome to [fork][fork] Picharsso,
21 | work on implementing the feature yourself,
22 | and submit a patch.
23 | In this case, it's _highly recommended_ that you first [open an issue][issue]
24 | describing your enhancement to get early feedback
25 | on the new feature that you are implementing.
26 | This will help avoid wasted efforts and ensure that your work is incorporated
27 | into the code base.
28 |
29 | ## Bug Reports
30 |
31 | Did something go wrong with Picharsso?
32 | Sorry about that!
33 | Bug reports are greatly appreciated!
34 |
35 | When you [submit a bug report][issue],
36 | please include relevant information
37 | such as Picharsso version, operating system,
38 | error messages, and steps to reproduce the bug.
39 | The more details you can include,
40 | the easier it is to find and fix the bug.
41 |
42 | ## Patches
43 |
44 | Want to hack on Picharsso? Awesome!
45 |
46 | If there are [open issues][issues],
47 | you're more than welcome to work on those -
48 | this is probably the best way to contribute to Picharsso.
49 | If you have your own ideas, that's great too!
50 | In that case, before working on substantial changes to the code base,
51 | it is _highly recommended_ that you first [open an issue][issue]
52 | describing what you intend to work on.
53 |
54 | **Patches are generally submitted as pull requests.**
55 |
56 | Any changes to the code base should
57 | follow the style and coding conventions used in the rest of the project.
58 | The version history should be clean,
59 | and commit messages should be descriptive and [properly formatted][commit-messages].
60 |
61 | [issue]: https://github.com/kelvindecosta/picharsso/issues/new
62 | [issues]: https://github.com/kelvindecosta/picharsso/issues
63 | [fork]: https://github.com/kelvindecosta/picharsso/fork
64 | [commit-messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Kelvin DeCosta
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Picharsso
2 |
3 |
4 |
5 |
6 |
7 |
8 | A utility for converting images to text art.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Installation
17 | |
18 | Documentation
19 | |
20 | Examples
21 | |
22 | Contributing
23 |
24 |
25 | ## Installation
26 |
27 | Run the following command:
28 |
29 | ```bash
30 | pip install picharsso
31 | ```
32 |
33 | This will:
34 |
35 | - download and install the [`picharsso` Python package](https://pypi.org/project/picharsso/)
36 | (along with its dependencies).
37 | - create an executable, `picharsso`, for the CLI (command line interface).
38 |
39 | > **Verification**
40 | >
41 | > To verify that Picharsso is installed, run:
42 | >
43 | > ```bash
44 | > python -c "import picharsso"
45 | > ```
46 |
47 | ## Commands
48 |
49 | Picharsso ships with a CLI that provides some basic functionality from the terminal.
50 |
51 | > **Usage**
52 | >
53 | > Run the following command to display a helpful message:
54 | >
55 | > ```bash
56 | > picharsso -h
57 | > ```
58 | >
59 | > ```
60 | > Usage: picharsso [options] [args]
61 | >
62 | > A utility for converting images to text art.
63 | >
64 | > Options:
65 | > -h, --help Show this message and exit.
66 | >
67 | > Commands:
68 | > draw Generate text art from an image.
69 | > info Displays package information.
70 | > ```
71 |
72 | Consider the following image:
73 |
74 |
75 |
76 |
77 |
78 |
Apple Computer [Rob Janoff, 1977]
79 |
80 |
81 | To convert an image to text art, run:
82 |
83 | ```bash
84 | picharsso draw -c -H 32 gradient
85 | ```
86 |
87 | Here's what it should look like:
88 |
89 |
90 |

94 |
95 |
96 | > **Breakdown**
97 | >
98 | > | Argument | Effect |
99 | > | :--------: | :------------------------------------------------------------------------------------ |
100 | > | `-c` | Apply **image colors** to the output text. |
101 | > | `-H 32` | Sets the **number of lines** of the output text to `32`. |
102 | > | `gradient` | Use the [gradient style](https://kelvindecosta.github.io/picharsso/styles/gradient/). |
103 | >
104 | > Don't forget to replace ``.
105 |
106 | Refer to the [CLI documentation](https://kelvindecosta.github.io/picharsso/commands/) to learn about the various **commands** and **arguments**.
107 |
108 | ## Library
109 |
110 | The example from the previous section can be implemented in just a few lines of Python:
111 |
112 | ```python
113 | from PIL import Image
114 | from picharsso import new_drawer
115 |
116 | if __name__ == "__main__":
117 | # Open image
118 | image = Image.open("")
119 |
120 | # Define drawer
121 | drawer = new_drawer("braille", height=32, colorize=True)
122 |
123 | # Print drawer output
124 | print(drawer(image))
125 | ```
126 |
127 | Here's what it should look like:
128 |
129 |
130 |

134 |
135 |
136 | > **Styles**
137 | >
138 | > Refer to the [Styles documentation](https://kelvindecosta.github.io/picharsso/styles/) for an in-depth guide to the **image processing behind Picharsso**.
139 |
140 | Now consider this animated GIF:
141 |
142 |
143 |
144 |
145 |
146 |
Nyan Cat
147 |
148 |
149 | With some more lines of code, you can animate GIFs in text!
150 |
151 | ```python
152 | import time
153 |
154 | from PIL import Image
155 | from picharsso import new_drawer
156 | from picharsso.utils import clear_screen, terminal_size
157 |
158 |
159 | if __name__ == "__main__":
160 | # Open image
161 | image = Image.open("")
162 |
163 | # Get terminal height
164 | height, _ = terminal_size()
165 |
166 | # Define drawer
167 | drawer = new_drawer("braille", height=height, colorize=True, threshold=0)
168 |
169 | # Iterate over frames
170 | texts = []
171 | for frame_id in range(image.n_frames):
172 | # Select frame
173 | image.seek(frame_id)
174 |
175 | # Save output for frame
176 | texts.append(drawer(image))
177 |
178 | # Iterate over saved outputs in a circular manner
179 | num_frames = len(texts)
180 | counter = 0
181 | while True:
182 | # Refresh
183 | clear_screen()
184 |
185 | # Print output
186 | print(texts[counter])
187 |
188 | # Set a delay between frames
189 | time.sleep(1 / num_frames)
190 |
191 | # Circular increment
192 | counter = (counter + 1) % num_frames
193 | ```
194 |
195 | Here's what it should look like:
196 |
197 |
198 |

202 |
203 |
204 | Refer to the [API documentation](https://kelvindecosta.github.io/picharsso/library/draw/) to learn about the various **classes** and **functions**.
205 |
206 | > **Examples**
207 | >
208 | > Check out some more [examples](https://kelvindecosta.github.io/picharsso/examples/01-image/).
209 | >
210 | > You can use an image [directly from the web](https://kelvindecosta.github.io/picharsso/examples/03-web/) too!
211 |
212 | ## Contributing
213 |
214 | Do you have a feature request, bug report, or patch? Great!
215 | Check out the [contributing guidelines](https://github.com/kelvindecosta/picharsso/blob/master/CONTRIBUTING.md)!
216 |
217 | ## License
218 |
219 | Copyright (c) 2019 Kelvin DeCosta.
220 | Released under the MIT License.
221 | See [LICENSE](https://github.com/kelvindecosta/picharsso/blob/master/LICENSE) for details.
222 |
--------------------------------------------------------------------------------
/docs/assets/css/mkdocstrings.css:
--------------------------------------------------------------------------------
1 | div.doc-contents:not(.first) {
2 | padding-left: 25px;
3 | border-left: 4px solid rgba(230, 230, 230);
4 | margin-bottom: 80px;
5 | }
6 |
7 | h5.doc-heading {
8 | text-transform: none !important;
9 | }
10 |
11 | h6.hidden-toc {
12 | margin: 0 !important;
13 | position: relative;
14 | top: -70px;
15 | }
16 |
17 | h6.hidden-toc::before {
18 | margin-top: 0 !important;
19 | padding-top: 0 !important;
20 | }
21 |
22 | h6.hidden-toc a.headerlink {
23 | display: none;
24 | }
25 |
26 | td code {
27 | word-break: normal !important;
28 | }
29 |
30 | td p {
31 | margin-top: 0 !important;
32 | margin-bottom: 0 !important;
33 | }
34 |
--------------------------------------------------------------------------------
/docs/assets/images/diagrams/formats/overview/colorization.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/diagrams/formats/overview/colorization.webp
--------------------------------------------------------------------------------
/docs/assets/images/diagrams/styles/braille/processing.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/diagrams/styles/braille/processing.webp
--------------------------------------------------------------------------------
/docs/assets/images/diagrams/styles/gradient/processing.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/diagrams/styles/gradient/processing.webp
--------------------------------------------------------------------------------
/docs/assets/images/diagrams/styles/overview/processing.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/diagrams/styles/overview/processing.webp
--------------------------------------------------------------------------------
/docs/assets/images/diagrams/styles/overview/resizing.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/diagrams/styles/overview/resizing.webp
--------------------------------------------------------------------------------
/docs/assets/images/favicon.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/favicon.webp
--------------------------------------------------------------------------------
/docs/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/logo.png
--------------------------------------------------------------------------------
/docs/assets/images/logo.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/logo.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/demo/apple-braille.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/demo/apple-braille.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/demo/apple-gradient.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/demo/apple-gradient.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/dimensions/zima-h32.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/dimensions/zima-h32.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/dimensions/zima-term-h.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/dimensions/zima-term-h.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/dimensions/zima-term-w.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/dimensions/zima-term-w.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/dimensions/zima-w32.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/dimensions/zima-w32.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-bicubic.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-bicubic.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-bilinear.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-bilinear.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-box.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-box.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-hamming.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-hamming.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-lanczos.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-lanczos.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/resample/starry-night-resample-nearest.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/resample/starry-night-resample-nearest.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t0.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t108.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t108.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t168.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t168.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t210.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t210.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t70.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/braille/threshold/contributions-braille-t70.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-block.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-block.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-default.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-default.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-dot.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-dot.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-hash.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/charset/slack-gradient-charset-hash.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/negative/github-gradient-negative.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/negative/github-gradient-negative.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/draw/styles/gradient/negative/github-gradient-normal.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/draw/styles/gradient/negative/github-gradient-normal.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/examples/01-image/hackerman-gradient.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/examples/01-image/hackerman-gradient.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/examples/02-gif/nyan-braille.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/examples/02-gif/nyan-braille.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/examples/02-gif/nyan-gradient.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/examples/02-gif/nyan-gradient.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/format/colorize/instagram-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/format/colorize/instagram-color.webp
--------------------------------------------------------------------------------
/docs/assets/images/outputs/format/colorize/instagram-gray.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/outputs/format/colorize/instagram-gray.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/apple.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/apple.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/contributions.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/contributions.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/github.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/github.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/instagram.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/instagram.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/slack.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/slack.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/starry-night.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/starry-night.webp
--------------------------------------------------------------------------------
/docs/assets/images/subjects/zima.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/assets/images/subjects/zima.webp
--------------------------------------------------------------------------------
/docs/assets/js/config.js:
--------------------------------------------------------------------------------
1 | window.MathJax = {
2 | tex: {
3 | inlineMath: [["\\(", "\\)"]],
4 | displayMath: [["\\[", "\\]"]],
5 | processEscapes: true,
6 | processEnvironments: true,
7 | },
8 | options: {
9 | ignoreHtmlClass: ".*|",
10 | processHtmlClass: "arithmatex",
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/docs/commands/draw/braille.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso draw braille - CLI - Picharsso"
3 | description: "Use the Braille style."
4 | ---
5 |
6 | # `picharsso draw braille`
7 |
8 | *Use the [Braille style](../../styles/braille.md).*
9 |
10 | ??? example "Example"
11 | Consider the following image:
12 |
13 |
14 |
15 |
16 |
17 |
18 | Apple Computer [Rob Janoff, 1977]
19 |
20 |
21 |
22 | Here's what it should look like:
23 |
24 |
25 |

29 |
30 |
31 | ## Usage
32 |
33 | ```bash
34 | picharsso draw braille [options]
35 | ```
36 |
37 | ## Options
38 |
39 | ### `-t`, `--threshold` `INTEGER` `RANGE`
40 | : *Threshold pixel luminance (from grayscale). [default: 64]*
41 |
42 | ??? example
43 | Consider the following image:
44 |
45 |
46 |
47 |
48 |
49 |
50 | Tiles ressembling GitHub contributions
51 |
52 |
53 |
54 | ```bash
55 | picharsso draw -c -H 32 docs/assets/images/subjects/contributions.webp braille -t
56 | ```
57 |
58 | Here's what it should look like:
59 |
60 | === "threshold = 0"
61 |
62 |

66 |
67 |
68 | === "70"
69 |
70 |

74 |
75 |
76 | === "108"
77 |
78 |

82 |
83 |
84 | === "168"
85 |
86 |

90 |
91 |
92 | === "210"
93 |
94 |

98 |
99 |
100 | ### `-h`, `--help`
101 | : *Show this message and exit.*
102 |
103 | ??? abstract "Message"
104 | ```
105 | --8<-- "docs/snippets/cli/draw/braille/help.txt"
106 | ```
107 |
--------------------------------------------------------------------------------
/docs/commands/draw/gradient.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso draw gradient - CLI - Picharsso"
3 | description: "Use the gradient style."
4 | ---
5 |
6 | # `picharsso draw gradient`
7 |
8 | *Use the [gradient style](../../styles/gradient.md).*
9 |
10 | ??? example "Example"
11 | Consider the following image:
12 |
13 |
14 |
15 |
16 |
17 |
18 | Apple Computer [Rob Janoff, 1977]
19 |
20 |
21 |
22 | Here's what it should look like:
23 |
24 |
25 |

29 |
30 |
31 | ## Usage
32 |
33 | ```bash
34 | picharsso draw gradient [options]
35 | ```
36 |
37 | ## Options:
38 |
39 | ### `-s`, `--charset` `TEXT`
40 | : *Character set ordered by increasing 'brightness'. [default: :!?PG@]*
41 |
42 | ??? example
43 | Consider the following image:
44 |
45 |
46 |
47 |
48 |
49 |
50 | Slack
51 |
52 |
53 |
54 | ```bash
55 | picharsso draw -c -H 32 docs/assets/images/subjects/slack.webp gradient -s
56 | ```
57 |
58 | Here's what it should look like:
59 |
60 | === "charset = ' :!?PG@' (default)"
61 |
62 |

66 |
67 |
68 | === "'.'"
69 |
70 |

74 |
75 |
76 | === "'#'"
77 |
78 |

82 |
83 |
84 | === "'█'"
85 |
86 |

90 |
91 |
92 | ### `-n`, `--negative`
93 | : Whether to invert output text brightness.
94 |
95 | ??? example
96 | Consider the following image:
97 |
98 |
99 |
100 |
101 |
102 |
103 | GitHub
104 |
105 |
106 |
107 | ```bash
108 | picharsso draw -H 32 docs/assets/images/subjects/github.webp gradient [-n]
109 | ```
110 |
111 | Here's what it should look like:
112 |
113 | === "negative = False"
114 |
115 |

119 |
120 |
121 | === "True"
122 |
123 |

127 |
128 |
129 | ### `-h`, `--help`
130 | : *Show this message and exit.*
131 |
132 | ??? abstract "Message"
133 | ```
134 | --8<-- "docs/snippets/cli/draw/gradient/help.txt"
135 | ```
136 |
--------------------------------------------------------------------------------
/docs/commands/draw/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso draw - CLI - Picharsso"
3 | description: "Generate text art from an image."
4 | ---
5 |
6 | # `picharsso draw`
7 |
8 | *Generate text art from an image.*
9 |
10 | ## Usage
11 |
12 | ```
13 | picharsso draw [options] [args]
14 | ```
15 |
16 | ## Arguments
17 |
18 | ### ``
19 | : *Path to the image file.*
20 |
21 | ## Options
22 |
23 | ### `-c`, `--colorize`
24 | : *Apply image colors to output text.*
25 |
26 | ??? example
27 | Consider the following image:
28 |
29 |
30 |
31 |
32 |
33 |
34 | Instagram
35 |
36 |
37 |
38 | ```bash
39 | picharsso draw [-c] -H 32 docs/assets/images/subjects/instagram.webp gradient
40 | ```
41 |
42 | Here's what it should look like:
43 |
44 | === "colorize = False"
45 |
46 |

50 |
51 |
52 | === "True"
53 |
54 |

58 |
59 |
60 | ### `-m`, `--mode` [`ansi`|`html`]
61 | : *Format mode for output text. [default: ansi]*
62 |
63 | !!! question "Formats"
64 | Refer to the [Formats documentation](../../formats/index.md)
65 | to learn about the supported output formats.
66 |
67 | ### `-r`, `--resample` [`nearest`|`box`|`bilinear`|`hamming`|`bicubic`|`lanczos`]
68 | : *Resampling filter. [default: nearest]*
69 |
70 | ??? example
71 | Consider the following image:
72 |
73 |
74 |
75 |
76 |
77 |
78 | Starry Night [Vincent van Gogh, 1889]
79 |
80 |
81 |
82 | ```bash
83 | picharsso draw -c -term-h -r docs/assets/images/subjects/starry-night.webp gradient -s "█"
84 | ```
85 |
86 | Here's what it should look like:
87 |
88 | === "resample = 'nearest'"
89 |
90 |

94 |
95 |
96 | === "'box'"
97 |
98 |

102 |
103 |
104 | === "'bilinear'"
105 |
106 |

110 |
111 |
112 | === "'hamming'"
113 |
114 |

118 |
119 |
120 | === "'bicubic'"
121 |
122 |

126 |
127 |
128 | === "'lanczos'"
129 |
130 |

134 |
135 |
136 | ### `-H`, `--height` `INTEGER`
137 | : *Height of output text in characters.*
138 | *If 0, derives from width. [default: 0]*
139 |
140 | !!! info "Lines"
141 | `height` is the number of lines in the text output.
142 |
143 | ??? example
144 | Consider the following image:
145 |
146 |
147 |
148 |
149 |
150 |
151 | Zima Blue [Zima]
152 |
153 |
154 |
155 | ```bash
156 | picharsso draw -c -H 32 docs/assets/images/subjects/zima.webp gradient
157 | ```
158 |
159 | Here's what it should look like:
160 |
161 |
162 |

166 |
167 |
168 | ### `-W`, `--width` `INTEGER`
169 | : *Width of output text in characters.*
170 | *If 0, derives from height. [default: 0]*
171 |
172 | !!! info "Characters per line"
173 | `width` is the number of characters (including whitespace) per line in the text output.
174 |
175 | ??? example
176 | Consider the following image:
177 |
178 |
179 |
180 |
181 |
182 |
183 | Zima Blue [Zima]
184 |
185 |
186 |
187 | ```bash
188 | picharsso draw -c -W 32 docs/assets/images/subjects/zima.webp gradient
189 | ```
190 |
191 | Here's what it should look like:
192 |
193 |
194 |

198 |
199 |
200 | ### `-term-h`, `--terminal-height`
201 | : *Sets height to terminal height.*
202 |
203 | ??? example
204 | Consider the following image:
205 |
206 |
207 |
208 |
209 |
210 |
211 | Zima Blue [Zima]
212 |
213 |
214 |
215 | ```bash
216 | picharsso draw -c -term-h docs/assets/images/subjects/zima.webp gradient
217 | ```
218 |
219 | Here's what it should look like:
220 |
221 |
222 |

226 |
227 |
228 | ??? bug
229 | When used while [piping](https://en.wikipedia.org/wiki/Pipeline_(Unix)){target=_blank},
230 | `height` is set to the default terminal height,
231 | which is usually `24`.
232 |
233 | ### `-term-w`, `--terminal-width`
234 | : *Sets width to terminal width.*
235 |
236 | ??? example
237 | Consider the following image:
238 |
239 |
240 |
241 |
242 |
243 |
244 | Zima Blue [Zima]
245 |
246 |
247 |
248 | ```bash
249 | picharsso draw -c -term-w docs/assets/images/subjects/zima.webp gradient
250 | ```
251 |
252 | Here's what it should look like:
253 |
254 |
255 |

259 |
260 |
261 | ??? bug
262 | When used while [piping](https://en.wikipedia.org/wiki/Pipeline_(Unix)){target=_blank},
263 | `width` is set to the default terminal width,
264 | which is usually `80`.
265 |
266 | ### `-h`, `--help`
267 | : *Show this message and exit.*
268 |
269 | ??? abstract "Message"
270 | ```
271 | --8<-- "docs/snippets/cli/draw/help.txt"
272 | ```
273 |
274 | ## Subcommands
275 |
276 | !!! question "Styles"
277 | Refer to the [Styles documentation](../../styles/index.md)
278 | for an in-depth guide to the **image processing behind Picharsso**.
279 |
280 | ### [`braille`](braille.md)
281 | : Use the [Braille style](../../styles/braille.md).
282 |
283 | ### [`gradient`](gradient.md)
284 | : Use the [gradient style](../../styles/gradient.md).
285 |
286 |
--------------------------------------------------------------------------------
/docs/commands/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso - CLI - Picharsso"
3 | description: "A utility for converting images to text art."
4 | ---
5 |
6 | # `picharsso`
7 |
8 | *A utility for converting images to text art.*
9 |
10 | ## Usage
11 |
12 | ```bash
13 | picharsso [options] [args]
14 | ```
15 |
16 | ## Options
17 |
18 | ### `-h`, `--help`
19 | : *Show this message and exit.*
20 |
21 | ??? abstract "Message"
22 | ```
23 | --8<-- "docs/snippets/cli/help.txt"
24 | ```
25 |
26 | ## Subcommands
27 |
28 | ### [`draw`](draw/index.md)
29 | : *Generate text art from an image.*
30 |
31 | ### [`info`](info.md)
32 | : *Displays package information.*
33 |
--------------------------------------------------------------------------------
/docs/commands/info.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso info - CLI - Picharsso"
3 | description: "Displays package information."
4 | ---
5 |
6 | # `picharsso info`
7 |
8 | *Displays package information.*
9 |
10 | ## Usage
11 |
12 | ```bash
13 | picharsso info [options]
14 | ```
15 |
16 | ## Options
17 |
18 | ### `-h`, `--help`
19 | : *Show this message and exit.*
20 |
21 | ??? abstract "Message"
22 | ```
23 | --8<-- "docs/snippets/cli/info/help.txt"
24 | ```
25 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Contributing - Picharsso"
3 | description: "Contributing Guidelines"
4 | ---
5 |
6 | --8<-- "CONTRIBUTING.md"
7 |
--------------------------------------------------------------------------------
/docs/examples/01-image/hackerman.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/examples/01-image/hackerman.webp
--------------------------------------------------------------------------------
/docs/examples/01-image/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Image - Examples - Picharsso"
3 | description: "This example illustrates how to covert an image to text art."
4 | ---
5 |
6 | # Image
7 |
8 | This example illustrates how to covert an image to text art.
9 |
10 | !!! abstract "Source"
11 | ```python linenums="1"
12 | --8<-- "docs/examples/01-image/main.py"
13 | ```
14 |
15 | ??? success "Result"
16 | Consider the following image:
17 |
18 |
19 |
20 |
21 |
22 |
23 | Elliot Anderson is Hackerman [u/JBisBlu]
24 |
25 |
26 |
27 | The output of the above script should look like this:
28 |
29 |
30 |

34 |
35 |
36 |
--------------------------------------------------------------------------------
/docs/examples/01-image/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 name> -*-
3 |
4 | """This script converts an image to text art."""
5 |
6 | from pathlib import Path
7 |
8 | from PIL import Image
9 | from picharsso import new_drawer
10 | from picharsso.utils import terminal_size
11 |
12 | if __name__ == "__main__":
13 | # Choose image
14 | # image_path = ""
15 | image_path = Path(__file__).parent / "hackerman.webp"
16 |
17 | # Open image
18 | image = Image.open(image_path)
19 |
20 | # Choose an art style
21 | style = "gradient" # or "braille"
22 |
23 | # Set height
24 | height, _ = terminal_size()
25 |
26 | # Define drawer
27 | drawer = new_drawer(style, height=height, colorize=True)
28 |
29 | # Print drawer output
30 | print(drawer(image))
31 |
--------------------------------------------------------------------------------
/docs/examples/02-gif/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "GIF - Examples - Picharsso"
3 | description: "This example illustrates how to animate a GIF image in text art."
4 | ---
5 |
6 | # GIF
7 |
8 | This example illustrates how to animate a GIF image in text art.
9 |
10 | !!! abstract "Source"
11 | ```python linenums="1"
12 | --8<-- "docs/examples/02-gif/main.py"
13 | ```
14 |
15 | ??? success "Result"
16 | Consider the following image:
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Nyan Cat
25 |
26 |
27 |
28 | The output of the above script should look like this:
29 |
30 |
31 |
32 |

36 |
37 |
--------------------------------------------------------------------------------
/docs/examples/02-gif/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 name> -*-
3 |
4 | """This script animates a GIF image in text art."""
5 |
6 | from pathlib import Path
7 | import time
8 |
9 | from PIL import Image
10 | from picharsso import new_drawer
11 | from picharsso.utils import clear_screen, terminal_size
12 |
13 |
14 | if __name__ == "__main__":
15 | # Choose image
16 | # image_path = ""
17 | image_path = Path(__file__).parent / ("nyan.webp")
18 |
19 | # Open image
20 | image = Image.open(image_path)
21 |
22 | # Get terminal height
23 | height, _ = terminal_size()
24 |
25 | # Choose an art style
26 | style = "gradient" # or "braille"
27 |
28 | # Define drawer
29 | drawer = new_drawer(style, height=height, colorize=True)
30 |
31 | # Iterate over frames
32 | texts = []
33 | for frame_id in range(image.n_frames):
34 | # Select frame
35 | image.seek(frame_id)
36 |
37 | # Save output for frame
38 | texts.append(drawer(image))
39 |
40 | # Iterate over saved outputs in a circular manner
41 | num_frames = len(texts)
42 | counter = 0
43 | while True:
44 | # Refresh
45 | clear_screen()
46 |
47 | # Print output
48 | print(texts[counter])
49 |
50 | # Set a delay between frames
51 | time.sleep(1 / num_frames)
52 |
53 | # Circular increment
54 | counter = (counter + 1) % num_frames
55 |
--------------------------------------------------------------------------------
/docs/examples/02-gif/nyan.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kelvindecosta/picharsso/2e73095c7cb230174bbf5a0242b65247f9ab08ad/docs/examples/02-gif/nyan.webp
--------------------------------------------------------------------------------
/docs/examples/03-web/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Web - Examples - Picharsso"
3 | description: "This example illustrates how to animate a GIF image, from the web, in text art."
4 | ---
5 |
6 | # Web
7 |
8 | This example illustrates how to animate a GIF image, from the web, in text art.
9 |
10 | ??? tip "Try it yourself!"
11 | *¡Apagando las luces!*
12 |
13 | !!! abstract "Source"
14 | ```python linenums="1"
15 | --8<-- "docs/examples/03-web/main.py"
16 | ```
17 |
18 | !!! note
19 | Although this example uses an animated GIF as input,
20 | the same principle can be applied to static images from the web.
21 |
22 | !!! warning
23 | This example requires the [`requests` library](https://requests.readthedocs.io/en/master/){target=_blank}.
24 |
--------------------------------------------------------------------------------
/docs/examples/03-web/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 name> -*-
3 |
4 | """This script animates a GIF image, from the web, in text art."""
5 |
6 | from io import BytesIO
7 | import time
8 |
9 | from PIL import Image
10 | from picharsso import new_drawer
11 | from picharsso.utils import clear_screen, terminal_size
12 |
13 | import requests
14 |
15 |
16 | if __name__ == "__main__":
17 | # Set URL of image
18 | image_url = "https://bit.ly/3hs2Vxr"
19 |
20 | # Open Image from respose content
21 | response = requests.get(image_url)
22 | image = Image.open(BytesIO(response.content))
23 |
24 | # Get terminal height
25 | height, _ = terminal_size()
26 |
27 | # Choose an art style
28 | style = "gradient" # or "braille"
29 |
30 | # Define drawer
31 | drawer = new_drawer(style, height=height, colorize=True)
32 |
33 | # Iterate over frames
34 | texts = []
35 | for frame_id in range(image.n_frames):
36 | # Select frame
37 | image.seek(frame_id)
38 |
39 | # Save output for frame
40 | texts.append(drawer(image))
41 |
42 | # Iterate over saved outputs in a circular manner
43 | num_frames = len(texts)
44 | counter = 0
45 | while True:
46 | # Refresh
47 | clear_screen()
48 |
49 | # Print output
50 | print(texts[counter])
51 |
52 | # Set a delay between frames
53 | time.sleep(1 / num_frames)
54 |
55 | # Circular increment
56 | counter = (counter + 1) % num_frames
57 |
--------------------------------------------------------------------------------
/docs/formats/ansi.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "ANSI - Formats - Picharsso"
3 | description: "The ANSI format"
4 | ---
5 |
6 | # ANSI
7 |
8 | This format supports [ANSI Escape Codes](https://en.wikipedia.org/wiki/ANSI_escape_code){target=_blank}.
9 |
10 | !!! info "Default"
11 | Since it can be used to create **plain text documents**,
12 | this format is chosen as the **default**.
13 |
14 | ## Procedure
15 |
16 | This format is implemented by the [`AnsiFormatter`][picharsso.format.ansi.AnsiFormatter].
17 |
18 | !!! question "Formatting"
19 | Refer to the [procedure](./index.md#procedure) outlined in the Formats documentation
20 | for an overview of the **steps common to all formats**.
21 |
22 | ### Translation
23 |
24 | This format doesn't require any translation.
25 |
26 | ??? abstract "Source"
27 | Refer to the [`translate` function][picharsso.format.ansi.AnsiFormatter.translate]
28 | for more information.
29 |
30 | ### Colorization
31 |
32 | Using the [`sty` Python library](https://sty.mewo.dev/){target=_blank},
33 | color is applied to the elements of the `text_matrix`.
34 |
35 | ??? abstract "Source"
36 | Refer to the [`color` function][picharsso.format.ansi.AnsiFormatter.color]
37 | for more information.
38 |
39 | ### Unification
40 |
41 | Elements of each row of the `text_matrix` are joined to form
42 | lines, which are further joined to form one huge string of text.
43 |
44 | ??? abstract "Source"
45 | Refer to the [`unify` function][picharsso.format.ansi.AnsiFormatter.unify]
46 | for more information.
47 |
--------------------------------------------------------------------------------
/docs/formats/html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "HTML - Formats - Picharsso"
3 | description: "The HTML format"
4 | ---
5 |
6 | # HTML
7 |
8 | This format supports [HTML](https://en.wikipedia.org/wiki/HTML){target=_blank}.
9 |
10 | ## Procedure
11 |
12 | This format is implemented by the [`HtmlFormatter`][picharsso.format.html.HtmlFormatter].
13 |
14 | !!! question "Formatting"
15 | Refer to the [procedure](./index.md#procedure) outlined in the Formats documentation
16 | for an overview of the **steps common to all formats**.
17 |
18 | ### Translation
19 |
20 | This format requires some characters to be translated
21 | to their equivalent [HTML character entities](https://html.spec.whatwg.org/multipage/named-characters.html#named-character-references){target=_blank}.
22 |
23 | ??? abstract "Source"
24 | Refer to the [`translate` function][picharsso.format.html.HtmlFormatter.translate]
25 | for more information.
26 |
27 | ### Colorization
28 |
29 | Color is applied to each element in the `text_matrix` by
30 | wrapping it in a styled `` element.
31 |
32 | ??? abstract "Source"
33 | Refer to the [`color` function][picharsso.format.html.HtmlFormatter.color]
34 | for more information.
35 |
36 | ### Unification
37 |
38 | Elements of each row of the `text_matrix` are joined to form
39 | lines.
40 | All lines are wrapped in a `` elemen each.
41 | The entire text output is wrapped in a `
` element.
42 |
43 | ??? abstract "Source"
44 | Refer to the [`unify` function][picharsso.format.html.HtmlFormatter.unify]
45 | for more information.
46 |
--------------------------------------------------------------------------------
/docs/formats/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Formats - Picharsso"
3 | description: "An overview of the output formats of Picharsso"
4 | ---
5 |
6 | # Formats
7 |
8 | After an `image` is coverted to a `text_matrix`,
9 | it must be formatted before it can be output.
10 |
11 | ## Procedure
12 |
13 | There are steps involved in this process that are common to
14 | all `formatters`.
15 | Picharsso defines a [`BaseFormatter`][picharsso.format.base.BaseFormatter]
16 | that abstracts this general procedure.
17 |
18 | ### Initialization
19 |
20 | This step assigns values to the parameters for the algorithms.
21 |
22 | #### Color
23 |
24 | The `colorize` parameter controls whether the output text must include the colors from the image.
25 |
26 | Consider the following image:
27 |
28 |
29 |
30 |
31 |
32 |
33 | Instagram
34 |
35 |
36 |
37 | Here's what it should look like:
38 |
39 | === "colorize = False"
40 |
41 |

45 |
46 |
47 | === "True"
48 |
49 |

53 |
54 |
55 | #### Vectorization
56 |
57 | The `vcolor` attribute is a vectorized version of the `color` method.
58 |
59 | ### Translation
60 |
61 | The elements of the `text_matrix` are encoded in the Unicode standard.
62 |
63 | Depending on the output format, these characters must be translated accordingly.
64 |
65 | ??? abstract "Source"
66 | Refer to the [`translate` function][picharsso.format.base.BaseFormatter.translate] for more information.
67 |
68 | ### Colorization
69 |
70 | Colors are pooled from the original `image` by resizing it to the dimensions of the output text.
71 | This ensures that each character has a unique pixel, and thus, a unique color.
72 |
73 | With the vectorized `color` method, `vcolor`, the elements of the `text_matrix`
74 | are transformed into strings of text that represent
75 | the original character as well as its color.
76 |
77 |
78 |

79 |
80 |
81 | ??? abstract "Source"
82 | Refer to the [`color` function][picharsso.format.base.BaseFormatter.color] for more information.
83 |
84 | ### Unification
85 |
86 | Finally, the `text_matrix` is unified into a single string of text.
87 | This text, when viewed through a means supporting the particular format,
88 | should look like the original image.
89 |
90 | ??? abstract "Source"
91 | Refer to the [`unify` function][picharsso.format.base.BaseFormatter.unify] for more information.
92 |
93 | ## Varities
94 |
95 | All the following formats are implemented by a `formatter`
96 | which inherits from the [`BaseFormatter`][picharsso.format.base.BaseFormatter].
97 |
98 | ### ANSI
99 | : The [ANSI format](ansi.md) is implemented by the [`AnsiFormater`][picharsso.format.ansi.AnsiFormatter].
100 |
101 | ### HTML
102 | : The [HTML format](html.md) is implemented by the [`HtmlFormater`][picharsso.format.html.HtmlFormatter].
103 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Picharsso
2 |
3 |
4 |
5 |
6 |
7 |
8 | A utility for converting images to text art.
9 |
10 |
11 |
12 | ## Installation
13 |
14 | Run the following command:
15 |
16 | ```bash
17 | pip install picharsso
18 | ```
19 |
20 | This will:
21 |
22 | * download and install the [`picharsso` Python package](https://pypi.org/project/picharsso/){target=_blank}
23 | (along with its dependencies).
24 | * create an executable, `picharsso`, for the CLI (command line interface).
25 |
26 | ??? success "Verification"
27 | To verify that Picharsso is installed, run:
28 |
29 | ```bash
30 | python -c "import picharsso"
31 | ```
32 |
33 | ## Commands (CLI)
34 |
35 | Picharsso ships with a CLI that provides some basic functionality from the terminal.
36 |
37 | ??? question "Usage"
38 | Run the following command to display a helpful message:
39 |
40 | ```bash
41 | picharsso -h
42 | ```
43 |
44 | ```
45 | --8<-- "docs/snippets/cli/help.txt"
46 | ```
47 |
48 | Consider the following image:
49 |
50 |
51 |
52 |
53 |
54 |
55 | Apple Computer [Rob Janoff, 1977]
56 |
57 |
58 |
59 | To convert an image to text art, run:
60 |
61 | === "Braille"
62 | ```bash
63 | picharsso draw -c -H 32
braille
64 | ```
65 |
66 | Here's what it should look like:
67 |
68 |
69 |

73 |
74 |
75 | !!! abstract "Breakdown"
76 | | Argument | Effect |
77 | | :-------: | :------------------------------------------------------- |
78 | | `-c` | Apply **image colors** to the output text. |
79 | | `-H 32` | Sets the **number of lines** of the output text to `32`. |
80 | | `braille` | Use the [Braille style](styles/braille.md). |
81 |
82 | === "Gradient"
83 | ```bash
84 | picharsso draw -c -H 32 gradient
85 | ```
86 |
87 | Here's what it should look like:
88 |
89 |
90 |

94 |
95 |
96 | !!! abstract "Breakdown"
97 | | Argument | Effect |
98 | | :--------: | :------------------------------------------------------- |
99 | | `-c` | Apply **image colors** to the output text. |
100 | | `-H 32` | Sets the **number of lines** of the output text to `32`. |
101 | | `gradient` | Use the [gradient style](styles/gradient.md). |
102 |
103 | !!! warning
104 | Don't forget to replace ``.
105 |
106 | !!! question "CLI"
107 | Refer to the [CLI documentation](commands/index.md)
108 | to learn about the various **commands** and **arguments**.
109 |
110 | ## Library (API)
111 |
112 | The example from the previous section can be implemented in just a few lines of Python:
113 |
114 | === "Braille"
115 | ```python linenums="1" hl_lines="8-12"
116 | from PIL import Image
117 | from picharsso import new_drawer
118 |
119 | if __name__ == "__main__":
120 | # Open image
121 | image = Image.open("")
122 |
123 | # Define drawer
124 | drawer = new_drawer("braille", height=32, colorize=True)
125 |
126 | # Print drawer output
127 | print(drawer(image))
128 | ```
129 |
130 | === "Gradient"
131 | ```python linenums="1" hl_lines="8-12"
132 | from PIL import Image
133 | from picharsso import new_drawer
134 |
135 | if __name__ == "__main__":
136 | # Open image
137 | image = Image.open("")
138 |
139 | # Define drawer
140 | drawer = new_drawer("gradient", height=32, colorize=True)
141 |
142 | # Print drawer output
143 | print(drawer(image))
144 | ```
145 |
146 | !!! info "Pillow"
147 | Picharsso integrates well with [Pillow](https://python-pillow.org/){target=_blank},
148 | the friendly PIL fork.
149 |
150 | !!! question "Styles"
151 | Refer to the [Styles documentation](styles/index.md)
152 | for an in-depth guide to the **image processing behind Picharsso**.
153 |
154 | Now consider this animated GIF:
155 |
156 |
157 |
158 |
159 |
160 |
161 | Nyan Cat
162 |
163 |
164 |
165 | With some more lines of code, you can animate GIFs in text!
166 |
167 | === "Braille"
168 | ```python linenums="1" hl_lines="15-16 24-25"
169 | import time
170 |
171 | from PIL import Image
172 | from picharsso import new_drawer
173 | from picharsso.utils import clear_screen, terminal_size
174 |
175 |
176 | if __name__ == "__main__":
177 | # Open image
178 | image = Image.open("")
179 |
180 | # Get terminal height
181 | height, _ = terminal_size()
182 |
183 | # Define drawer
184 | drawer = new_drawer("braille", height=height, colorize=True, threshold=0)
185 |
186 | # Iterate over frames
187 | texts = []
188 | for frame_id in range(image.n_frames):
189 | # Select frame
190 | image.seek(frame_id)
191 |
192 | # Save output for frame
193 | texts.append(drawer(image))
194 |
195 | # Iterate over saved outputs in a circular manner
196 | num_frames = len(texts)
197 | counter = 0
198 | while True:
199 | # Refresh
200 | clear_screen()
201 |
202 | # Print output
203 | print(texts[counter])
204 |
205 | # Set a delay between frames
206 | time.sleep(1 / num_frames)
207 |
208 | # Circular increment
209 | counter = (counter + 1) % num_frames
210 | ```
211 |
212 | Here's what it should look like:
213 |
214 |
215 |

219 |
220 |
221 | === "Gradient"
222 | ```python linenums="1" hl_lines="15-16 24-25"
223 | import time
224 |
225 | from PIL import Image
226 | from picharsso import new_drawer
227 | from picharsso.utils import clear_screen, terminal_size
228 |
229 |
230 | if __name__ == "__main__":
231 | # Open image
232 | image = Image.open("")
233 |
234 | # Get terminal height
235 | height, _ = terminal_size()
236 |
237 | # Define drawer
238 | drawer = new_drawer("gradient", height=height, colorize=True)
239 |
240 | # Iterate over frames
241 | texts = []
242 | for frame_id in range(image.n_frames):
243 | # Select frame
244 | image.seek(frame_id)
245 |
246 | # Save output for frame
247 | texts.append(drawer(image))
248 |
249 | # Iterate over saved outputs in a circular manner
250 | num_frames = len(texts)
251 | counter = 0
252 | while True:
253 | # Refresh
254 | clear_screen()
255 |
256 | # Print output
257 | print(texts[counter])
258 |
259 | # Set a delay between frames
260 | time.sleep(1 / num_frames)
261 |
262 | # Circular increment
263 | counter = (counter + 1) % num_frames
264 | ```
265 |
266 | Here's what it should look like:
267 |
268 |
269 |

273 |
274 |
275 | !!! question "API"
276 | Refer to the [API documentation](library/draw/index.md)
277 | to learn about the various **classes** and **functions**.
278 |
279 | !!! tip "Examples"
280 | Check out some more [examples](examples/01-image/index.md).
281 |
282 | You can use an image [directly from the web](examples/03-web/index.md) too!
283 |
--------------------------------------------------------------------------------
/docs/library/draw/base.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.draw.base - API - Picharsso"
3 | description: "This module defines an abstract base formatter."
4 | ---
5 |
6 | # `base`
7 |
8 | ::: picharsso.draw.base
9 |
--------------------------------------------------------------------------------
/docs/library/draw/braille.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.draw.braille - API - Picharsso"
3 | description: "This module defines a drawer for Braille style."
4 | ---
5 |
6 | # `braille`
7 |
8 | ::: picharsso.draw.braille
9 |
--------------------------------------------------------------------------------
/docs/library/draw/gradient.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.draw.gradient - API - Picharsso"
3 | description: "This module defines a drawer for gradient style."
4 | ---
5 |
6 | # `gradient`
7 |
8 | ::: picharsso.draw.gradient
9 |
--------------------------------------------------------------------------------
/docs/library/draw/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.draw - API - Picharsso"
3 | description: "This package defines drawers for different styles of text art."
4 | ---
5 |
6 | # `draw`
7 |
8 | ::: picharsso.draw.__init__
9 |
--------------------------------------------------------------------------------
/docs/library/format/ansi.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.format.ansi - API - Picharsso"
3 | description: "This module defines a formatter for the ANSI coloring scheme."
4 | ---
5 |
6 | # `ansi`
7 |
8 | ::: picharsso.format.ansi
9 |
--------------------------------------------------------------------------------
/docs/library/format/base.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.format.base - API - Picharsso"
3 | description: "This module defines an abstract base formatter."
4 | ---
5 |
6 | # `base`
7 |
8 | ::: picharsso.format.base
9 |
--------------------------------------------------------------------------------
/docs/library/format/html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.format.html - API - Picharsso"
3 | description: "This module defines a formatter for HTML."
4 | ---
5 |
6 | # `html`
7 |
8 | ::: picharsso.format.html
9 |
--------------------------------------------------------------------------------
/docs/library/format/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.format - API - Picharsso"
3 | description: "This package defines formatters for different modes of text output."
4 | ---
5 |
6 | # `format`
7 |
8 | ::: picharsso.format.__init__
9 |
--------------------------------------------------------------------------------
/docs/library/meta.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.meta - API - Picharsso"
3 | description: "This module defines variables for the package metadata."
4 | ---
5 |
6 | # `meta`
7 |
8 | ::: picharsso.meta
9 |
--------------------------------------------------------------------------------
/docs/library/utils.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "picharsso.utils - API - Picharsso"
3 | description: "This module defines utility functions that are used across the package."
4 | ---
5 |
6 | # `utils`
7 |
8 | ::: picharsso.utils
9 |
--------------------------------------------------------------------------------
/docs/license.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "License - Picharsso"
3 | description: "Package License"
4 | ---
5 |
6 | # License
7 |
8 | ```
9 | --8<-- "LICENSE"
10 | ```
--------------------------------------------------------------------------------
/docs/overrides/main.html:
--------------------------------------------------------------------------------
1 | {#-
2 | This file was automatically generated - do not edit
3 | -#}
4 | {% extends "base.html" %}
5 | {% block extrahead %}
6 | {% set image = config.site_url ~ config.extra.site_image %}
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | {% endblock %}
23 |
--------------------------------------------------------------------------------
/docs/overrides/partials/footer.html:
--------------------------------------------------------------------------------
1 | {% import "partials/language.html" as lang with context %}
2 |
3 |
4 |
28 |
--------------------------------------------------------------------------------
/docs/snippets/cli/draw/braille/help.txt:
--------------------------------------------------------------------------------
1 | Usage: picharsso draw braille [options]
2 |
3 | Use the Braille style.
4 |
5 | Options:
6 | -t, --threshold INTEGER RANGE Threshold pixel luminance (from grayscale).
7 | [default: 64]
8 |
9 | -h, --help Show this message and exit.
10 |
--------------------------------------------------------------------------------
/docs/snippets/cli/draw/gradient/help.txt:
--------------------------------------------------------------------------------
1 | Usage: picharsso draw gradient [options]
2 |
3 | Use the gradient style.
4 |
5 | Options:
6 | -s, --charset TEXT Character set ordered by increasing 'brightness'.
7 | [default: :!?PG@]
8 |
9 | -n, --negative Whether to invert output text brightness.
10 | -h, --help Show this message and exit.
11 |
--------------------------------------------------------------------------------
/docs/snippets/cli/draw/help.txt:
--------------------------------------------------------------------------------
1 | Usage: picharsso draw [options] [args]
2 |
3 | Generate text art from an image.
4 |
5 | Path to the image file.
6 |
7 | Options:
8 | -c, --colorize Apply image colors to output text.
9 | -m, --mode [ansi|html] Format mode for output text. [default:
10 | ansi]
11 |
12 | -r, --resample [nearest|box|bilinear|hamming|bicubic|lanczos]
13 | Resampling filter. [default: nearest]
14 | -H, --height INTEGER Height of output text in characters.
15 |
16 | If 0, derives from width. [default: 0]
17 |
18 | -W, --width INTEGER Width of output text in characters.
19 |
20 | If 0, derives from height. [default: 0]
21 |
22 | -term-h, --terminal-height Sets height to terminal height.
23 | -term-w, --terminal-width Sets width to terminal width.
24 | -h, --help Show this message and exit.
25 |
26 | Commands:
27 | braille Use the Braille style.
28 | gradient Use the gradient style.
29 |
--------------------------------------------------------------------------------
/docs/snippets/cli/help.txt:
--------------------------------------------------------------------------------
1 | Usage: picharsso [options] [args]
2 |
3 | A utility for converting images to text art.
4 |
5 | Options:
6 | -h, --help Show this message and exit.
7 |
8 | Commands:
9 | draw Generate text art from an image.
10 | info Displays package information.
11 |
--------------------------------------------------------------------------------
/docs/snippets/cli/info/help.txt:
--------------------------------------------------------------------------------
1 | Usage: picharsso info [options]
2 |
3 | Displays package information.
4 |
5 | Options:
6 | -h, --help Show this message and exit.
7 |
--------------------------------------------------------------------------------
/docs/styles/braille.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Braille - Styles - Picharsso"
3 | description: "The Braille based text art style"
4 | ---
5 |
6 | # Braille
7 |
8 | This style uses the characters of the [Braille writing system](https://en.wikipedia.org/wiki/Braille){target=_blank}.
9 |
10 | ??? example "Example"
11 | Consider the following image:
12 |
13 |
14 |
15 |
16 |
17 |
18 | Apple Computer [Rob Janoff, 1977]
19 |
20 |
21 |
22 | Here's what it should look like:
23 |
24 |
25 |

29 |
30 |
31 | !!! info "Encoding"
32 | Traditional Braille characters are made up of `6` dots (⠿).
33 | Since each dot could be in one of `2` states (raised or lowered),
34 | there are a total of `64` unique combinations.
35 |
36 | In [Unicode](https://en.wikipedia.org/wiki/Unicode){target=_blank}, braille is represented in a block,
37 | the [Braille Patterns](https://en.wikipedia.org/wiki/Braille_Patterns){target=_blank}.
38 | There are `256` unique characters each in its own 8-dot cell (⣿).
39 |
40 | ## Procedure
41 |
42 | This style is implemented using the [`BrailleDrawer`][picharsso.draw.braille.BrailleDrawer].
43 |
44 | !!! question "Styling"
45 | Refer to the [procedure](./index.md#procedure) outlined in the Styles documentation
46 | for an overview of the **steps common to all styles**.
47 |
48 | ### Initialization
49 |
50 | #### Threshold
51 |
52 | The `threshold` parameter **filters out pixels** of the input image
53 | whose **grayscale intensities are lesser** than it.
54 |
55 | Consider the following image:
56 |
57 |
58 |
59 |
60 |
61 |
62 | Tiles ressembling GitHub contributions
63 |
64 |
65 |
66 | Here's what it should look like:
67 |
68 | === "threshold = 0"
69 |
70 |

74 |
75 |
76 | === "70"
77 |
78 |

82 |
83 |
84 | === "108"
85 |
86 |

90 |
91 |
92 | === "168"
93 |
94 |

98 |
99 |
100 | === "210"
101 |
102 |

106 |
107 |
108 | #### Matrices
109 |
110 | The `kernel` attribute holds a NumPy [`ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html){target=_blank}
111 | containing the following matrix:
112 |
113 | $$
114 | kernel =
115 | \begin{bmatrix}
116 | 1 & 8\\
117 | 2 & 16\\
118 | 4 & 32\\
119 | 64 & 128\end{bmatrix}
120 | $$
121 |
122 | The Unicode encoding of the 8-dot cell Braille system
123 | is done by assigning each of the dots a power of `2`.
124 | Each character in the Braille Patterns block has a unique Unicode value
125 | that is obtained by summing these powers.
126 |
127 | The `charset_array` attribute holds another NumPy [`ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html){target=_blank}
128 | containing all 256 Braille characters.
129 |
130 | ### Conversion
131 |
132 | #### Resizing
133 |
134 | Assuming the output text should have the dimensions `text_height` and `text_width`,
135 | the image must be resized according to the following criteria:
136 |
137 | * `image_height = 4 * text_height`.
138 | * `image_width = 2 * text_width`.
139 | * If either `image_height` or `image_width` is `0`,
140 | it is derived from the other by preserving the aspect ratio of the original image.
141 |
142 | Following the above algorithm, **each pixel** of the resized `image`
143 | will be **assigned to one dot** (Braille character dot) in the output text.
144 |
145 | ??? abstract "Source"
146 | Refer to the [`calculate_size` function][picharsso.draw.braille.BrailleDrawer.calculate_size]
147 | for more information.
148 |
149 | #### Processing
150 |
151 | 1. The resized `image` is first converted to its grayscale.
152 | 2. Each pixel is set to either `0` or `1` based on whether
153 | its grayscale intensity is below or above the `threshold`.
154 | 3. A convolution operation is performed on this filtered image
155 | using the `kernel` matrix.
156 | The resultant matrix has the ofsetted Unicode values for
157 | the corresponding Braille character.
158 | 4. The `charset_array` is indexed with the resultant "indices" matrix,
159 | giving the final `text_matrix`.
160 |
161 |
162 |

163 |
164 |
165 | ??? abstract "Source"
166 | Refer to the [`process` function][picharsso.draw.braille.BrailleDrawer.process]
167 | for more information.
168 |
--------------------------------------------------------------------------------
/docs/styles/gradient.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Gradient - Styles - Picharsso"
3 | description: "The gradient based text art style"
4 | ---
5 |
6 | # Gradient
7 |
8 | This style uses [Unicode characters](https://en.wikipedia.org/wiki/Unicode){target=_blank}.
9 |
10 | ??? example "Example"
11 | Consider the following image:
12 |
13 |
14 |
15 |
16 |
17 |
18 | Apple Computer [Rob Janoff, 1977]
19 |
20 |
21 |
22 | Here's what it should look like:
23 |
24 |
25 |

29 |
30 |
31 | ## Procedure
32 |
33 | This style is implemented using the [`GradientDrawer`][picharsso.draw.gradient.GradientDrawer].
34 |
35 | !!! question "Styling"
36 | Refer to the [procedure](./index.md#procedure) outlined in the Styles documentation
37 | for an overview of the **steps common to all styles**.
38 |
39 | ### Initialization
40 |
41 | #### Charset
42 |
43 | The `charset` parameter is a string containing characters **ordered by their
44 | perceived brightness**.
45 |
46 | Consider the following image:
47 |
48 |
49 |
50 |
51 |
52 |
53 | Slack
54 |
55 |
56 |
57 | Here's what it should look like:
58 |
59 | === "charset = ' :!?PG@' (default)"
60 |
61 |

65 |
66 |
67 | === "'.'"
68 |
69 |

73 |
74 |
75 | === "'#'"
76 |
77 |

81 |
82 |
83 | === "'█'"
84 |
85 |

89 |
90 |
91 | #### Negative
92 |
93 | The `negative` parameter controls whether the `charset` must be **reversed**.
94 |
95 | Consider the following image:
96 |
97 |
98 |
99 |
100 |
101 |
102 | GitHub
103 |
104 |
105 |
106 | Here's what it should look like:
107 |
108 | === "negative = False"
109 |
110 |

114 |
115 |
116 | === "True"
117 |
118 |

122 |
123 |
124 | #### Matrices
125 |
126 | The `charset_array` attribute holds a NumPy [`ndarray`](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html){target=_blank}
127 | containing all the characters in the `charset`.
128 |
129 | ### Conversion
130 |
131 | #### Resizing
132 |
133 | Assuming the output text should have the dimensions `text_height` and `text_width`,
134 | the image must be resized according to the following criteria:
135 |
136 | * `image_height = text_height`.
137 | * `image_width = text_width`.
138 | * If either `image_height` or `image_width` is `0`,
139 | it is derived from the other by preserving the aspect ratio of the original image.
140 |
141 | Following the above algorithm, **each pixel** of the resized `image`
142 | will be assigned to **one character** in the output text.
143 |
144 | ??? abstract "Source"
145 | Refer to the [`calculate_size` function][picharsso.draw.gradient.GradientDrawer.calculate_size]
146 | for more information.
147 |
148 | #### Processing
149 |
150 | 1. The resized `image` is first converted to its grayscale.
151 | 2. The image matrix is normalized such that the grayscale range shifts from `(0, 255)` to `(0, len(charset))`.
152 | 3. The `charset_array` is indexed with the resultant "indices" matrix,
153 | giving the final `text_matrix`.
154 |
155 |
156 |

157 |
158 |
159 | ??? abstract "Source"
160 | Refer to the [`process` function][picharsso.draw.gradient.GradientDrawer.process]
161 | for more information.
162 |
--------------------------------------------------------------------------------
/docs/styles/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Styles - Picharsso"
3 | description: "An overview of the styles of Picharsso"
4 | ---
5 |
6 | # Styles
7 |
8 | Styles refer to the different image processing algorithms
9 | that are performed on input images.
10 | **They affect how images look when viewed in the text form**.
11 |
12 | ## Procedure
13 |
14 | Although the different styles use algorithms that produce different results,
15 | there are many *common*, yet fundamental, steps involved in the entire process.
16 | Picharsso defines a [`BaseDrawer`][picharsso.draw.base.BaseDrawer]
17 | that abstracts this general procedure.
18 |
19 | ### Initialization
20 |
21 | This step **assigns values to the parameters** for the algorithms.
22 |
23 | #### Dimensions
24 |
25 | Picharsso provides control over the **dimensions of the output text**
26 | with the `height` and `width` parameters.
27 |
28 | Consider the following image:
29 |
30 |
31 |
32 |
33 |
34 |
35 | Zima Blue [Zima]
36 |
37 |
38 |
39 | Here's what it should look like:
40 |
41 | === "height = 32"
42 |
43 |

47 |
48 |
49 | === "terminal height"
50 |
51 |

55 |
56 |
57 | === "width = 32"
58 |
59 |

63 |
64 |
65 | === "terminal width"
66 |
67 |

71 |
72 |
73 | !!! info "Preserving Aspect Ratio"
74 | The relationship between `height` and `width` preserves the aspect ratio of the input image.
75 |
76 | *When either one of the dimensions is set as `0`, it derives its value from the other.*
77 |
78 | ??? error
79 | Assigning `0` to both `height` and `width` raises an error.
80 | Atleast one of the dimensions must be assigned a non-zero positive integer.
81 |
82 | #### Resampling Filter
83 |
84 | There are instances when an input image must be **scaled to an appropriate size**
85 | before it can be used as input for an algorithm.
86 | During this resizing process, pixels must sampled/ resampled
87 | to generate the new, resized, image.
88 |
89 | Picharsso uses the [resampling filters that come with Pillow](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#filters){target=_blank}.
90 | The choice of the resampling filter is defined by the `resample` parameter.
91 |
92 | Consider the following image:
93 |
94 |
95 |
96 |
97 |
98 |
99 | Starry Night [Vincent van Gogh, 1889]
100 |
101 |
102 |
103 | Here's what it should look like:
104 |
105 | === "resample = 'nearest'"
106 |
107 |

111 |
112 |
113 | === "'box'"
114 |
115 |

119 |
120 |
121 | === "'bilinear'"
122 |
123 |

127 |
128 |
129 | === "'hamming'"
130 |
131 |

135 |
136 |
137 | === "'bicubic'"
138 |
139 |

143 |
144 |
145 | === "'lanczos'"
146 |
147 |

151 |
152 |
153 | !!! note
154 | All resizing operations use the same filter that is set by `resample`.
155 |
156 | ### Normalization
157 |
158 | Pillow supports multiple [image modes](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes){target=_blank}.
159 | For simplicity, the algorithms were designed to work on the `RGB` image mode.
160 | Hence, images must be converted appropriately.
161 |
162 | !!! info "White Background"
163 | A white background is applied to images with the `P` and `RGBA` modes.
164 |
165 | ??? abstract "Source"
166 | Refer to the [`ensure_rgb` function][picharsso.utils.ensure_rgb] for more information.
167 |
168 | ### Conversion
169 |
170 | This step lies at the heart of each style.
171 |
172 | #### Resizing
173 |
174 | Before the `image` can be processed, it must be resized appropriately.
175 | The **scale** of the resizing **depends on the processing algorithm**.
176 |
177 |
178 |

179 |
180 |
181 | ??? abstract "Source"
182 | Refer to the [`calculate_size` function][picharsso.draw.base.BaseDrawer.calculate_size]
183 | for more information.
184 |
185 | #### Processing
186 |
187 | The resized `image` is processed into a `text_matrix`.
188 |
189 |
190 |

191 |
192 |
193 | ??? abstract "Source"
194 | Refer to the [`process` function][picharsso.draw.base.BaseDrawer.process]
195 | for more information.
196 |
197 | ### Formatting
198 |
199 | Before it can be displayed, the `text_matrix` must be **formatted into a single string**.
200 | The type of `formatter` used is defined by the `mode` parameter.
201 |
202 | !!! info "Colorization"
203 | The `formatter` requires the original `image` and the choice of `resample` filter
204 | for pooling colors.
205 |
206 | Refer to the [colorization step](../formats/index.md#colorization)
207 | for more information.
208 |
209 | !!! question "Formats"
210 | Refer to the [Formats documentation](../formats/index.md)
211 | to learn about the supported output formats.
212 |
213 | ## Varieties
214 |
215 | All the following styles are implemented using a `drawer`
216 | which inherits from the [`BaseDrawer`][picharsso.draw.base.BaseDrawer].
217 |
218 | Consider the following image:
219 |
220 |
221 |
222 |
223 |
224 |
225 | Apple Computer [Rob Janoff, 1977]
226 |
227 |
228 |
229 | Here's what it should look like:
230 |
231 | ### Braille
232 | : The [Braille style](braille.md) is implemented using the
233 | [`BrailleDrawer`][picharsso.draw.braille.BrailleDrawer].
234 |
235 |
236 |

240 |
241 |
242 | ### Gradient
243 | : The [gradient style](gradient.md) is implemented using the
244 | [`GradientDrawer`][picharsso.draw.gradient.GradientDrawer].
245 |
246 |
247 |

251 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Picharsso
2 | site_description: "A utility for converting images to text art."
3 | site_author: "Kelvin DeCosta"
4 | site_url: https://kelvindecosta.github.io/picharsso/
5 |
6 | repo_name: kelvindecosta/picharsso
7 | repo_url: https://github.com/kelvindecosta/picharsso
8 | edit_uri: ""
9 |
10 | copyright: Copyright © 2019 Kelvin DeCosta
11 |
12 | nav:
13 | - Home: index.md
14 | - Styles:
15 | - Overview: styles/index.md
16 | - Braille: styles/braille.md
17 | - Gradient: styles/gradient.md
18 | - Formats:
19 | - Overview: formats/index.md
20 | - ANSI: formats/ansi.md
21 | - HTML: formats/html.md
22 | - CLI:
23 | - picharsso: commands/index.md
24 | - picharsso draw: commands/draw/index.md
25 | - picharsso draw braille: commands/draw/braille.md
26 | - picharsso draw gradient: commands/draw/gradient.md
27 | - picharsso info: commands/info.md
28 | - API:
29 | - draw:
30 | - __init__: library/draw/index.md
31 | - base: library/draw/base.md
32 | - braille: library/draw/braille.md
33 | - gradient: library/draw/gradient.md
34 | - format:
35 | - __init__: library/format/index.md
36 | - base: library/format/base.md
37 | - ansi: library/format/ansi.md
38 | - html: library/format/html.md
39 | - meta: library/meta.md
40 | - utils: library/utils.md
41 | - Examples:
42 | - Image: examples/01-image/index.md
43 | - GIF: examples/02-gif/index.md
44 | - Web: examples/03-web/index.md
45 | - License: license.md
46 | - Contributing: contributing.md
47 |
48 | theme:
49 | name: material
50 | custom_dir: docs/overrides
51 | logo: assets/images/favicon.webp
52 | palette:
53 | primary: black
54 | accent: light blue
55 | font:
56 | text: Nunito
57 | code: Source Code Pro
58 | favicon: assets/images/favicon.webp
59 | include_search_page: false
60 | search_index_only: true
61 |
62 | markdown_extensions:
63 | - admonition
64 | - attr_list
65 | - codehilite:
66 | guess_lang: false
67 | - def_list
68 | - meta
69 | - pymdownx.betterem:
70 | smart_enable: all
71 | - pymdownx.details
72 | - pymdownx.arithmatex:
73 | generic: true
74 | - pymdownx.smartsymbols
75 | - pymdownx.snippets:
76 | check_paths: true
77 | - pymdownx.superfences
78 | - pymdownx.tabbed
79 | - toc:
80 | permalink: "#"
81 |
82 | plugins:
83 | - search
84 | - mkdocstrings:
85 | handlers:
86 | python:
87 | rendering:
88 | show_root_heading: false
89 | show_root_toc_entry: false
90 | - exclude:
91 | glob:
92 | - snippets/*
93 | - minify:
94 | minify_html: true
95 |
96 | extra:
97 | social:
98 | - icon: fontawesome/solid/globe
99 | link: https://kelvindecosta.com
100 | name: "Website"
101 | - icon: fontawesome/brands/github
102 | link: https://github.com/kelvindecosta
103 | name: "GitHub"
104 | - icon: fontawesome/brands/linkedin
105 | link: https://linkedin.com/in/kelvindecosta
106 | name: "LinkedIn"
107 | - icon: fontawesome/brands/instagram
108 | link: https://instagram.com/_kelvindecosta
109 | name: "Instagram"
110 | - icon: fontawesome/brands/twitter
111 | link: https://twitter.com/_kelvindecosta
112 | name: "Twitter"
113 | - icon: fontawesome/solid/envelope
114 | link: https://mailhide.io/e/c1R8e
115 | name: "Mail"
116 | site_image: assets/images/logo.png
117 |
118 | extra_css:
119 | - assets/css/mkdocstrings.css
120 |
121 | extra_javascript:
122 | - assets/js/config.js
123 | - https://polyfill.io/v3/polyfill.min.js?features=es6
124 | - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
125 |
126 | google_analytics:
127 | - !!python/object/apply:os.getenv ["GOOGLE_ANALYTICS_KEY"]
128 | - auto
129 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # For package
2 | click
3 | numpy
4 | pillow
5 | sty
6 |
7 | # For examples
8 | requests
9 |
10 | # For repository
11 | mkdocs
12 | mkdocs-exclude
13 | mkdocs-material
14 | mkdocs-minify-plugin
15 | mkdocstrings
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import find_packages, setup
2 |
3 | from src.meta import NAME, DESCRIPTION, VERSION, REPO_URL, DOCS_URL, AUTHOR, LICENSE
4 |
5 | with open("README.md", "r") as fs:
6 | LONGE_DESCRIPTION = fs.read()
7 |
8 | setup(
9 | name=NAME,
10 | version=VERSION,
11 | description=DESCRIPTION,
12 | long_description=LONGE_DESCRIPTION,
13 | long_description_content_type="text/markdown",
14 | project_urls={"Documentation": DOCS_URL, "Source": REPO_URL},
15 | author=AUTHOR,
16 | author_email="decostakelvin@gmail.com",
17 | license=LICENSE,
18 | classifiers=[
19 | "Programming Language :: Python :: 3",
20 | "Operating System :: OS Independent",
21 | "License :: OSI Approved :: MIT License",
22 | "Development Status :: 5 - Production/Stable",
23 | "Topic :: Artistic Software",
24 | "Topic :: Terminals",
25 | "Topic :: Utilities",
26 | ],
27 | packages=list(map(lambda x: x.replace("src", NAME), find_packages("."))),
28 | package_dir={NAME: "src"},
29 | package_data={"": ["data/*.txt"]},
30 | python_requires=">=3.8",
31 | install_requires=["click", "numpy", "pillow", "sty",],
32 | entry_points={"console_scripts": [f"{NAME} = {NAME}.cli:main"]},
33 | )
34 |
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
1 | from .draw import new_drawer
2 | from .format import new_formatter
3 | from .meta import DESCRIPTION as __doc__, VERSION as __version__
4 |
5 | __all__ = ["new_drawer", "new_formatter"]
6 |
--------------------------------------------------------------------------------
/src/__main__.py:
--------------------------------------------------------------------------------
1 | """This module defines the behaviour of the package
2 | in a top-level script environment.
3 |
4 | The following command executes this script:
5 |
6 | ```bash
7 | python -m picharsso
8 | ```
9 | """
10 |
11 | from .cli import main
12 |
13 | if __name__ == "__main__":
14 | main()
15 |
--------------------------------------------------------------------------------
/src/cli/__init__.py:
--------------------------------------------------------------------------------
1 | """This package defines the `picharsso` command.
2 |
3 | Refer to https://kelvindecosta.github.io/picharsso/commands/.
4 | """
5 |
6 |
7 | import click
8 |
9 | from .draw import draw
10 | from .info import info
11 | from ..meta import DESCRIPTION
12 |
13 | CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
14 |
15 |
16 | @click.group(
17 | help=DESCRIPTION,
18 | options_metavar="[options]",
19 | subcommand_metavar=" [args]",
20 | context_settings=CONTEXT_SETTINGS,
21 | )
22 | def main():
23 | """The main program."""
24 |
25 |
26 | main.add_command(draw)
27 | main.add_command(info)
28 |
--------------------------------------------------------------------------------
/src/cli/draw/__init__.py:
--------------------------------------------------------------------------------
1 | """This package defines the `picharsso draw` command.
2 |
3 | Refer to https://kelvindecosta.github.io/picharsso/commands/draw/.
4 | """
5 |
6 | import click
7 | from PIL import Image
8 |
9 | from ...draw import RESAMPLING_FILTERS, DEFAULT_RESAMPLING
10 | from ...format import FORMATTERS, DEFAULT_FORMATTER
11 | from ...utils import terminal_size
12 |
13 | from .gradient import draw_gradient
14 | from .braille import draw_braille
15 |
16 |
17 | @click.group(options_metavar="[options]", subcommand_metavar=" [args]")
18 | @click.argument("path", type=click.Path(exists=True), metavar="")
19 | @click.option(
20 | "-c", "--colorize", is_flag=True, help="Apply image colors to output text."
21 | )
22 | @click.option(
23 | "-m",
24 | "--mode",
25 | type=click.Choice(list(FORMATTERS.keys())),
26 | default=DEFAULT_FORMATTER,
27 | help="Format mode for output text.",
28 | show_default=True,
29 | )
30 | @click.option(
31 | "-r",
32 | "--resample",
33 | type=click.Choice(list(RESAMPLING_FILTERS.keys())),
34 | default=DEFAULT_RESAMPLING,
35 | help="Resampling filter.",
36 | show_default=True,
37 | )
38 | @click.option(
39 | "-H",
40 | "--height",
41 | type=int,
42 | default=0,
43 | help="Height of output text in characters.\n\nIf 0, derives from width.",
44 | show_default=True,
45 | )
46 | @click.option(
47 | "-W",
48 | "--width",
49 | type=int,
50 | default=0,
51 | help="Width of output text in characters.\n\nIf 0, derives from height.",
52 | show_default=True,
53 | )
54 | @click.option(
55 | "-term-h",
56 | "--terminal-height",
57 | is_flag=True,
58 | help="Sets height to terminal height.",
59 | )
60 | @click.option(
61 | "-term-w", "--terminal-width", is_flag=True, help="Sets width to terminal width.",
62 | )
63 | @click.pass_context
64 | def draw(
65 | context,
66 | path,
67 | colorize,
68 | mode,
69 | resample,
70 | height,
71 | width,
72 | terminal_height,
73 | terminal_width,
74 | ):
75 | """Generate text art from an image.
76 |
77 | Path to the image file.
78 | """
79 | image = Image.open(path)
80 |
81 | if terminal_width or terminal_height or height == 0 and width == 0:
82 | term_h, term_w = terminal_size()
83 |
84 | if terminal_height:
85 | height = term_h
86 |
87 | if terminal_width:
88 | width = term_w
89 |
90 | if height == 0 and width == 0:
91 | height = term_h
92 | width = term_w
93 |
94 | context.obj = {
95 | "image": image,
96 | "colorize": colorize,
97 | "mode": mode,
98 | "resample": resample,
99 | "height": height,
100 | "width": width,
101 | }
102 |
103 |
104 | draw.add_command(draw_gradient)
105 | draw.add_command(draw_braille)
106 |
--------------------------------------------------------------------------------
/src/cli/draw/braille.py:
--------------------------------------------------------------------------------
1 | """This module defines the `picharsso draw braille` command.
2 |
3 | Refer to https://kelvindecosta.github.io/picharsso/commands/draw/braille/.
4 | """
5 |
6 |
7 | import click
8 |
9 | from ...draw import new_drawer
10 | from ...draw.braille import DEFAULT_THRESHOLD
11 |
12 |
13 | @click.command("braille", options_metavar="[options]")
14 | @click.option(
15 | "-t",
16 | "--threshold",
17 | type=click.IntRange(0, 255),
18 | help="Threshold pixel luminance (from grayscale).",
19 | default=DEFAULT_THRESHOLD,
20 | show_default=True,
21 | )
22 | @click.pass_context
23 | def draw_braille(context, threshold):
24 | """Use the Braille style."""
25 |
26 | image = context.obj.pop("image")
27 |
28 | drawer = new_drawer("braille", threshold=threshold, **context.obj)
29 | print(drawer(image))
30 |
--------------------------------------------------------------------------------
/src/cli/draw/gradient.py:
--------------------------------------------------------------------------------
1 | """This module defines the `picharsso draw gradient` command.
2 |
3 | Refer to https://kelvindecosta.github.io/picharsso/commands/draw/gradient/.
4 | """
5 |
6 | import click
7 |
8 | from ...draw import new_drawer
9 | from ...draw.gradient import DEFAULT_CHARSET
10 |
11 |
12 | @click.command("gradient", options_metavar="[options]")
13 | @click.option(
14 | "-s",
15 | "--charset",
16 | type=str,
17 | help="Character set ordered by increasing 'brightness'.",
18 | default=DEFAULT_CHARSET,
19 | show_default=True,
20 | )
21 | @click.option(
22 | "-n", "--negative", is_flag=True, help="Whether to invert output text brightness."
23 | )
24 | @click.pass_context
25 | def draw_gradient(context, charset, negative):
26 | """Use the gradient style."""
27 |
28 | image = context.obj.pop("image")
29 |
30 | drawer = new_drawer("gradient", charset=charset, negative=negative, **context.obj)
31 | print(drawer(image))
32 |
--------------------------------------------------------------------------------
/src/cli/info.py:
--------------------------------------------------------------------------------
1 | """This module defines the `picharsso info` command.
2 |
3 | Refer to https://kelvindecosta.github.io/picharsso/commands/info/.
4 | """
5 |
6 | from pathlib import Path
7 |
8 | import click
9 |
10 | from .. import __file__ as root_module_path
11 | from ..meta import NAME, VERSION, DESCRIPTION, REPO_URL, DOCS_URL, LICENSE, AUTHOR
12 | from ..utils import embolden, italicize
13 |
14 |
15 | @click.command(options_metavar="[options]")
16 | def info():
17 | """Displays package information."""
18 | with open(Path(root_module_path).parent / "data" / "logo.txt", "r") as file_stream:
19 | logo_text = file_stream.read().strip()
20 |
21 | output = logo_text.split("\n")
22 |
23 | line = 3
24 | output[line] += f" {embolden(NAME)}"
25 |
26 | line += 2
27 | output[line] += f" {italicize(DESCRIPTION)}"
28 |
29 | line += 3
30 | output[line] += f" {italicize('Version')} : {VERSION}"
31 |
32 | line += 1
33 | output[line] += f" {italicize('License')} : {LICENSE}"
34 |
35 | line += 1
36 | output[line] += f" {italicize('Author')} : {AUTHOR}"
37 |
38 | line += 3
39 | output[line] += f" {italicize('Source')} : {REPO_URL}"
40 |
41 | line += 1
42 | output[line] += f" {italicize('Docs')} : {DOCS_URL}"
43 |
44 | print("\n".join(output[1:-1]))
45 |
--------------------------------------------------------------------------------
/src/data/logo.txt:
--------------------------------------------------------------------------------
1 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
2 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
3 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
4 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
5 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
6 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;229;62;62m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
7 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;237;137;54mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
8 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
9 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
10 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
11 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;214;158;46mP[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
12 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
13 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;56;161;105m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
14 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;49;130;206m?[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
15 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
16 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;254;235;200m@[39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
17 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
18 | [38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m[38;2;0;0;0m [39m
19 |
--------------------------------------------------------------------------------
/src/draw/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | This package defines drawers for different styles of text art.
3 |
4 | !!! question "Styles"
5 | Refer to the [Styles documentation](../../styles/index.md)
6 | for an in-depth guide to the **image processing behind Picharsso**.
7 | """
8 |
9 | from .gradient import GradientDrawer
10 | from .base import BaseDrawer, RESAMPLING_FILTERS, DEFAULT_RESAMPLING
11 | from .braille import BrailleDrawer
12 |
13 | DRAWERS: dict = {"gradient": GradientDrawer, "braille": BrailleDrawer}
14 | """The collection of drawers."""
15 |
16 |
17 | def new_drawer(style, **kwargs):
18 | """Creates a new drawer instance.
19 |
20 | Args:
21 | style (str): The style of the text art.
22 | **kwargs (dict): Appropriate keyword arguments.
23 | See [`BaseDrawer`][picharsso.draw.base.BaseDrawer]
24 | and others.
25 |
26 | Returns:
27 | Type[picharsso.draw.BaseDrawer]: The new drawer instance.
28 | """
29 | return DRAWERS[style](**kwargs)
30 |
--------------------------------------------------------------------------------
/src/draw/base.py:
--------------------------------------------------------------------------------
1 | """
2 | This module defines an abstract base drawer.
3 |
4 | !!! question "Styles"
5 | Refer to the [Styles documentation](../../styles/index.md)
6 | for an in-depth guide to the **image processing behind Picharsso**.
7 | """
8 |
9 | from abc import ABC, abstractmethod
10 |
11 | from PIL import Image
12 |
13 | from ..format import new_formatter
14 | from ..utils import ensure_rgb
15 |
16 | RESAMPLING_FILTERS: dict = {
17 | "nearest": Image.NEAREST,
18 | "box": Image.BOX,
19 | "bilinear": Image.BILINEAR,
20 | "hamming": Image.HAMMING,
21 | "bicubic": Image.BICUBIC,
22 | "lanczos": Image.LANCZOS,
23 | }
24 | """A collection of resampling filters.
25 | See [Pillow's Filters](https://pillow.readthedocs.io/en/stable/handbook/concepts.html#filters){target=_blank}.
26 | """
27 |
28 | DEFAULT_RESAMPLING: str = "nearest"
29 | """The default resampling filter."""
30 |
31 |
32 | class BaseDrawer(ABC):
33 | """
34 | An abstract base drawer.
35 |
36 | Attributes:
37 | height (int): The desired height of the text in characters.
38 | width (int): The desired width of the text in characters.
39 | resample (int): The resampling filter.
40 | format (Type[picharsso.format.BaseFormatter]): The formatter instance.
41 |
42 | Note:
43 | The following methods must be overwritten:
44 |
45 | - [`calculate_size`][picharsso.draw.base.BaseDrawer.calculate_size]
46 | - [`process`][picharsso.draw.base.BaseDrawer.process]
47 | """
48 |
49 | def __init__(self, height=42, width=0, resample=DEFAULT_RESAMPLING, **kwargs):
50 | """Initialization method.
51 |
52 | Args:
53 | height (Optional[int]): The desired height of the text in characters.
54 | width (Optional[int]): The desired width of the text in characters.
55 | resample (Optional[str]): The resampling filter.
56 | **kwargs (dict): Appropriate keyword arguments.
57 | See [`BaseFormatter`][picharsso.format.base.BaseFormatter] and others.
58 |
59 | Note:
60 | When set as `0`, `height` is derived from `width` and vice versa.
61 | This is done to preserve the aspect ratio of the image.
62 | """
63 | self.height = None
64 | self.width = None
65 | self.resample = None
66 | BaseDrawer.set(self, height=height, width=width, resample=resample)
67 |
68 | self.format = new_formatter(**kwargs)
69 |
70 | def __call__(self, image):
71 | """Applies processing and formatting on the `image`
72 | and returns a single string.
73 |
74 | Args:
75 | image (PIL.Image.Image): The subject image.
76 |
77 | Returns:
78 | str: The string of text art.
79 | """
80 | # Ensure that the image is in the `RGB` mode.
81 | image = ensure_rgb(image)
82 |
83 | # Calculate the new size of the image, for processing the text matrix.
84 | image_size = self.calculate_size(image.size[::-1])
85 |
86 | # Process text matrix from the resized image.
87 | text_matrix = self.process(
88 | image.resize(image_size[::-1], resample=self.resample)
89 | )
90 |
91 | # Apply formatting.
92 | return self.format(text_matrix, image, self.resample)
93 |
94 | @abstractmethod
95 | def calculate_size(self, image_size):
96 | """Calculates the size of the image for processing the text matrix.
97 |
98 | Args:
99 | image_size (Tuple[int, int]): The height and width of the subject image.
100 |
101 | Returns:
102 | Tuple[int, int]: The size of the image.
103 | """
104 |
105 | @abstractmethod
106 | def process(self, image):
107 | """Converts an image to a matrix of text.
108 |
109 | Args:
110 | image (PIL.Image.Image): The subject image,
111 | with `mode = "RGB"`,
112 | and `size = (, )`.
113 |
114 | Returns:
115 | numpy.ndarray: The text matrix,
116 | with `shape = (, )`,
117 | and `dtype = str`.
118 | """
119 |
120 | def set(self, height=None, width=None, resample=None):
121 | """Sets attributes of the drawer instance.
122 |
123 | Args:
124 | height (Option[int]): Sets `height`.
125 | width (Option[int]): Sets `width`.
126 | resample (Option[str]): Sets `resample`.
127 |
128 | Raises:
129 | ValueError: If both `height` and `width` are set to `0`.
130 | """
131 | # Set resampling filter
132 | if resample is not None:
133 | self.resample = RESAMPLING_FILTERS[resample]
134 |
135 | # Set height and width
136 | if height is not None or width is not None:
137 | new_h = self.height if height is None else height
138 | new_w = self.width if width is None else width
139 |
140 | if new_h == 0 and new_w == 0:
141 | raise ValueError("Either height or width must be non-zero")
142 |
143 | self.height = new_h
144 | self.width = new_w
145 |
146 |
147 | __all__ = ["BaseDrawer", "RESAMPLING_FILTERS", "DEFAULT_RESAMPLING"]
148 |
--------------------------------------------------------------------------------
/src/draw/braille.py:
--------------------------------------------------------------------------------
1 | """
2 | This module defines a drawer for the [Braille style](../../styles/braille.md).
3 |
4 | ??? example "Example"
5 | Consider the following image:
6 |
7 |
8 |
9 |
10 |
11 |
12 | Apple Computer [Rob Janoff, 1977]
13 |
14 |
15 |
16 | Here's what it should look like:
17 |
18 |
19 |

23 |
24 | """
25 |
26 | import numpy as np
27 |
28 | from .base import BaseDrawer
29 | from ..utils import submatrices
30 |
31 | DEFAULT_THRESHOLD: int = 64
32 | """The default threshold grayscale intensity."""
33 |
34 |
35 | class BrailleDrawer(BaseDrawer):
36 | """
37 | A drawer for the [Braille style](../../styles/braille.md).
38 |
39 | Inherits [`BaseDrawer`][picharsso.draw.base.BaseDrawer].
40 |
41 | Attributes:
42 | threshold (int): Threshold grayscale intensity for pixels to be considered.
43 | kernel (numpy.ndarray): A hard-coded matrix relating the intensity to
44 | the Unicode values for Braille characters.
45 | charset_array (numpy.ndarray): A matrix of all Braille characters,
46 | indexed by their offsetted Unicode value.
47 | """
48 |
49 | def __init__(self, threshold=DEFAULT_THRESHOLD, **kwargs):
50 | """Initialization method.
51 |
52 | Args:
53 | threshold (Optional[int]): Threshold grayscale intensity
54 | for pixels to be considered.
55 | """
56 |
57 | super().__init__(**kwargs)
58 | self.threshold = None
59 | self.set(threshold=threshold)
60 |
61 | self.kernel = np.array([[1, 8], [2, 16], [4, 32], [64, 128]]).astype(np.uint8)
62 | self.charset_array = np.array([chr(ord("\u2800") + x) for x in range(256)])
63 |
64 | def calculate_size(self, image_size):
65 | # Possible dimensions
66 | new_h = self.height
67 | new_w = self.width
68 |
69 | new_h = new_h * 4
70 | new_w = new_w * 2
71 |
72 | # Image dimensions
73 | old_h, old_w = image_size
74 |
75 | # If height is not set, infer it from width
76 | if not new_h:
77 | new_h = int(round(old_h / old_w * new_w))
78 |
79 | # If width is not set, infer it from height
80 | if not new_w:
81 | new_w = int(round(old_w / old_h * new_h))
82 |
83 | return new_h, new_w
84 |
85 | def process(self, image):
86 | # Convert the image mode to grayscale.
87 | # Filter all pixels with intensity greater than or equal to the threshold.
88 | # Perform a convolution on this filtered image with the Braille kernel.
89 | # The resultant matrix has the offsetted Unicode values, i.e., indices
90 | # for the corresponding Braille characters that form the image.
91 | # Index the character set with the indices.
92 | return self.charset_array[
93 | np.einsum(
94 | "ij,klij->kl",
95 | self.kernel,
96 | submatrices(
97 | (np.array(image.convert("L")) >= self.threshold).astype(np.uint8),
98 | self.kernel.shape,
99 | ),
100 | )
101 | ]
102 |
103 | def set(self, threshold=None, **kwargs):
104 | """Sets attributes of the drawer instance.
105 |
106 | Args:
107 | threshold (Optional[int]): Sets `threshold`.
108 | **kwargs (dict): Appropriate keyword arguments.
109 | See [`BaseDrawer.set`][picharsso.draw.base.BaseDrawer.set].
110 | """
111 | super().set(**kwargs)
112 |
113 | if threshold is not None:
114 | self.threshold = threshold
115 |
116 |
117 | __all__ = ["BrailleDrawer"]
118 |
--------------------------------------------------------------------------------
/src/draw/gradient.py:
--------------------------------------------------------------------------------
1 | """
2 | This module defines a drawer for the [gradient style](../../styles/gradient.md).
3 |
4 | ??? example "Example"
5 | Consider the following image:
6 |
7 |
8 |
9 |
10 |
11 |
12 | Apple Computer [Rob Janoff, 1977]
13 |
14 |
15 |
16 | Here's what it should look like:
17 |
18 |
19 |

23 |
24 | """
25 |
26 | import numpy as np
27 |
28 | from .base import BaseDrawer
29 |
30 | DEFAULT_CHARSET: str = " :!?PG@"
31 | """The default character set."""
32 |
33 |
34 | class GradientDrawer(BaseDrawer):
35 | """
36 | A drawer for the [gradient style](../../styles/gradient.md).
37 |
38 | Inherits [`BaseDrawer`][picharsso.draw.base.BaseDrawer].
39 |
40 | Attributes:
41 | charset (str): A set of characters ordered by the amount of area
42 | their symbols occupy.
43 | negative (bool): Whether or not to reverse the `charset`.
44 | charset_array (numpy.ndarray): A vectorized version of the `charset`.
45 | """
46 |
47 | def __init__(self, charset=DEFAULT_CHARSET, negative=False, **kwargs):
48 | """Initialization method.
49 |
50 | Args:
51 | charset (Optional[str]): A set of characters ordered
52 | by the amount of area their symbols occupy.
53 | Defaults to `DEFAULT_CHARSET`
54 | negative (Optional[bool]): Whether or not to reverse the `charset`.
55 | **kwargs (dict): Appropriate keyword arguments.
56 | See [`BaseDrawer`][picharsso.draw.base.BaseDrawer].
57 | """
58 | super().__init__(**kwargs)
59 | self.charset = None
60 | self.negative = None
61 | self.charset_array = None
62 | self.set(charset=charset, negative=negative)
63 |
64 | def calculate_size(self, image_size):
65 | # Possible dimensions
66 | new_h = self.height
67 | new_w = self.width
68 |
69 | # Image dimensions
70 | old_h, old_w = image_size
71 |
72 | # If height is not set, infer it from width
73 | if not new_h:
74 | new_h = int(round(old_h / old_w * new_w / 2.125))
75 |
76 | # If width is not set, infer it from height
77 | if not new_w:
78 | new_w = int(round(old_w / old_h * new_h * 2.125))
79 |
80 | return new_h, new_w
81 |
82 | def process(self, image):
83 | # Convert the image mode to grayscale.
84 | # Normalize the pixel values from a range of (0, 255) to (0, len(self.charset)-1),
85 | # to obtain indices for the character set.
86 | # Index the character set array with the indices.
87 | return self.charset_array[
88 | np.round(
89 | np.array(image.convert("L")) / 255 * (len(self.charset) - 1)
90 | ).astype(int)
91 | ]
92 |
93 | def set(self, charset=None, negative=None, **kwargs):
94 | """Sets attributes of the drawer instance.
95 |
96 | Args:
97 | charset (Optional[str]): Sets `charset`.
98 | negative (Optional[bool]): Sets `negative`.
99 | **kwargs (dict): Appropriate keyword arguments.
100 | See [`BaseDrawer.set`][picharsso.draw.base.BaseDrawer.set].
101 | """
102 | super().set(**kwargs)
103 |
104 | if charset is not None:
105 | self.charset = charset
106 |
107 | if negative is not None:
108 | self.negative = negative
109 |
110 | self.charset_array = np.array(
111 | list(self.charset if not self.negative else self.charset[::-1])
112 | )
113 |
114 |
115 | __all__ = ["GradientDrawer"]
116 |
--------------------------------------------------------------------------------
/src/format/__init__.py:
--------------------------------------------------------------------------------
1 | """
2 | This package defines formatters for different modes of text output.
3 |
4 | !!! question "Formats"
5 | Refer to the [Formats documentation](../../formats/index.md)
6 | to learn about the supported output formats.
7 | """
8 |
9 | from .ansi import AnsiFormatter
10 | from .base import BaseFormatter
11 | from .html import HtmlFormatter
12 |
13 | FORMATTERS: dict = {"ansi": AnsiFormatter, "html": HtmlFormatter}
14 | """The collection of formatters."""
15 |
16 | DEFAULT_FORMATTER: str = "ansi"
17 | """The default formatter."""
18 |
19 |
20 | def new_formatter(mode=DEFAULT_FORMATTER, **kwargs):
21 | """Creates a new formatter instance.
22 |
23 | Args:
24 | mode (Option[str]): The mode of the output text.
25 | Defaults to `DEFAULT_FORMATTER`.
26 | **kwargs (dict): Appropriate keyword arguments.
27 | See [`BaseFormatter`][picharsso.format.base.BaseFormatter]
28 | and others.
29 |
30 | Returns:
31 | Type[picharsso.format.BaseFormatter] : The new formatter instance.
32 | """
33 | return FORMATTERS[mode](**kwargs)
34 |
--------------------------------------------------------------------------------
/src/format/ansi.py:
--------------------------------------------------------------------------------
1 | """This module defines a formatter for the [ANSI coloring scheme](../../formats/ansi.md)."""
2 |
3 | from sty import fg
4 |
5 | from .base import BaseFormatter
6 |
7 |
8 | class AnsiFormatter(BaseFormatter):
9 | """
10 | A formatter for the [ANSI coloring scheme](../../formats/ansi.md).
11 |
12 | Inherits [`BaseFormatter`][picharsso.format.base.BaseFormatter].
13 | """
14 |
15 | @staticmethod
16 | def color(text, color):
17 | return f"{fg(*color)}{text}{fg.rs}"
18 |
19 | @staticmethod
20 | def translate(text_matrix):
21 | return text_matrix
22 |
23 | @staticmethod
24 | def unify(text_matrix):
25 | return "\n".join(["".join(row) for row in text_matrix])
26 |
27 |
28 | __all__ = ["AnsiFormatter"]
29 |
--------------------------------------------------------------------------------
/src/format/base.py:
--------------------------------------------------------------------------------
1 | """
2 | This module defines an abstract base formatter.
3 |
4 | !!! question "Formats"
5 | Refer to the [Formats documentation](../../formats/index.md)
6 | to learn about the supported output formats.
7 | """
8 |
9 | from abc import ABC, abstractmethod
10 |
11 | import numpy as np
12 | from numpy.lib.recfunctions import unstructured_to_structured
13 |
14 |
15 | class BaseFormatter(ABC):
16 | """
17 | An abstract base formatter.
18 |
19 | Attributes:
20 | colorize (bool): Whether to color the text.
21 | vcolor (Callable): The vectorized implementation of the `color` method.
22 |
23 | Note:
24 | The following methods must be overwritten:
25 |
26 | - [`color`][picharsso.format.base.BaseFormatter.color]
27 | - [`translate`][picharsso.format.base.BaseFormatter.translate]
28 | - [`unify`][picharsso.format.base.BaseFormatter.unify]
29 | """
30 |
31 | def __init__(self, colorize=False):
32 | """Initialization method.
33 |
34 | Args:
35 | colorize (Option[bool]): Whether to color the text.
36 | """
37 | self.colorize = None
38 | BaseFormatter.set(self, colorize=colorize)
39 |
40 | self.vcolor = np.vectorize(self.color)
41 |
42 | def __call__(self, text_matrix, image, resample):
43 | """Applies formatting and colorization on the `text_matrix`
44 | and returns a single string.
45 |
46 | Args:
47 | text_matrix (numpy.ndarray): The subject text matrix,
48 | with `shape = (, )`,
49 | and `dtype = str`.
50 | image (PIL.Image.Image): The subject image.
51 | resample (int): The resampling filter.
52 |
53 | Returns:
54 | str: The formatted string of text with color (if specified).
55 | """
56 |
57 | text_size = text_matrix.shape
58 |
59 | # Apply any translations.
60 | text_matrix = self.translate(text_matrix)
61 |
62 | # Colorize if necessary
63 | if self.colorize:
64 | # Pool the colors from the original image by resizing it to the size of the text output.
65 | # Using the vectorized `color` method, color each element in the `text_martix`.
66 | # The vectorized operation takes a `str` from `text_matrix`
67 | # and a `List[int, int, int]` from the pooled colors.
68 | text_matrix = self.vcolor(
69 | text_matrix,
70 | unstructured_to_structured(
71 | np.array(image.resize(text_size[::-1], resample=resample)).astype(
72 | np.uint8
73 | )
74 | ).astype("O"),
75 | )
76 |
77 | return self.unify(text_matrix)
78 |
79 | @staticmethod
80 | @abstractmethod
81 | def color(text, color):
82 | """Applies `color` to a string of `text`.
83 |
84 | Args:
85 | text (str): The subject text.
86 | color (Tuple[int, int, int]): The `RGB` value for the color.
87 |
88 | Returns:
89 | str: The colored text.
90 | """
91 |
92 | @staticmethod
93 | @abstractmethod
94 | def translate(text_matrix):
95 | """Applies translatations to `text_matrix`.
96 |
97 | Args:
98 | text_matrix (numpy.ndarray): The subject text matrix,
99 | with `shape = (, )`,
100 | and `dtype = str`.
101 |
102 | Returns:
103 | numpy.ndarray: The translated text_matrix.
104 | """
105 |
106 | @staticmethod
107 | @abstractmethod
108 | def unify(text_matrix):
109 | """Formats a `text_matrix` into a single string.
110 |
111 | Args:
112 | text_matrix (numpy.ndarray): The subject text matrix,
113 | with `shape = (, )`,
114 | and `dtype = str`.
115 |
116 | Returns:
117 | str: The formatted string of text art.
118 | """
119 |
120 | def set(self, colorize=None):
121 | """Sets attributes of the formatter instance.
122 |
123 | Args:
124 | colorize (Optional[bool]): Sets `colorize`.
125 | """
126 | if colorize is not None:
127 | self.colorize = colorize
128 |
129 |
130 | __all__ = ["BaseFormatter"]
131 |
--------------------------------------------------------------------------------
/src/format/html.py:
--------------------------------------------------------------------------------
1 | """This module defines a formatter for [HTML](../../formats/html.md)."""
2 |
3 | from html.entities import name2codepoint
4 |
5 | import numpy as np
6 |
7 | from .base import BaseFormatter
8 |
9 | HTML_ENTITY_MAP: dict = {chr(value): key for (key, value) in name2codepoint.items()}
10 | """A dictionary mapping unicode characters to their equivalent HTML entities."""
11 |
12 | HTML_ENTITY_MAP[" "] = "nbsp;"
13 |
14 |
15 | class HtmlFormatter(BaseFormatter):
16 | """
17 | A formatter for [HTML](../../formats/html.md).
18 |
19 | Inherits [`BaseFormatter`][picharsso.format.base.BaseFormatter].
20 | """
21 |
22 | @staticmethod
23 | def color(text, color):
24 | return f'{text}'
25 |
26 | @staticmethod
27 | def translate(text_matrix):
28 | unique_chars = np.unique(text_matrix)
29 |
30 | # Change datatype to accomodate strings of varying length
31 | text_matrix = text_matrix.astype(
32 | f"{}".format(
45 | "\n".join([f"
{''.join(row)}
" for row in text_matrix])
46 | )
47 |
48 |
49 | __all__ = ["HtmlFormatter", "HTML_ENTITY_MAP"]
50 |
--------------------------------------------------------------------------------
/src/meta.py:
--------------------------------------------------------------------------------
1 | """This module defines variables for the package metadata."""
2 |
3 | NAME: str = "picharsso"
4 | """The package name."""
5 |
6 | DESCRIPTION: str = "A utility for converting images to text art."
7 | """The package description."""
8 |
9 | VERSION: str = "2.0.1"
10 | """The current package version.
11 | """
12 |
13 | REPO_URL: str = f"https://github.com/kelvindecosta/{NAME}"
14 | """The URL of the package source code."""
15 |
16 | DOCS_URL: str = f"https://kelvindecosta.github.io/{NAME}"
17 | """The URL of the package documentation."""
18 |
19 | AUTHOR: str = "Kelvin DeCosta"
20 | """The package author."""
21 |
22 | LICENSE: str = "MIT"
23 | """The package license."""
24 |
--------------------------------------------------------------------------------
/src/utils.py:
--------------------------------------------------------------------------------
1 | """This module defines utility functions that are used across the package."""
2 |
3 | from os import system, name
4 | import shutil
5 |
6 | import numpy as np
7 | from PIL import Image
8 | from sty import ef, rs
9 |
10 |
11 | def clear_screen():
12 | """Clears the terminal console."""
13 | # Windows systems
14 | if name == "nt":
15 | _ = system("cls")
16 | # Unix systems
17 | else:
18 | _ = system("clear")
19 |
20 |
21 | def embolden(text):
22 | """Modifies text to appear in a bold typeface,
23 | using [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).
24 |
25 | Args:
26 | text (str): The subject text.
27 |
28 | Returns:
29 | str: The text in a bold typeface.
30 | """
31 | return f"{ef.bold}{text}{rs.bold_dim}"
32 |
33 |
34 | def ensure_rgb(image):
35 | """Usually converts any [Pillow](https://python-pillow.org/)
36 | `image` to its equivalent in the `RGB` mode.
37 |
38 | Args:
39 | image (PIL.Image.Image): The subject image.
40 |
41 | Returns:
42 | PIL.Image.Image: The image in the `RGB` mode.
43 | """
44 | # If the image has a color palette,
45 | # convert to the `RGBA` mode.
46 | if image.mode == "P":
47 | image = image.convert("RGBA")
48 |
49 | # If the image is in `RGBA` mode,
50 | # create a white background.
51 | if image.mode == "RGBA":
52 | temp = Image.new("RGB", image.size, (255, 255, 255))
53 | temp.paste(image, mask=image.split()[3])
54 | image = temp
55 |
56 | # Convert to `RGB` mode
57 | return image.convert("RGB")
58 |
59 |
60 | def italicize(text):
61 | """Modifies text to appear in italics,
62 | using [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).
63 |
64 | Args:
65 | text (str): The subject text.
66 |
67 | Returns:
68 | str: The text in italics.
69 | """
70 | return f"{ef.italic}{text}{rs.italic}"
71 |
72 |
73 | def submatrices(matrix, shape):
74 | """Returns a rolling window view of a `matrix`, without overlapping,
75 | given the `shape` of the window.
76 |
77 | Args:
78 | matrix (numpy.ndarray): The subject matrix.
79 | shape (Tuple[int, int]): The `
` and `` of the window.
80 |
81 | Returns:
82 | numpy.ndarray: The rolling window view of the matrix.
83 |
84 | Note:
85 | This operation doesn't account for the loss of border elements.
86 | """
87 | # Extract strides and shapes for calculation.
88 | mat_hs, mat_ws = matrix.strides[:2]
89 | mat_h, mat_w = matrix.shape[:2]
90 | ker_h, ker_w = shape
91 |
92 | # View `matrix` according to new strides and shape.
93 | return np.lib.stride_tricks.as_strided(
94 | matrix,
95 | (1 + (mat_h - ker_h) // ker_h, 1 + (mat_w - ker_w) // ker_w, ker_h, ker_w)
96 | + matrix.shape[2:],
97 | strides=(ker_h * mat_hs, ker_w * mat_ws, mat_hs, mat_ws) + matrix.strides[2:],
98 | )
99 |
100 |
101 | def terminal_size():
102 | """Returns the size of the terminal window.
103 |
104 | Returns:
105 | (Tuple[int, int]): The `` and ``
106 | of the terminal window in characters.
107 |
108 | Note:
109 | When used while piping,
110 | this function usually returns the default terminal size, `(24, 80)`.
111 | """
112 | return shutil.get_terminal_size()[::-1]
113 |
114 |
115 | __all__ = [
116 | "clear_screen",
117 | "embolden",
118 | "ensure_rgb",
119 | "italicize",
120 | "submatrices",
121 | "terminal_size",
122 | ]
123 |
--------------------------------------------------------------------------------