ASCII Art from Image, Explained
After reading this you will understand how a color photograph becomes a grid of text characters, how to pick a character ramp and width, and why the same picture can look sharp or muddy depending on a handful of numbers.
What ASCII art actually is
ASCII art replaces each region of an image with a single text character chosen by how bright that region is. A dark patch becomes a heavy character like @ or #. A bright patch becomes a light character like . or a space. Line up thousands of these characters in a grid and your eye reassembles them into a recognizable picture, the same way newspaper halftones fool you from across the room.
The trick works because monospaced text is itself a grid. Every character occupies the same cell, roughly twice as tall as it is wide in most fonts. If you map one cell of the image to one character, and you choose the character by brightness, you get a low-resolution but faithful rendering. A 100-character-wide result holds 100 tonal decisions per row, which is enough for a face or a logo to read clearly.
This tool does the whole conversion in your browser. It samples the image, measures brightness per cell, maps each brightness to a character from a ramp, and optionally paints each character with the source color for ANSI or PNG output.
When it helps and when it does not
ASCII art earns its place where you need an image inside a text-only channel: a terminal banner, a README file, a code comment, an email signature, a chat message. It also compresses drastically. A photo that is 500 KB as a JPEG might become 6 KB of plain text at 120 columns.
It is a poor choice when detail matters. Text at 100 columns gives you at most 100 tonal samples horizontally, so fine features vanish. Faces work because they are mostly large tonal blocks. Dense text in a photographed sign, a barcode, or a QR code will not survive. For machine-readable codes use the QR code generator and reader or the barcode generator instead, which preserve exact modules.
Pick images with strong contrast and a clear subject. A portrait against a plain background converts far better than a busy landscape, because ASCII has so few brightness levels to spend.
The brightness formula
Each output cell covers a block of pixels. The tool averages those pixels into one color, then converts that color to a single brightness value. The standard weighting uses luma, which reflects how the human eye responds more to green than to red or blue.
Here R, G and B are the averaged channel values in the range 0 to 255, and L is the resulting brightness, also 0 to 255. Pure white is L = 255. Pure green scores L = 0.587 \times 255 \approx 150, much brighter than pure blue at L = 0.114 \times 255 \approx 29.
Once you have L, you index into the character ramp. If the ramp has N characters ordered from darkest to lightest, the chosen index is:
The floor function rounds down to a whole number. Dividing L by 256 gives a fraction from 0 up to just under 1, and multiplying by N spreads that fraction across the ramp positions. Inverted mode simply reverses the ramp, so dark input produces light characters, which is what you want for a light-on-dark terminal.
Choosing width and aspect
Width is the count of characters per row. It sets everything else. If the source is 800 pixels wide and you ask for 100 columns, each column samples a block 8 pixels wide.
The height needs a correction. Characters are taller than they are wide, typically in a ratio near 2:1. If you sampled square blocks, the output would look stretched vertically. So the tool divides the row count by a factor near 2. For an 800 \times 600 image at 100 columns:
That produces a grid of 100 \times 37 = 3700 characters that preserves the original proportions on screen. Skip the aspect correction and the same subject looks about twice as tall as it should.
Reproducing the demo defaults
The demo button converts the default sample image using the standard 10-character ramp @%#*+=-:. at the default width. Follow the numbers for one cell.
- Take a cell whose averaged color is a mid gray,
R = 120,G = 120,B = 120. - Compute brightness: L = 0.299(120) + 0.587(120) + 0.114(120) = 120, since the weights sum to
1. - The ramp has N = 10 characters, darkest first. Index i = \lfloor \frac{120}{256} \times 10 \rfloor = \lfloor 4.6875 \rfloor = 4.
- Position
4in@%#*+=-:.(space) is+, so this cell prints a+. - A near-black cell at L = 10 gives i = \lfloor 0.39 \rfloor = 0, printing
@. A near-white cell at L = 250 gives i = \lfloor 9.77 \rfloor = 9, printing a space.
Every cell runs the same four arithmetic steps. A 100 \times 37 grid is 3700 repetitions of this calculation.
How brightness maps to characters
The mapping is a staircase. Each ramp character owns an equal slice of the 0 to 255 range. With 10 characters, each slice is 256 / 10 \approx 25.6 brightness units wide.
| Index | Character | Brightness range | Example L |
|---|---|---|---|
| 0 | @ | 0 to 25 | 10 |
| 2 | # | 51 to 76 | 60 |
| 4 | + | 102 to 127 | 120 |
| 6 | - | 153 to 179 | 165 |
| 9 | (space) | 230 to 255 | 250 |
Reading the result
Judge output by squinting or stepping back from the screen. At normal reading distance you see characters. From two meters away, or with your eyes half closed, the tonal pattern resolves into the image. If it does not resolve, the usual causes are too few columns, a flat image with little contrast, or a ramp that is too short.
Color output changes the game. In ANSI or PNG mode the character shape carries brightness while the color carries hue. That lets a red apple read as red even though the character is chosen purely from brightness. Plain text output has no color, so it relies entirely on the shape of the characters and the ramp ordering.
Common mistakes
Forgetting the aspect correction is the single most common error. If your output looks stretched tall, the row count was not divided by the character height ratio. A subject that should be circular will appear as an ellipse about twice as tall as wide.
A second mistake is choosing a ramp whose characters are not ordered by ink density. If . appears before @ in the ramp but the ramp is meant to run dark to light, tones invert in patches and the image looks scrambled. Order matters: darkest first for normal mode, or use inverted mode to flip it.
A third is pushing width too high for the display. At 300 columns the text wraps or shrinks below readability in a chat window. Match the width to where the art will live. Terminals are commonly 80 columns, so 72 to 80 is a safe default for pasting into one.
Finally, low-contrast sources produce mush. If every cell lands near L = 128, every character is the same middle ramp glyph and no shape emerges. Raise contrast before converting, or accept that flat images do not translate well. The dithering tool takes the opposite approach for a similar problem, spreading tonal error across neighboring pixels rather than picking one character per block.
Related tools
If you are building text-mode or pixel assets, a few neighbors help. The placeholder image generator produces sized stand-in images with labels, handy for testing a layout before you have final art. The sprite sheet generator and splitter packs many small images into one grid or slices a grid apart, which pairs naturally with tile-based text art.
Frequently asked questions
Why does my ASCII art look stretched vertically?
The row count was not corrected for character shape. Monospaced characters are about twice as tall as wide, so the number of rows should be roughly half of what a square grid would give. Dividing by a factor near 2 fixes the proportions.
How many characters should the ramp have?
Between 8 and 12 works for most photos. Fewer than 5 gives harsh banding because each character covers a wide brightness slice. More than 15 gives smoother gradients but the individual steps carry so little contrast that they add little at typical widths.
Does color output still use the brightness formula?
Yes. The character is always chosen by brightness L. Color is applied afterward by painting the chosen character in the cell's average color, so shape and hue come from two separate calculations.
Can I convert a QR code to ASCII and still scan it?
Usually not. ASCII conversion averages blocks of pixels, which blurs the sharp module edges a scanner needs. Generate or read codes with the dedicated QR and barcode tools instead of round-tripping them through text.
Is my image sent anywhere?
No. Everything runs locally in your browser, and your images are never uploaded to any server. The conversion is pure arithmetic on pixel values, so it needs no network.