5

I am working on a program (in C/C++) where the user should take a user selected image and convert this into ASCII art (using SQL). So far I have been able for the user to select an image and display this image in greyscale in a window.

However, I am currently having difficulties sorting the ASCII characters as an array of brightness levels and then matching the single character to a pixel area.

I am aware that I will need to use 'for' loops, but I can't find anything that useful on the internet so far. Thank you :D

INeedHelp
  • 61
  • 1
  • 1
  • 2
  • You should add some of your code, so we can see what you have already and where the exact issue is. – Wouter May 07 '15 at 10:20
  • The issue is that I have no idea how to analyse the pixel groups and match them to the ASCII character of the same 'brightness'. – INeedHelp May 07 '15 at 10:28
  • See [jp2a](https://csl.name/jp2a/) – Sinan Ünür May 07 '15 at 10:34
  • 1
    You might want to pick one language, C or C++. – MSalters May 07 '15 at 10:36
  • 1
    This would, among other things, depend on the font and the colors used used for display. There is no such thing as the brightness of character 65, it is just a number that represents some printable glyph, how that is rendered is a matter of the font used. – David Rodríguez - dribeas May 07 '15 at 10:46
  • Thank you so far for the help.....okay so in that case how would you work out (in code) how much 'white' and 'black' each character has, to determine how bright each character looks and then sort them into an order of how bright they appear the screen? – INeedHelp May 07 '15 at 11:15

4 Answers4

16
$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,"^`'.

Here's a standard grayscale from dark to light (or the other way around depending on your preferred display colour.)

Ahsen Khan
  • 171
  • 1
  • 5
  • This response demonstrates a simple, graceful response to a relatively easy to understand question from a likely student. It shows a desire to be helpful more than a pathological need to prove expertise with a hammer. (Other responses … not so much.) – DaveFer Aug 03 '22 at 14:16
  • :D I too have noticed that students tend to be some of the most helpful, because they don't suffer from imposter syndrome as much as older, more experienced people. – Ahsen Khan Aug 04 '22 at 15:03
6
 `.-':_,^=;><+!rc*/z?sLTv)J7(|Fi{C}fI31tlu[neoZ5Yxjya]2ESwqkP6h9d4VpOGbUAKXHm8RD#$Bg0MNWQ%&@

I found Ahsen Khan's answer not to be exactly accurate for my Windows console's font (consolas), which produced slightly off results. I wrote a program to analyse and order the characters by summing the greyscale values of each pixel, which produced this. Don't forget to include the space at the beginning.

The characters also aren't distributed evenly by darkness (although I found the results of assuming an even distribution to be fine). The darkness for each character is:

[0, 0.0751, 0.0829, 0.0848, 0.1227, 0.1403, 0.1559, 0.185, 0.2183, 0.2417, 0.2571, 0.2852, 0.2902, 0.2919, 0.3099, 0.3192, 0.3232, 0.3294, 0.3384, 0.3609, 0.3619, 0.3667, 0.3737, 0.3747, 0.3838, 0.3921, 0.396, 0.3984, 0.3993, 0.4075, 0.4091, 0.4101, 0.42, 0.423, 0.4247, 0.4274, 0.4293, 0.4328, 0.4382, 0.4385, 0.442, 0.4473, 0.4477, 0.4503, 0.4562, 0.458, 0.461, 0.4638, 0.4667, 0.4686, 0.4693, 0.4703, 0.4833, 0.4881, 0.4944, 0.4953, 0.4992, 0.5509, 0.5567, 0.5569, 0.5591, 0.5602, 0.5602, 0.565, 0.5776, 0.5777, 0.5818, 0.587, 0.5972, 0.5999, 0.6043, 0.6049, 0.6093, 0.6099, 0.6465, 0.6561, 0.6595, 0.6631, 0.6714, 0.6759, 0.6809, 0.6816, 0.6925, 0.7039, 0.7086, 0.7235, 0.7302, 0.7332, 0.7602, 0.7834, 0.8037, 0.9999]

These values are scaled for 0 being all black pixels (i.e. the space character), and 0.9999 being the brightest ('@').

chungaloider
  • 71
  • 1
  • 4
  • 1
    Good answer! It's a longer gradient too, which is nice. Thank you for providing a better answer, I will definitely use this myself. – Ahsen Khan Apr 04 '23 at 21:48
  • I believe it is also valuable to note that this is not a linear scale, though it is pretty close to linear near the middle. It is definitely in order though https://pasteboard.co/vIUIqelvMroz.png – Ahsen Khan Aug 03 '23 at 21:31
2

ASCII characters have no intrinsic grayness, because this only depends on how they are drawn on your screen - in what font, size, and horizontal and vertical spacing, and in what colors.

Still: it's possible to make an educated guess. A space is 'all white' for most fonts, a full stop will be a small dot in most fonts, a comma is slightly larger, et cetera. All you need is the ratio of black-to-white pixels, for each displayable character.

  1. Find (or create) a bitmapped version of the font you are going to use, or one close to it. Since most ASCII fonts are actually very close in their design, you can even use a simple 8x8 bitmap font (not many fonts will have a ! that is "heavier" than a W - if you find one that does, find another). As you are going to use it for ASCII art, you probably want monospaced fonts only. Drawing ASCII art with proportional fonts is possible but much harder.

  2. Loop over each character and count the black pixels. Typically, a space will have 0, a full stop 1, and something like a # will have 16 or so. (Hey look! This is where you can use a for loop!)

  3. The exact grayness of each character can be represented by value/area where area is the entire size of the bitmap. But you are not interested in the absolute value! A normal ASCII range does not contain a character that should be "all black". To find out the relative grayness, divide the value for each character by the maximum value you found for the entire font. That way, the space will be 0, the "maximum value" character will be 1, and all other characters will have a value in between. (Actually, if your Space character contains black pixels, subtract these from the initial values as well. Just to outline the general idea; you'd better not use such a weird font.)

  4. You will end up with 95 values - one for each from Space (#32) to Tilde (#126). If you want to use all characters in your output, you are ready to go. Sort the characters on their gray level. For each gray input pixel (a level from 0 to 255), divide it by 255 to get it into the same range as your character map value. Then print the character with a level closest to it. (This is the most straightforward method but can be optimized in various ways.)

  5. If you want to restrict the grayscale to a smaller range of values/characters, build a smaller array with values closest to the levels you want. For example, if you want 16 levels of gray, find the characters closest to 0, 1/15, 2/15 ... 15/15.

See also Step 5 and 6 of my answer to a related question.

Community
  • 1
  • 1
Jongware
  • 22,200
  • 8
  • 54
  • 100
  • I applied a similar approach here: https://jod.li/optimal-character-choices-for-ascii-art-in-php/ The results are good enough for me. – luvzfootball Nov 30 '20 at 07:08
1

There's no reasonable way to do this, and existing ASCII-art programs just use a predefined character order. I.e. char myASCII[] = " .,:ilwW";

MSalters
  • 173,980
  • 10
  • 155
  • 350