How it works
// 01 DPI and pixel density
The image is drawn to an offscreen canvas sized to the target column count. Each cell of the grid corresponds to one output character, so a 120-column render at a 2:1 character aspect ratio samples a 120 by (60 times image height over width) pixel block. Averaging the pixels inside each cell gives a single brightness value per cell.
// 02 Bleed and cut tolerance
Luminance is calculated with the Rec. 709 weights (0.2126 R, 0.7152 G, 0.0722 B), which matches how human vision perceives brightness across colors. A naive average of RGB would make pure red look as dark as pure blue, which is wrong. The resulting 0 to 255 value is mapped to an index in the intensity ramp, and that character is written to the output grid.
// 03 Safe zone and trim accuracy
Character aspect ratio matters. Most monospace fonts render about twice as tall as they are wide, so the canvas sampling grid is half as tall as it is wide to keep the output image from stretching vertically. The widget accounts for this automatically based on the font metrics measured at runtime, so the ASCII portrait holds the same proportions as the source photo.
// why this exists
I can turn brand imagery into chrome
ASCII art looks like a joke until you see what it can do for a brand. A photograph rendered as dense terminal characters keeps the image legible while stripping out everything that would make it feel like stock. Drop a photo into this widget and it comes back as a grid of characters, sized to the viewport, ready to screenshot or paste into a header.
The technique is old. It comes from the era when the only display you had was a monospaced character grid and the only way to show a face was to pick characters whose ink coverage approximated the brightness of the pixels behind them. The grammar has not changed. What changed is that a modern browser can resample an 8-megapixel image into a 120-column grid in a few milliseconds, which means the conversion can happen live as you drag the slider for character density.
The widget accepts any JPEG, PNG, or WebP. The image is drawn to an offscreen canvas, downsampled to the chosen column count, converted to grayscale using the standard Rec. 709 luminance weights, and then mapped character-by-character through an intensity ramp. The ramp runs from the lightest characters (space, period, apostrophe) to the heaviest (at sign, percent, hash). Pick a sparser ramp for a cleaner look. Pick a denser ramp for a photograph that still reads as a photograph.
You can copy the rendered ASCII as plain text, copy it as a styled HTML block, or download a PNG of the text rendered in a monospace face. The PNG path uses the same offscreen canvas that produced the ASCII, which means the output is crisp at any scale. The file is small because it is mostly flat color.
I use this for build log headers, for social post art, and for brand moments where the subject matters but the photo cannot look like a photo. It is free. It runs in the browser. No image leaves your machine.
Frequently asked questions
Does my photo get uploaded anywhere?
No. The entire conversion happens in the browser. The file never leaves your device.
What photos work best for ASCII conversion?
High contrast subjects with a clean background. Faces work, product shots work, landscapes work if the sky is not a blown-out gradient. Low contrast photos lose detail fast.
Why do my ASCII portraits look stretched?
Your monospace font has a non-standard aspect ratio. The widget measures the ratio at runtime and corrects the sampling grid. If the output still looks tall, switch to a character density above 80 columns.
Can I change the character ramp?
Yes. The widget ships with three ramps: minimal (10 characters), classic (32 characters), and dense (65 characters). A denser ramp preserves more tonal detail at the cost of visual busyness.
How is brightness calculated?
Rec. 709 luminance weights: 0.2126 R, 0.7152 G, 0.0722 B. That matches how human vision perceives brightness across different colors.
What resolution should I use for printed ASCII art?
For print, target 200 to 300 columns and render the PNG at 300 dpi. The file will be large but the characters stay crisp.
Can I use this commercially?
Yes. The output is derived from your own photo. Michael's widget does not claim any rights to your input or output.
Why does my ASCII render look muddy in dark areas?
Your image has crushed blacks. Raise the shadows in your photo editor before converting, or switch to a denser character ramp that has more gradations at the dark end.
Is there a way to add color?
Not in this version. The output is pure grayscale brightness mapped to characters. Colorized ASCII is on the list for a future revision.