Click here to Skip to main content
15,881,027 members
Articles / Programming Languages / C#

ASCII Imaging

Rate me:
Please Sign up or sign in to vote.
4.93/5 (6 votes)
2 Jan 2013CPOL2 min read 25.1K   516   22   5
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.

C#
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.

C#
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.

C#
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.

C#
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:

C#
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.

C#
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.

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 4 Pin
JamesHollowell20-Jan-13 2:49
JamesHollowell20-Jan-13 2:49 
GeneralMy vote of 4 Pin
jfriedman2-Jan-13 18:07
jfriedman2-Jan-13 18:07 
Cool code! Why only certain characters in the map? Where does that similarity algorithm come from and if you made it why are there only limited cases? Can you explain it or elaborate more on the other ways? Thanks!
GeneralRe: My vote of 4 Pin
austinbox2-Jan-13 18:19
austinbox2-Jan-13 18:19 
GeneralRe: My vote of 4 Pin
jfriedman2-Jan-13 18:48
jfriedman2-Jan-13 18:48 
GeneralRe: My vote of 4 Pin
austinbox2-Jan-13 20:44
austinbox2-Jan-13 20:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.