ansi-pixel 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ansi_pixel-0.2.0/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- ansi_pixel-0.2.0/.github/pull_request_template.md +24 -0
- ansi_pixel-0.2.0/.github/workflows/ci.yml +86 -0
- ansi_pixel-0.2.0/.github/workflows/publish.yml +76 -0
- ansi_pixel-0.2.0/.github/workflows/release-binaries.yml +114 -0
- ansi_pixel-0.2.0/.gitignore +31 -0
- ansi_pixel-0.2.0/IMPROVEMENTS.md +160 -0
- ansi_pixel-0.2.0/LICENSE +21 -0
- ansi_pixel-0.2.0/PKG-INFO +304 -0
- ansi_pixel-0.2.0/README.md +269 -0
- ansi_pixel-0.2.0/TASK_PLAN.md +101 -0
- ansi_pixel-0.2.0/docs/homebrew.md +79 -0
- ansi_pixel-0.2.0/img_to_ansi.py +15 -0
- ansi_pixel-0.2.0/logo.png +0 -0
- ansi_pixel-0.2.0/main.py +16 -0
- ansi_pixel-0.2.0/packaging/homebrew/ansi-pixel.rb +48 -0
- ansi_pixel-0.2.0/pyproject.toml +105 -0
- ansi_pixel-0.2.0/requirements.txt +1 -0
- ansi_pixel-0.2.0/rules.md +112 -0
- ansi_pixel-0.2.0/src/ansi_pixel/__init__.py +49 -0
- ansi_pixel-0.2.0/src/ansi_pixel/cli.py +299 -0
- ansi_pixel-0.2.0/src/ansi_pixel/converter.py +374 -0
- ansi_pixel-0.2.0/src/ansi_pixel/exporters/__init__.py +100 -0
- ansi_pixel-0.2.0/src/ansi_pixel/exporters/ansi.py +19 -0
- ansi_pixel-0.2.0/src/ansi_pixel/exporters/code.py +44 -0
- ansi_pixel-0.2.0/src/ansi_pixel/exporters/html.py +145 -0
- ansi_pixel-0.2.0/src/ansi_pixel/exporters/markdown.py +18 -0
- ansi_pixel-0.2.0/src/ansi_pixel/optimizer.py +153 -0
- ansi_pixel-0.2.0/src/ansi_pixel/py.typed +1 -0
- ansi_pixel-0.2.0/src/ansi_pixel/render.py +57 -0
- ansi_pixel-0.2.0/tests/test_cli.py +415 -0
- ansi_pixel-0.2.0/tests/test_converter.py +259 -0
- ansi_pixel-0.2.0/tests/test_exporters.py +161 -0
- ansi_pixel-0.2.0/tests/test_optimizer.py +149 -0
- ansi_pixel-0.2.0/tests/test_packaging.py +61 -0
- ansi_pixel-0.2.0/tests/test_render.py +205 -0
- ansi_pixel-0.2.0/uv.lock +805 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Issue
|
|
3
|
+
about: Report a bug, suggest an improvement, or ask a question about ansi-pixel
|
|
4
|
+
title: ""
|
|
5
|
+
labels: ""
|
|
6
|
+
assignees: ""
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Description
|
|
10
|
+
|
|
11
|
+
<!-- What would you like to report or discuss? -->
|
|
12
|
+
|
|
13
|
+
## Details
|
|
14
|
+
|
|
15
|
+
<!-- For bugs, include steps to reproduce and the expected behavior. For ideas, describe the proposed change and the problem it solves. -->
|
|
16
|
+
|
|
17
|
+
- Input image or a minimal example:
|
|
18
|
+
- Command used:
|
|
19
|
+
- Expected behavior:
|
|
20
|
+
- Actual behavior or proposed solution:
|
|
21
|
+
|
|
22
|
+
## Environment
|
|
23
|
+
|
|
24
|
+
<!-- Complete these fields when relevant. -->
|
|
25
|
+
|
|
26
|
+
- OS:
|
|
27
|
+
- Python version:
|
|
28
|
+
- Pillow version:
|
|
29
|
+
|
|
30
|
+
## Additional context
|
|
31
|
+
|
|
32
|
+
<!-- Include a traceback, screenshot, or sample image when useful. -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this pull request change, and why? -->
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
-
|
|
8
|
+
|
|
9
|
+
## Testing
|
|
10
|
+
|
|
11
|
+
<!-- Include the command(s) you ran and the result. -->
|
|
12
|
+
|
|
13
|
+
- [ ] Tested locally
|
|
14
|
+
- [ ] Updated documentation, if needed
|
|
15
|
+
- [ ] Added or updated tests, if needed
|
|
16
|
+
|
|
17
|
+
## Screenshots or sample output
|
|
18
|
+
|
|
19
|
+
<!-- Include before/after output when the change affects rendering or CLI behavior. -->
|
|
20
|
+
|
|
21
|
+
## Checklist
|
|
22
|
+
|
|
23
|
+
- [ ] The change is focused and ready for review.
|
|
24
|
+
- [ ] I have not committed generated output files.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- "release/**"
|
|
8
|
+
pull_request:
|
|
9
|
+
branches:
|
|
10
|
+
- main
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
lint:
|
|
19
|
+
name: Code Quality & Linting
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- name: Check out repository
|
|
23
|
+
uses: actions/checkout@v4
|
|
24
|
+
|
|
25
|
+
- name: Set up Python 3.12
|
|
26
|
+
uses: actions/setup-python@v5
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
cache: "pip"
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install --upgrade pip
|
|
34
|
+
python -m pip install -e ".[dev]"
|
|
35
|
+
|
|
36
|
+
- name: Check formatting with Ruff
|
|
37
|
+
run: ruff format --check src tests
|
|
38
|
+
|
|
39
|
+
- name: Run Ruff linter
|
|
40
|
+
run: ruff check src tests
|
|
41
|
+
|
|
42
|
+
- name: Run Mypy strict type checking
|
|
43
|
+
run: mypy src tests
|
|
44
|
+
|
|
45
|
+
test:
|
|
46
|
+
name: Test (${{ matrix.os }} - Py ${{ matrix.python-version }})
|
|
47
|
+
needs: lint
|
|
48
|
+
runs-on: ${{ matrix.os }}
|
|
49
|
+
strategy:
|
|
50
|
+
fail-fast: false
|
|
51
|
+
matrix:
|
|
52
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
53
|
+
python-version:
|
|
54
|
+
- "3.9"
|
|
55
|
+
- "3.10"
|
|
56
|
+
- "3.11"
|
|
57
|
+
- "3.12"
|
|
58
|
+
- "3.13"
|
|
59
|
+
- "3.14-dev"
|
|
60
|
+
include:
|
|
61
|
+
# Allow experimental Python 3.14-dev pre-release builds to fail without blocking CI
|
|
62
|
+
- python-version: "3.14-dev"
|
|
63
|
+
experimental: true
|
|
64
|
+
continue-on-error: ${{ matrix.experimental || false }}
|
|
65
|
+
|
|
66
|
+
steps:
|
|
67
|
+
- name: Check out repository
|
|
68
|
+
uses: actions/checkout@v4
|
|
69
|
+
|
|
70
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
71
|
+
uses: actions/setup-python@v5
|
|
72
|
+
with:
|
|
73
|
+
python-version: ${{ matrix.python-version }}
|
|
74
|
+
allow-prereleases: true
|
|
75
|
+
cache: "pip"
|
|
76
|
+
|
|
77
|
+
- name: Install package and dependencies
|
|
78
|
+
run: |
|
|
79
|
+
python -m pip install --upgrade pip
|
|
80
|
+
python -m pip install -e ".[dev]"
|
|
81
|
+
|
|
82
|
+
- name: Run Pytest test suite
|
|
83
|
+
run: pytest
|
|
84
|
+
|
|
85
|
+
- name: Verify CLI console script entry point
|
|
86
|
+
run: ansi-pixel --help
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
target:
|
|
10
|
+
description: "Publish target"
|
|
11
|
+
type: choice
|
|
12
|
+
required: true
|
|
13
|
+
default: "pypi"
|
|
14
|
+
options:
|
|
15
|
+
- pypi
|
|
16
|
+
- testpypi
|
|
17
|
+
|
|
18
|
+
concurrency:
|
|
19
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
build:
|
|
24
|
+
name: Build distribution packages
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Check out repository
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Set up Python 3.12
|
|
31
|
+
uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.12"
|
|
34
|
+
cache: "pip"
|
|
35
|
+
|
|
36
|
+
- name: Install build tools
|
|
37
|
+
run: |
|
|
38
|
+
python -m pip install --upgrade pip
|
|
39
|
+
python -m pip install build twine
|
|
40
|
+
|
|
41
|
+
- name: Build sdist and wheel
|
|
42
|
+
run: python -m build
|
|
43
|
+
|
|
44
|
+
- name: Verify package distributions with twine
|
|
45
|
+
run: twine check --strict dist/*
|
|
46
|
+
|
|
47
|
+
- name: Upload distribution packages
|
|
48
|
+
uses: actions/upload-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: python-package-distributions
|
|
51
|
+
path: dist/
|
|
52
|
+
retention-days: 7
|
|
53
|
+
|
|
54
|
+
publish:
|
|
55
|
+
name: Publish to ${{ github.event.inputs.target || 'pypi' }}
|
|
56
|
+
needs: build
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
environment:
|
|
59
|
+
name: ${{ github.event.inputs.target || 'pypi' }}
|
|
60
|
+
url: ${{ (github.event.inputs.target == 'testpypi') && 'https://test.pypi.org/p/ansi-pixel' || 'https://pypi.org/p/ansi-pixel' }}
|
|
61
|
+
permissions:
|
|
62
|
+
id-token: write
|
|
63
|
+
contents: read
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Download distribution packages
|
|
67
|
+
uses: actions/download-artifact@v4
|
|
68
|
+
with:
|
|
69
|
+
name: python-package-distributions
|
|
70
|
+
path: dist/
|
|
71
|
+
|
|
72
|
+
- name: Publish package distributions to PyPI
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
74
|
+
with:
|
|
75
|
+
repository-url: ${{ (github.event.inputs.target == 'testpypi') && 'https://test.pypi.org/legacy/' || '' }}
|
|
76
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
name: Release Standalone Binaries
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*.*.*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
inputs:
|
|
9
|
+
tag_name:
|
|
10
|
+
description: "Release tag (optional, e.g. v0.2.0)"
|
|
11
|
+
required: false
|
|
12
|
+
type: string
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build-binaries:
|
|
20
|
+
name: Build (${{ matrix.target }})
|
|
21
|
+
runs-on: ${{ matrix.os }}
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
include:
|
|
26
|
+
- target: Linux x86_64
|
|
27
|
+
os: ubuntu-latest
|
|
28
|
+
binary_name: ansi-pixel-linux-x86_64
|
|
29
|
+
output_file: dist/ansi-pixel-linux-x86_64
|
|
30
|
+
- target: macOS Apple Silicon (ARM64)
|
|
31
|
+
os: macos-latest
|
|
32
|
+
binary_name: ansi-pixel-darwin-arm64
|
|
33
|
+
output_file: dist/ansi-pixel-darwin-arm64
|
|
34
|
+
- target: macOS Intel (x86_64)
|
|
35
|
+
os: macos-13
|
|
36
|
+
binary_name: ansi-pixel-darwin-x86_64
|
|
37
|
+
output_file: dist/ansi-pixel-darwin-x86_64
|
|
38
|
+
- target: Windows x86_64
|
|
39
|
+
os: windows-latest
|
|
40
|
+
binary_name: ansi-pixel-windows-x86_64
|
|
41
|
+
output_file: dist/ansi-pixel-windows-x86_64.exe
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Check out repository
|
|
45
|
+
uses: actions/checkout@v4
|
|
46
|
+
|
|
47
|
+
- name: Set up Python 3.12
|
|
48
|
+
uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.12"
|
|
51
|
+
cache: "pip"
|
|
52
|
+
|
|
53
|
+
- name: Install dependencies and PyInstaller
|
|
54
|
+
run: |
|
|
55
|
+
python -m pip install --upgrade pip
|
|
56
|
+
python -m pip install pyinstaller .
|
|
57
|
+
|
|
58
|
+
- name: Build standalone executable with PyInstaller
|
|
59
|
+
run: pyinstaller --onefile --clean --name ${{ matrix.binary_name }} main.py
|
|
60
|
+
|
|
61
|
+
- name: Smoke test executable (Linux / macOS)
|
|
62
|
+
if: runner.os != 'Windows'
|
|
63
|
+
run: |
|
|
64
|
+
./${{ matrix.output_file }} --help
|
|
65
|
+
./${{ matrix.output_file }} --version
|
|
66
|
+
|
|
67
|
+
- name: Smoke test executable (Windows)
|
|
68
|
+
if: runner.os == 'Windows'
|
|
69
|
+
run: |
|
|
70
|
+
.\${{ matrix.output_file }} --help
|
|
71
|
+
.\${{ matrix.output_file }} --version
|
|
72
|
+
|
|
73
|
+
- name: Upload binary artifact
|
|
74
|
+
uses: actions/upload-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: ${{ matrix.binary_name }}
|
|
77
|
+
path: ${{ matrix.output_file }}
|
|
78
|
+
retention-days: 7
|
|
79
|
+
|
|
80
|
+
release:
|
|
81
|
+
name: Create GitHub Release & Upload Assets
|
|
82
|
+
needs: build-binaries
|
|
83
|
+
runs-on: ubuntu-latest
|
|
84
|
+
permissions:
|
|
85
|
+
contents: write
|
|
86
|
+
|
|
87
|
+
steps:
|
|
88
|
+
- name: Check out repository
|
|
89
|
+
uses: actions/checkout@v4
|
|
90
|
+
|
|
91
|
+
- name: Download all binary artifacts
|
|
92
|
+
uses: actions/download-artifact@v4
|
|
93
|
+
with:
|
|
94
|
+
path: release-assets
|
|
95
|
+
merge-multiple: true
|
|
96
|
+
|
|
97
|
+
- name: Generate SHA256 checksums
|
|
98
|
+
run: |
|
|
99
|
+
cd release-assets
|
|
100
|
+
sha256sum ansi-pixel-* > checksums.txt
|
|
101
|
+
echo "Generated checksums:"
|
|
102
|
+
cat checksums.txt
|
|
103
|
+
|
|
104
|
+
- name: Publish GitHub Release
|
|
105
|
+
if: startsWith(github.ref, 'refs/tags/v') || (github.event.inputs.tag_name != '')
|
|
106
|
+
uses: softprops/action-gh-release@v2
|
|
107
|
+
with:
|
|
108
|
+
tag_name: ${{ github.event.inputs.tag_name || github.ref_name }}
|
|
109
|
+
files: |
|
|
110
|
+
release-assets/ansi-pixel-*
|
|
111
|
+
release-assets/checksums.txt
|
|
112
|
+
generate_release_notes: true
|
|
113
|
+
draft: false
|
|
114
|
+
prerelease: false
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
env/
|
|
11
|
+
|
|
12
|
+
# Environment variables
|
|
13
|
+
.env
|
|
14
|
+
|
|
15
|
+
# PyInstaller / Build artifacts
|
|
16
|
+
build/
|
|
17
|
+
dist/
|
|
18
|
+
*.spec
|
|
19
|
+
*.egg-info/
|
|
20
|
+
|
|
21
|
+
# Quality tool caches
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.pytest_cache/
|
|
24
|
+
.ruff_cache/
|
|
25
|
+
|
|
26
|
+
# Output test files
|
|
27
|
+
output.txt
|
|
28
|
+
output.md
|
|
29
|
+
output.py
|
|
30
|
+
*.ans
|
|
31
|
+
repomix-output.md
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# Improvements & Evolution Roadmap (`IMPROVEMENTS.md`)
|
|
2
|
+
|
|
3
|
+
This document identifies all current limitations of `ansi-pixel`, defines real-world use cases, and outlines the technical roadmap to elevate this project into a widely adopted CLI utility and published Python package.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Analysis of Current Limitations & Bugs
|
|
8
|
+
|
|
9
|
+
### 1.1 Inadvertent White Pixel Erasure (Bug)
|
|
10
|
+
|
|
11
|
+
- **Current Behavior**:
|
|
12
|
+
```python
|
|
13
|
+
top_empty = top_a < 128 or (top_r > 245 and top_g > 245 and top_b > 245)
|
|
14
|
+
```
|
|
15
|
+
The script assumes any pixel with $R > 245, G > 245, B > 245$ is background and replaces it with an empty terminal space.
|
|
16
|
+
- **Problem**: In images that legitimately contain white elements (logos, eyes, clouds, text), these regions become transparent voids.
|
|
17
|
+
- **Solution**: Decouple alpha transparency from color filtering. Only transparent pixels ($A < 128$) are empty by default. Provide an optional `--chroma-key <HEX>` or `--trim-bg` flag for users who intentionally want to strip a white/solid background.
|
|
18
|
+
|
|
19
|
+
### 1.2 Dead Code & Broken Border Crop
|
|
20
|
+
|
|
21
|
+
- **Current Behavior**:
|
|
22
|
+
```python
|
|
23
|
+
bg = Image.new("RGBA", img.size, (255, 255, 255, 0))
|
|
24
|
+
bbox = img.getbbox()
|
|
25
|
+
```
|
|
26
|
+
`bg` is allocated and never used. Furthermore, `getbbox()` on an RGBA image only trims where alpha is 0. It does not crop solid white backgrounds.
|
|
27
|
+
- **Solution**: Remove unused variables. If auto-trimming borders is desired, implement a robust bounding-box calculator that detects margin borders against background color or alpha.
|
|
28
|
+
|
|
29
|
+
### 1.3 Bloated ANSI Output (No Sequence Compression)
|
|
30
|
+
|
|
31
|
+
- **Current Behavior**:
|
|
32
|
+
For every single column, the script emits:
|
|
33
|
+
`\033[38;2;{top_r};{top_g};{top_b}m\033[48;2;{bot_r};{bot_g};{bot_b}m▀\033[0m`
|
|
34
|
+
- **Problem**: Every character carries up to 40 bytes of ANSI sequences, even if the entire row has the same color. A $100 \times 50$ output can exceed 150 KB.
|
|
35
|
+
- **Solution**: Implement an **ANSI Sequence Optimizer**:
|
|
36
|
+
- Track current foreground and background colors.
|
|
37
|
+
- Only emit color escape sequences when the color transitions.
|
|
38
|
+
- Omit `\033[0m` resets between consecutive characters, resetting only at end-of-line or when entering a transparent block.
|
|
39
|
+
- Result: 50% to 75% reduction in output size and faster rendering over remote SSH connections.
|
|
40
|
+
|
|
41
|
+
### 1.4 Hardcoded File Overwrites in CWD
|
|
42
|
+
|
|
43
|
+
- **Current Behavior**:
|
|
44
|
+
`main.py` hardcodes file output paths to `./output.txt`, `./output.md`, or `./output.py`.
|
|
45
|
+
- **Problem**: When `ansi-pixel` is installed globally via `pip` or `pipx`, running it inside any project directory will create unwanted files in the user's working folder.
|
|
46
|
+
- **Solution**:
|
|
47
|
+
- Follow standard UNIX CLI conventions: Print directly to `stdout` by default.
|
|
48
|
+
- Provide `-o` / `--output <PATH>` to write to a specific destination file.
|
|
49
|
+
- Provide `-f` / `--format <txt|md|py|js|html>` to specify the format.
|
|
50
|
+
|
|
51
|
+
### 1.5 Suboptimal Pixel Reading Loop
|
|
52
|
+
|
|
53
|
+
- **Current Behavior**:
|
|
54
|
+
Nested Python loops calling `img.getpixel((x, y))` twice per coordinate.
|
|
55
|
+
- **Problem**: `getpixel()` in pure Python has high function-call overhead.
|
|
56
|
+
- **Solution**: Use `img.load()` (direct pixel buffer pointer) or byte arrays, which executes 10x–30x faster.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 2. Real-World Purpose & Practical Applications
|
|
61
|
+
|
|
62
|
+
To make `ansi-pixel` a tool that developers actively seek out and integrate, we target four core use cases:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
┌────────────────────────────────────────────────────────┐
|
|
66
|
+
│ ansi-pixel Real Use Cases │
|
|
67
|
+
└────────────────────────────────────────────────────────┘
|
|
68
|
+
│ │ │
|
|
69
|
+
┌──────────┴────────┐ ┌────────┴────────┐ ┌────────┴────────┐
|
|
70
|
+
│ CLI Tool Banners │ │ Remote Terminal │ │ GitHub README │
|
|
71
|
+
│ & Startup Mascots │ │ Image Preview │ │ & Doc Badges │
|
|
72
|
+
└───────────────────┘ └─────────────────┘ └─────────────────┘
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
1. **CLI Branding & Welcome Screens**:
|
|
76
|
+
- CLI framework authors (FastAPI, Typer, Click, Node.js CLI tools) want branded logos in the console.
|
|
77
|
+
- `ansi-pixel logo.png -f python` generates ready-to-paste Python banner code (`LOGO = "..."`).
|
|
78
|
+
- `ansi-pixel logo.png -f js` generates JavaScript template strings for Node.js / Deno CLIs.
|
|
79
|
+
2. **Headless & SSH Image Previewer**:
|
|
80
|
+
- Developers and sysadmins on remote servers or inside Docker containers lack GUI viewers.
|
|
81
|
+
- Running `ansi-pixel cat.png` provides an immediate visual preview right in their shell.
|
|
82
|
+
- Support streaming from pipes: `curl -sL https://site.com/image.png | ansi-pixel -`.
|
|
83
|
+
3. **Rich & Textual TUI Dashboard Avatars**:
|
|
84
|
+
- Python terminal applications need to display user avatars, status badges, or product icons in terminal user interfaces.
|
|
85
|
+
- Providing an importable Python API (`import ansi_pixel`) allows direct embedding into Rich consoles, Textual widgets, and prompt_toolkit applications.
|
|
86
|
+
4. **GitHub Markdown Colored Art**:
|
|
87
|
+
- Modern GitHub Markdown renders ``ansi` code blocks. `ansi-pixel` produces ready-to-paste ANSI markdown blocks to spice up repository READMEs.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 3. High-Priority Feature Improvements
|
|
92
|
+
|
|
93
|
+
### 3.1 Terminal Dimensions Auto-Detection
|
|
94
|
+
|
|
95
|
+
- Automatically read the user's terminal column width using `shutil.get_terminal_size()`.
|
|
96
|
+
- Default to fitting cleanly within the terminal (e.g. `width = min(terminal_cols, 80)`), eliminating horizontal line-wrapping on small screens while keeping images crisp.
|
|
97
|
+
|
|
98
|
+
### 3.2 Flexible Resampling Filters
|
|
99
|
+
|
|
100
|
+
- Pixel art logos look best with `Image.Resampling.NEAREST` (sharp pixels).
|
|
101
|
+
- Photographs and gradients look best with `Image.Resampling.LANCZOS` or `BILINEAR`.
|
|
102
|
+
- Provide `--filter <nearest|lanczos|bilinear>` (default: `nearest` for small images, `lanczos` for large photos).
|
|
103
|
+
|
|
104
|
+
### 3.3 Color Mode Reductions & Fallbacks
|
|
105
|
+
|
|
106
|
+
- **TrueColor (24-bit)**: `\033[38;2;r;g;bm` (Default).
|
|
107
|
+
- **256-Color (8-bit)**: Maps RGB to the standard xterm 256-color palette for older terminals or restricted SSH sessions.
|
|
108
|
+
- **16-Color (4-bit)**: Basic ANSI colors.
|
|
109
|
+
- **Grayscale / Monochromatic**: For clean ASCII/block aesthetic.
|
|
110
|
+
- **`NO_COLOR` Compliance**: Automatically disable ANSI escape sequences when the `NO_COLOR` environment variable is detected or when redirected to a non-TTY pipe without forced color flags.
|
|
111
|
+
|
|
112
|
+
### 3.4 Extended Exporters
|
|
113
|
+
|
|
114
|
+
- `-f ansi` (default): Pure ANSI escape strings.
|
|
115
|
+
- `-f md`: GitHub-compliant ``ansi` Markdown block.
|
|
116
|
+
- `-f py`: Clean Python snippet (`BANNER = "..."` or list of lines).
|
|
117
|
+
- `-f js`: ES6 JavaScript template literal (`export const banner = \`...\``).
|
|
118
|
+
- `-f html`: HTML `<pre>` block using styled `<span style="color:...;background:...">` for web pages.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 4. Packaging & Distribution Plan
|
|
123
|
+
|
|
124
|
+
### Where to Release:
|
|
125
|
+
|
|
126
|
+
| Platform | Channel | Install Method | Target Audience |
|
|
127
|
+
| :------------------ | :--------------------- | :-------------------------------------------------------------------------------- | :-------------------------------------- |
|
|
128
|
+
| **PyPI** | Official Python Index | `pip install ansi-pixel`<br>`pipx run ansi-pixel`<br>`uv tool install ansi-pixel` | Python developers, CLI users, sysadmins |
|
|
129
|
+
| **GitHub Releases** | Binaries & Assets | Download pre-built binary | Users without Python runtime installed |
|
|
130
|
+
| **Homebrew Tap** | macOS / Linux packages | `brew install senuradesilva/tap/ansi-pixel` | Mac / Linux terminal power users |
|
|
131
|
+
| **Docker / GHCR** | Container image | `docker run --rm ghcr.io/senuradesilva/ansi-pixel` | CI/CD automation & pipeline inspection |
|
|
132
|
+
|
|
133
|
+
### How to Package:
|
|
134
|
+
|
|
135
|
+
1. **Modern PEP 621 Standard**:
|
|
136
|
+
- Adopt `pyproject.toml` with `hatchling` build backend.
|
|
137
|
+
- Declare entrypoint script: `ansi-pixel = "ansi_pixel.cli:main"`.
|
|
138
|
+
2. **Source Code Structure**:
|
|
139
|
+
```
|
|
140
|
+
ansi-pixel/
|
|
141
|
+
├── pyproject.toml
|
|
142
|
+
├── README.md
|
|
143
|
+
├── LICENSE
|
|
144
|
+
├── src/
|
|
145
|
+
│ └── ansi_pixel/
|
|
146
|
+
│ ├── __init__.py
|
|
147
|
+
│ ├── cli.py
|
|
148
|
+
│ ├── converter.py
|
|
149
|
+
│ ├── optimizer.py
|
|
150
|
+
│ ├── exporters.py
|
|
151
|
+
│ └── py.typed
|
|
152
|
+
└── tests/
|
|
153
|
+
├── test_cli.py
|
|
154
|
+
├── test_converter.py
|
|
155
|
+
├── test_optimizer.py
|
|
156
|
+
└── test_exporters.py
|
|
157
|
+
```
|
|
158
|
+
3. **Automated Publishing via GitHub Actions**:
|
|
159
|
+
- Configure **PyPI Trusted Publishing (OIDC)**: No manual API tokens or passwords needed.
|
|
160
|
+
- Pushing a new git tag (e.g., `git tag v0.2.0 && git push origin v0.2.0`) builds the distribution wheels and securely publishes directly to PyPI.
|
ansi_pixel-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Senura Hesara
|
|
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.
|