AS ASCII Silhouettify

[ About | Example | Galleries | Install | Uninstall | Options | Algorithm ]

About

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.

Example

Here is the output of Neofetch under an instance of Ubuntu:

Neofetch Ubuntu output

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:

Ubuntu logo

We run it through the command-line version of ASCII Silhouettify:

Ubuntu logo ANSI art

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:

Generating Neofetch ASCII art file

The first line of the output file is a list of color indices. The successive lines contain the encoded image:

Neofetch ASCII art file

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 with improved logo

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.

Neofetch script segment

For comparison, here is the original logo overlaid on the generated result:

Logos overlaid

Note how the algorithm selects the largest characters that fit within the outlines of each colored region.

Galleries

For more examples, click on one of the buttons below.

Install

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.

In the Windows Command Prompt or PowerShell (but not WSL), run:

npm install -g ascii-silhouettify

On macOS and Linux (including WSL), you need to use sudo:

sudo npm install -g ascii-silhouettify

Uninstall

In the Windows Command Prompt or PowerShell (but not WSL), run:

npm uninstall -g ascii-silhouettify

On macOS and Linux (including WSL), you need to use sudo:

sudo npm uninstall -g ascii-silhouettify

Options

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.

Input

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.

Output

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.

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.

Colors and Monochrome

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.

Font Size and Line Height

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:

Intellij terminal

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.

Scale

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.

Darkness

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.

Threads

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.

Algorithm

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:

Thresholded characters

The algorithm separates the source image into unique color planes, each a white silhouette on a black background:

planes

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.

Sorted characters

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: