Created
April 24, 2026 14:14
-
-
Save drscotthawley/cbd2383b7de420d8986c894cf1b95333 to your computer and use it in GitHub Desktop.
Prints an ASCII-character version of an image.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #! /usr/bin/env python3 | |
| # Usage: img2ascii <img_file> <col_width> | |
| from PIL import Image | |
| import numpy as np | |
| ASCII_CHARS = np.array(list( | |
| " .:-=+*#%@" | |
| )) | |
| # simpler ramp often looks better than huge ones | |
| def rescale(pixels, low=2, high=98): | |
| # percentile-based contrast stretch (prevents blowout) | |
| lo = np.percentile(pixels, low) | |
| hi = np.percentile(pixels, high) | |
| pixels = np.clip(pixels, lo, hi) | |
| return (pixels - lo) / (hi - lo) * 255 | |
| def image_to_ascii(path, width=140, gamma=1.2, invert=False): | |
| img = Image.open(path).convert("L") | |
| aspect_ratio = img.height / img.width | |
| height = int(aspect_ratio * width * 0.55) | |
| img = img.resize((width, height)) | |
| pixels = np.array(img).astype(float) | |
| # 🔑 key: percentile stretch instead of min/max | |
| pixels = rescale(pixels, 3, 97) | |
| # gamma correction (controls brightness distribution) | |
| pixels = 255 * ((pixels / 255) ** gamma) | |
| if invert: | |
| pixels = 255 - pixels | |
| indices = (pixels / 255 * (len(ASCII_CHARS) - 1)).astype(int) | |
| ascii_img = ASCII_CHARS[indices] | |
| return "\n".join("".join(row) for row in ascii_img) | |
| if __name__ == "__main__": | |
| import sys | |
| print(image_to_ascii(sys.argv[1], width=int(sys.argv[2]), gamma=1.3)) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Totally generated by ChatGPT. Not actually "mine". Though we did iterate over a few versions to get it the way I liked it.