ASCII Art

Download ASCII_Art.zip (16 KB)

I’ve always wanted to write an ASCII Art program, if only for the fun of it. This post takes you through the different steps you need to write your own, or you can pull apart my source code. Full code listings are provided. I’ve tried to make this project as extensible as possible, so creating your own custom ASCII brush should be trivial.

Before and after ASCII processing

Our first step is to read in an image and get the colour for each pixel

Bitmap bmp = (Bitmap)Bitmap.FromFile(inputPath);
for (int y = 0; y < bmp.Height; y++)
{
  for (int x = 0; x < bmp.Width; x++)
  {
    Color color = bmp.GetPixel(x, y);
    // todo...
  }
}

Next, we need a method to convert our pixel’s colour into an ASCII character. We should wrap this logic up into an object, lets call this our “TextBrush”. Each text brush needs a method that takes a colour and returns a character. We can declare this using an interface:

public interface ITextBrush
{
  char GetCharacter(Color color);
}

We can now build our brush class, implementing the interface we just created:

public class DemoBrush : ITextBrush
{
  public char GetCharacter(Color color)
  {
    float brightness = color.GetBrightness();
    if (brightness > 0.9f)
      return ' ';
    else if (brightness > 0.8f)
      return '.';
    else if (brightness > 0.7f)
      return '-';
    else if (brightness > 0.6f)
      return '"';
    else if (brightness > 0.5f)
      return '*';
    else if (brightness > 0.4f)
      return '+';
    else if (brightness > 0.3f)
      return '=';
    else if (brightness > 0.2f)
      return '#';
    else if (brightness > 0.1f)
      return '$';
    else
      return '&';
  }
}

The final part is to write the character to a file as we loop through the pixels:

using (TextWriter tw = new StreamWriter(outputPath))
{
  ITextBrush brush = new DemoBrush();
  Bitmap bmp = (Bitmap)Bitmap.FromFile(inputPath);
  for (int y = 0; y &lt; bmp.Height; y++)
  {
    for (int x = 0; x &lt; bmp.Width; x++)
    {
      Color color = bmp.GetPixel(x, y);
      char c = brush.GetCharacter(color);
      tw.Write(c);
    }
    tw.WriteLine();
  }
}

This provides the basics of an ASCII Art program, but there are few things we need to fix up before this will work correctly. Firstly, this uses a one-character to one-pixel relationship which causes the ASCII images to be huge in comparison to the original JPEG. Secondly, a pixel is always square whereas a character usually occupies a rectangular space. This causes our image to be stretched vertically.

Both of these problems can be solved by resizing the image prior to processing. I usually reduce the width and height to 25% and scale the height down futher to 63% to correct the skew. The exact figures to use will depend on the font and size you choose. I'm using Lucinda Console at 8pt.

I used the following method to resize the bitmap:

private Bitmap ResizeBitmap(Bitmap bmp, int width, int height)
{
  Bitmap result = new Bitmap(width, height);
  using (Graphics g = Graphics.FromImage((Image)result))
  {
    g.DrawImage(bmp, 0, 0, width, height);
  }
  return result;
}

Here’s the final result:

Before and after ASCII processing

Full source code in C# can be downloaded here:

Download ASCII_Art.zip (16 KB)

Advertisements
This entry was posted in Projects and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s