ASCII Silhouettify
[ About | Example | Galleries | Install | Uninstall | Options | Algorithm ]
ASCII Silhouettify is an app that converts images into ASCII silhouettes, a style of ASCII art distinguished by uniformly filled geometric shapes rather than lines or textures. For input, the app expects flat graphics—visuals with minimalistic, high-contrast forms lacking dimensional depth, such as logos, banners, and pixel art. It cannot handle photographs because it does not render shading, highlights, shadows, or gradients.
ASCII Silhouettify restricts itself to the 95 printable ASCII characters, the medium of traditional ASCII artists, as opposed to the line and block characters prevalent in ANSI art or the copious Unicode characters of kaomoji. However, based on user configuration, the app outputs monochrome plain text, text colored with ANSI escape sequences, HTML with or without color, or Neofetch ASCII art format.
ASCII Silhouettify is a desktop app accessible from a browser and from the command-line.
Here is the output of Neofetch under an instance of Ubuntu:
For optimal ASCII art, we obtain a high-resolution image of the Ubuntu logo from the web, and we scale it to the size we want it to appear in the console:
We run it through the command-line version of ASCII Silhouettify:
By default, ASCII Silhouettify generates text colored with ANSI escape sequences. With the -o
flag, we can direct the output to a file that Neofetch will display. But Neofetch inserts a wide margin between ANSI art and the OS metrics. To prevent this, we‘ll use Neofetch‘s custom ASCII art file format:
The first line of the output file is a list of color indices. The successive lines contain the encoded image:
In a text editor, we copy the first line to the clipboard, and then we remove it.
We invoke Neofetch with the following command, pasting in the value we stored in the clipboard:
Neofetch is a bash script. To make the change permanent, we replace the following part of the script, again using the value we stored in the clipboard.
For comparison, here is the original logo overlaid on the generated result:
Note how the algorithm selects the largest characters that fit within the outlines of each colored region.
For more examples, click on one of the buttons below.
The command-line version of ASCII Silhouettify is a Node.js application. If you don't have Node.js installed on your system, follow the steps described here. On macOS and Linux, ensure that npm
is set up for global installs without using the root user by following the steps detailed here and here.
To install, issue this command:
npm install -g ascii-silhouettify
To uninstall, issue this command:
npm uninstall -g ascii-silhouettify
The browser version and the command-line version support the same set of options. In the command-line version, the -h
flag outputs a message that summarizes the information below.
ASCII Silhouettify can convert multiple images at the same time. It supports png
, svg
, jpg
, webp
, gif
, tif
, heif
, avif
, and pdf
image formats. The command-line version‘s -i
flag accepts various filename pattern-matching rules (see the help message for details). The input images should have black or transparent backgrounds.
ASCII Silhouettify can output plane or ANSI-colored text, monospaced text in HTML format, or Neofetch‘s custom ASCII art format. The latter is limited to six colors of the 256-color extended ANSI palette.
By default, ASCII Silhouettify uses a palette of 240 colors from the 256-color extended ANSI palette, excluding the 16-color standard ANSI palette, as it is often redefined in modern terminal emulators. However, users have the option to select the first 8 colors of the standard ANSI palette, the full 16-color standard ANSI palette, the full 256-color extended ANSI palette, or stick with the default 240-color palette.
The user can specify the maximum number of colors to appear in the output, not counting the presumably black background. The default is 255. Monochrome mode effectively sets this to one. For Neofetch‘s custom ASCII art format, it defaults to six, the maximum number of colors supported by that format.
When viewed in a terminal emulator, the aspect ratio of the generated ASCII art depends on the font, font size, line height, and the rounding rules for character dimensions. To optimize it, capture an image of text in the terminal, and measure the size of each monospaced character in pixels, including the space between lines:
Plug the values into the following formulae to determine font size and line height settings.
$\text{font size} = \dfrac{\text{character width}+a}{.78}, a \in [-0.5, 0.5)$
$\text{line height} = \dfrac{.75 (\text{character height} + b)}{\text{font size}}, b \in [-0.5, 0.5) $
Select arbitrary values for $a$ and $b$ within the range $-0.5$ to $0.5$.
Here are some measured character dimensions and suggested settings based on the developer’s Windows desktop:
Application | Character Width | Character Height | Font Size | Line Height |
---|---|---|---|---|
IntelliJ Terminal | 8 | 22 | 10 | 1.65 |
Putty | 8 | 16 | 10 | 1.2 |
Notepad | 10 | 18 | 13 | 1.04 |
Notepad++ | 9 | 19 | 12 | 1.2 |
Windows Command Prompt | 8 | 16 | 10 | 1.2 |
Windows Console Host | 9 | 20 | 12 | 1.25 |
Windows Terminal | 9 | 19 | 12 | 1.2 |
Your mileage may vary.
Ideally, the input image file should be scaled in a paint program to the size the user wants it to appear in the terminal. However, for minor tweaks, ASCII Silhouettify accepts an image scaling factor, which defaults to one.
The conversion algorithm replaces areas of the image below 5% brightness with space characters, enabling the presumably black background to fully show through. The user can adjust this threshold as needed.
By default, the conversion algorithm distributes work across all available logical processors. The user can reduce the number of allocated processors to as few as one, though this will result in longer processing times.
On the Windows desktop where the developer created ASCII Silhouettify, Terminal renders each monospaced character within a 9×19 pixel rectangle when configured with the default 12-points, 1.2-em Cascadia Mono font. The developer captured images of the 95 printable ASCII characters and thresholded them at 50% intensity, producing images containing only black and white pixels:
The algorithm separates the source image into unique color planes, each a white silhouette on a black background:
The algorithm partitions each plane into a matrix of 9×19 pixel rectangular regions, every one of them destined to be replaced by an ASCII character. To select the optimal character, the algorithm compares a region pixel-by-pixel against every ASCII character image. If a white pixel in a character coincides with a black pixel in the region, the algorithm excludes the character to avoid distorting the silhouette's outline. Of the remaining characters, the algorithm selects the one with the maximum number of matching white pixels.
When the algorithm replaces a region with an ASCII character, it records the number of matching white pixels. After converting all planes, the algorithm combines them by selecting the characters with the highest number of matching white pixels. Finally, it colors those characters based on the colors of the planes from which they originated.
Prior to converting a source image, the algorithm sorts the ASCII character images by the number of white pixels. As shown below, the space character contains the fewest white pixels (zero), while the at sign contains the most.
The algorithm compares each region with the ASCII character images, starting with the at sign and moving downward. As soon as it finds a character that fully fits within the silhouette, the algorithm replaces the region with it because that character contains the greatest number of white pixels.
To significantly speed up the process, the algorithm prepares 171 bitmasks, one for each pixel of the 9×19 pixel rectangular regions. Each bitmask represents the set of ASCII characters images with a black pixel at the coordinates that uniquely identifies the bitmask.
Specifically, each bitmask contains 95 bits, where each bit corresponds to an ASCII character image ordered by the number of white pixels: bit-0 represents the space character, and bit-94 represents the at sign. The algorithm clears all bits in all bitmasks. Then, for each black pixel in each ASCII character image, the algorithm sets the bit corresponding to the character in the bitmask associated with the pixel.
During region conversion, the algorithm maintains a 95-bit accumulator that represents a narrowing set of ASCII characters it can use for the replacement. When it begins to convert a region, the algorithm initializes the accumulator to all ones, indicating all characters are initially considered. Then, for each black pixel in the region, the algorithm updates the accumulator to the current accumulator value bitwise ANDed with the bitmask corresponding to the pixel. That operation excludes all ASCII character images with a white pixel at a location where a black pixel exists in the region.
After the algorithm repeats that process across the region, the accumulator‘s set bits represent the remaining characters that can replace the region. Since the characters are ordered, the number of leading zeros in the accumulator is the index of the ASCII character image with the greatest number of white pixels fully contained within the plane‘s silhouette. With the help of a library, the algorithm invokes a microprocessor instruction for counting leading zeros to obtain the value it needs rapidly.
When the algorithm partitions the source image into a matrix of rectangular regions, the origin of the matrix affects the outcome. To optimize the result, the algorithm repeats the entire image conversion for all integer-coordinate origins within a 9×19 pixel area around the image origin. It then returns the best result found. To manage the extensive processing required, the algorithm distributes the work among the available logical processors.
Based on user configuration, the algorithm limits itself to a palette that ranges from just the first eight colors of the standard ANSI palette to the full 256-color extended ANSI palette. To separate the source image into unique color planes, the algorithm employs the computationally expensive CIEDE2000 perceptual color difference formula to find the closest colors within the palette.
The source is available from the following repositories: