Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASCII Imaging

0.00/5 (No votes)
2 Jan 2013 1  
How to convert images to ASCII in a Console Application with colors.

Failed to load image

Failed to load image

Introduction

In this article I will show you how to convert images to ASCII art. To convert images to ASCII we will need some basic programming knowledge of C# 3.0 which includes:

  • Loops
  • Math operands
  • Imaging

Background

ASCII - American Standard Code for Information Interchange, is often used for telegraphic codes and for other uses such as for fun. ASCII has 128 keyboard characters and 33 control characters. Encoding on the World-Wide-Web also used ASCII encoding until UTF-8 was preferred. Nowadays ASCII is often referred to as sometimes art to draw pictures with only using keyboard characters.

Using the code

To convert images to ASCII, we are going to first need to convert all of the colors to console colors since Console applications are limited to 16 colors.

Let's first create a class file used to print ASCII characters with a console color and character.

public class CString
{
    public ConsoleColor Color;
    public string String;
    public CString(string s, ConsoleColor color)
    {
        String = s;
        Color = color;
    }
    public CString()
    {

    }
}

Now that we have a class file for storing a console color and character let's get to converting the colors. For more information on converting colors there is a well written article on converting colors here. Let's first retrieve all of the console colors.

static Color[] ConsoleColors()
{
    //Create an array for the consolecolors
    Color[] array = new Color[16];
    //Retrieve all of the names of the consolecolors
    string[] names = Enum.GetNames(typeof(ConsoleColor));      
    //Loop throught the names, adding each to the array as a Color
    for (int i = 0; i < names.Length; i++)
        array[i] = Color.FromName(names[i]);
    //Return the array
    return array;
}

Now let's create a function to find the closest color to these colors.

static ConsoleColor Closest(Color _1)
{
    //If the color is already a consolecolor convert it directly...
    if (_1.IsSystemColor)
        return (ConsoleColor)Enum.Parse(typeof(ConsoleColor), _1.Name);
        
    //The following code is not mine and can be found at
    //http://www.codeproject.com/Articles/17044/Find-the-Nearest-Color-with-C-Using-the-Euclidean
    //NOTE: For questions about how the following code works please refer to his article.
    double dbl_input_red = Convert.ToDouble(_1.R);
    double dbl_input_green = Convert.ToDouble(_1.G);
    double dbl_input_blue = Convert.ToDouble(_1.B);
    double distance = 500.0;

    double dbl_test_red;
    double dbl_test_green;
    double dbl_test_blue;
    Color nearest_color = Color.Empty;
    //Loop through all of the consolecolors
    foreach (object o in ConsoleColors())
    {
        dbl_test_red = Math.Pow(Convert.ToDouble(((Color)o).R) - dbl_input_red, 2.0);
        dbl_test_green = Math.Pow(Convert.ToDouble
            (((Color)o).G) - dbl_input_green, 2.0);
        dbl_test_blue = Math.Pow(Convert.ToDouble
            (((Color)o).B) - dbl_input_blue, 2.0);
        double temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red);
        if (temp == 0.0)
        {
            nearest_color = (Color)o;
            break;
        }
        else if (temp < distance)
        {
            distance = temp;
            nearest_color = (Color)o;
        }
    }
    //END OF http://www.codeproject.com/Articles/17044/
    //           Find-the-Nearest-Color-with-C-Using-the-Euclidean

    //Now that we have the closest color parse it and return the correct color.
    return (ConsoleColor)Enum.Parse(typeof(ConsoleColor), nearest_color.Name);
}

Now that we have a function for finding the closest console color, let's create a function that finds the closest ASCII character for a specified color.

static string Brightness(Color _1)
{
    //there are lots of ways to do this,
    //but I decided just to add all of
    //the colors R, G, B values and go from there.
    //For better accuracy try
    //float factor = _1.Brightness();
    //NOTE: make sure to change the values below if you decide
    //to use brightness.
    
    int factor = _1.R + _1.G + _1.B;
    
    //Experiment with your own characters for different results.
    if (factor >= 602)
        return "M";
    if (factor >= 572)
        return "@";
    if (factor >= 532)
        return "#";
    if (factor >= 502)
        return "8";
    if (factor >= 472)
        return "0";
    if (factor >= 432)
        return "&";
    if (factor >= 402)
        return "%";
    if (factor >= 372)
        return "?";
    if (factor >= 332)
        return "<";
    if (factor >= 302)
        return "/";
    if (factor >= 252)
        return "*";
    if (factor >= 200)
        return ".";
    return " ";
}

Let's create another function to implement to CString class:

static CString CSimiliarity(Color _1)
{
    //Create a blank instance of a CString class
    CString str = new CString();
    //Set the character based on Brightness
    str.String = Brightness(_1);
    //Set teh color closest to a consolecolor
    str.Color = Closest(_1);
    //Lastly, return the CString object
    return str;
}

Lastly, convert the Bitmap object to a multidimensional array of CStrings.

static CString[,] ImageToASCII(Bitmap b)
{
    Image.GetThumbnailImageAbort myCallback = null;
    //If the width of the bitmap is greater than 80 (console screen)
    //Resize it for better results
    if (b.Width > 80)
        b = (Bitmap)b.GetThumbnailImage(80, 60, myCallback, IntPtr.Zero);
    CString[,] map = new CString[80, b.Height];
    //Loop through the image and add each CString to the array
    for (int y = 0; y < b.Height; y++)
        for (int x = 0; x < 80; x++)
            map[x, y] = CSimiliarity(b.GetPixel(x, y));
    return map;
}

Since you probably want to see the end result, let's create a function to print the array.

static void PrintCStringMult(CString[,] mult)
{
    //Get width of the array
    int width = mult.GetLength(0);
    //Get height of the array
    int height = mult.GetLength(1);
    //Loop through each CString,
    //Set the Foreground Color to the consolecolor
    //and Use Console.Write to write the character
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            CString m = mult[x, y];
            Console.ForegroundColor = m.Color;
            Console.Write(m.String);
        }
    }
}

Points of Interest

For best results make sure you resize the picture to exactly 80, it doesn't work well with anything below 80. Note: Console screen width is 80 characters (pixels in this case).

Thanks

I have used a small bit of code from this article published on The Code Project: http://www.codeproject.com/Articles/17044/Find-the-Nearest-Color-with-C-Using-the-Euclidean.

History

N\A.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here