Recently I have been making little programs that I have thought about for years wandering how they are done only to find out now I actually know how to do it and do it properly.
Today’s program I was thinking about was an ASCII art generator. That is a program that takes an image file and converts it into a representation made of text. For example below is the wikipedia logo but if you look view the original you will notice it is comprised of different letters.

The easiest way to achieve this is to take all of the letters you want the image to comprise of put them in order of pixel density (I.E. “M” is much denser than “.”). Then you take a grey scale version of your input and translate each grey colour into a letter. I decided this would be a bit too easy and so to make it slightly more challenging I would output this to console and use every character the console could output not just A-Z. To achieve this the encoding for the console would have to be taken into account. I ended up with the following code:

Encoding enc = Console.OutputEncoding;
List charDensity = Enumerable.Range((int)char.MinValue, (int)char.MaxValue).
           Select(c=>enc.GetString(enc.GetBytes((char)c))[0]).
           Distinct().
           Where(c=>!char.IsControl(c)).
           Select().(c=>{
            Bitmap bm = new Bitmap(20,20);
            using(Graphic g = Graphics.FromImage(bm)){
              g.DrawString( c.ToString(), new Font("Arial",8), Brushes.Black, new RectangleF(0,0,20,20));
            }
            var Sum = Enumerable.Range(0,bm.Width).Select(x=>
             Enumerable.Range(0,bm.Height).Select(y=>
              bm.GetPixel(x,y).ToArgb()==Brushes.Black.ToArgb()?1:0)).ToList().Sum();
            return new{ ch=c, sum=Sum};
           }.OrderBy(c=>c.sum).Select(c=>c.ch).ToList();

Now this may look like quite a mouthful but thats mainly because I was trying out all of my linq knowledge. If I was to do this properly I most likely not lay it out like the above as it is hard to read. But its not too hard to work out what is happening. After sorting out all the characters that we can output we draw that character count how many pixels it uses and call that its density. Then we sort the characters by density.

After producing the character density list its not hard to translate pixel values into an appropriate char value.

charDensity[charDensity.Count-1-(pixel.color*charDensity.Count)/(256*3)]

In this instance pixel color is the addition of the RGB values.

And that is how you make an ascii art generator that uses all of the characters that can be outputted.

Advertisements