Introduction

Have you ever seen a C# application that converts a given image to a text-based ASCII Art image like the ones shown above?

Well, a few months ago, I stumbled across an article4 on Code Project by Daniel Fisher which talks about creating an application that does just this. According to Daniel, he was not able to find any C# application on the web that does image-to-ASCII conversions, so he decided to write his own, and hence his article. This is yet another article on the same topic, but with a slightly more enhanced ASCII Art generation. What I did was I searched through the web, found some web sites with image-to-ASCII conversion applications in PHP, combined all their ideas (including Daniel's), and implemented another (more enhanced) version of the ASCII Art generator in .NET.

For the list of web sites from where I got all my ideas/information, or if you just want to know more about ASCII Art in general, please check out the References section given below.

Using the code (Installation)

In the source files included above, you will find the following two Visual Studio projects:

Note: On some machines (especially servers), IIS doesn't actually use the ASPNET account to run ASP.NET pages. To find out exactly what account your IIS is using, just copy and paste the following code into Notepad and save it as who.aspx, then put the file into a web-folder under IIS and view it in Internet Explorer. The page will display the correct user account that ASP.NET is running under.

The above method is fast, but may not produce a high-quality resized image, and you don't have the option to select only a portion/section of the image to work with. The other alternative is to use System.Drawing.Graphics, as follows:

Now, at this stage, you may be wondering whether we can merge Step 3 and 4 together (assuming you use the second resizing method above), the short answer is: yes. The merged version will look like the following:

However, there is a catch in using the above merged method. To illustrate this, consider the case where you want to resize a HUGE image down to a small size and then convert it to ASCII Art. If you use the merged method, you will need to transform the entire image before the resizing takes place. This takes a lot of time. Therefore, it is better to resize it first before transforming it, hence the two separate methods given above.

Of course, you may argue that if somebody wants to resize a small image to a larger one and then transform it, the above situation will be reversed. But the fact is that this doesn't happen often in real life, so using the two separate methods will still be a better option.

But then, you could always implement both ways and choose the correct way depending on the original vs. resized size ratio. I leave this up to you.

In Step 4 above, we use a custom method called CreateColorMatrix(). This method simply calculates a proper 5x5 color matrix for the specified brightness, contrast, and saturation. This color matrix is used for transforming the image by means of matrix multiplication. In fact, the construction of this matrix is also based on matrix multiplication. In this article, I will not talk about how matrix multiplication works. But if you want to know more about it, you can check out the MSDN Site10 for an excellent explanation on this topic in relation to the usage of the ColorMatrix object.

Warning: Implementing the CreateColorMatrix() method involves a lot of mathematical details. If you find this boring, simply skip the details given below and go straight here for the source code of this method.

The following shows the actual matrix values of the brightness, contrast, and saturation matrices:

Notice that the saturation matrix has three special constants: lumR, lumG, and lumB. These represent the proportion of each RGB value that contributes to the luminance (brightness) value. In short, luminance for a pixel is calculated as follows:

From the above information, we can calculate the proper color matrix to transform a given image. To use all three matrices, we need to multiply them together into one single transformation matrix (using matrix multiplication). The result of multiplication is as follows:

First, you need to create a transformed image that is purely grayscale (saturation = 0). The brightness and contrast can be user-given. Then for each pixel in the grayscale image, get the luminance/brightness of that pixel, find the matching ASCII character with a similar proportion of brightness/luminance from the constructed character array in Step 2 above, and then output that character.

Sometimes, you need to display the transformed image in colors, or display the ASCII Art output in colors. In this case, you need to create one more transformed image based on the user-given saturation. Then for each generated ASCII character, color it based on the corresponding pixel color in the transformed colored image. For example, if you are displaying the ASCII Art in a web page, you can use the HTML <font> tags to change the character color.

The above code is actually not optimal as it always encloses each character with a separate <font> tag, even if adjacent characters have the same color. Therefore, you can optimize the code given above so that adjacent characters with the same font color will share the same <font> tags.

For example, the HTML ASCII Art output:

<fontcolor="#FFCC00">W</font><fontcolor="#FFCC00">N</font>

should be changed to:

<fontcolor="#FFCC00">WN</font>

Finally, if you are displaying the ASCII Art onto a web page, you should wrap the entire ASCII image in a properly-formatted block so that spaces between characters can be reduced. You can use style-sheet to do this:

Known issues and suggested solutions

The character weighting (brightness/luminance) information is mainly from IMG2ASCII1, which unfortunately is not very accurate.

Some block symbols do not have the same fixed-width as other characters. Therefore, distortion can occur if you use block symbols.

I suggest using custom character sets to compensate the above two problems. The default chosen custom character set is " .:,;+ijtfLGDKW#" (without the quotes). (This character set is derived from the ASCII data used in IMG2TXT3.)

If you just want color HTML, then just use the letter 'W' for the custom character set.

If you include custom characters that are not found in XML data file, then those characters will automatically be removed from the custom character set. This behavior is due to the design.

That's all!

If you want to see the full implementation of the above logic, just download the source files given above and have a look at the source codes. Note that the C# code presented in this article is a simplified version of the actual code; I have left out all that is irrelevant to the purpose of this article, such as error-handling and freeing resources.

Also, in my source files, I have put open curly braces at the end of a line, not at the beginning of a new line. Now, I'm not going to argue with you guys about which style is the best one that we should use. Personally, I use the end-of-line curly braces because I find it easier to read long lines of code. (Each start-of-line curly brace use up one line of code, so long lines of code will get even longer.) And no, I don't have a problem locating the start and end of a block since indentation is used.

Other than that, have fun!

Please don't hesitate to write me suggestions/comments if you have any.

To-do list

Modify the web page code to allow user to change the brightness, contrast, and saturation of the image.

Modify the web page code to allow user to select only a portion of the image for ASCII Art output.

Modify the web page architecture so that uploading a file to a permanent physical location of the server is not necessary to generate its ASCII Art.

Implement hue adjustment of the image in ASCII Art library.

History

12th July, 2005

Article: Added a few more sample ASCII Art images.

Article: Added a References section.

Article: Added a History section.

Article: Minor cosmetic changes in wording.

13th July, 2005

Article: Added two more sample ASCII Art images.

16th July, 2005

CODE: Improved the graphics manipulation logic in ASCII Art library.

Article: Added a To-do list section.

Article: Modified lot of stuff in The Library Logic section in response to the new changes in code.

23 May 2007

Added a Windows desktop GUI port submitted by David Luu.

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.

But if I click the button to change the contrast, it doesn't work. Yes, the color is change, but it does not change the contrast of the image, the image turns into color more gray even solid black if "call setcontrast(0.0)"

For anyone up to the task, and interested, I think this article/project would be awesome ported to Windows 8 as a Metro UI application, and perhaps also to Windows Phone 8 (not sure about Windows Phone 7.x older versions).

For Metro, it could be using WinJS to keep the HTML/javascript UI aspects of the application, perhaps even mixed with calls to C# components for the portion that handles the ASCII conversion/generation. This would allow for a web UI based app without the drawbacks of requiring a photo/file upload to convert to ASCII, just convert a locally photo you browse for, maybe even integrated with Microsoft's Photo viewer app, etc. via share contracts.

"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson

I want to say your work is excellent.I have read your program and find there are many problems for me to understand it.So I wonder whether you can help me with this program. I'll appreciate it if you can do me a faver. My contact is handsomedzl@foxmail.com. Thank you!

I want to say your work is excellent.I have read your program and find there are many problems for me to understand it.So I wonder whether you can help me with this program. I'll appreciate it if you can do me a faver. My contact is handsomedzl@foxmail.com. Thank you!

Howdy, I've ported this generator to an Ajax solution by using Gaia Ajax Widgets. It's Open Source just as the original version and it can be found both as a sample running and as a code download here; Ascii Art Generator Ajaxified

Hmm...just doing a search on ASCII art to check up on this article and what do I find?

Some new articles on ASCII art generation in C#. Mostly similar to what this article has but maybe with a (slightly) different spin or implementation. Well, it's nice to have more than one solution, but...sigh...isn't it simpler to avoid re-inventing the wheel?

Actually, this is probably a good thing. When there are multiple articles for the same topic, people get more information, references, and inputs from different sources. Different articles have different level of usefulness to different people depending on what they are looking for.

> whoami
The system is unable to identify you when you don't even know your name!

Would you be interested in posting up my C# windows forms (desktop GUI) port of your ASCII Art Generator? I would like to share it with others and prefer not to host it elsewhere or write a new article for it if I don't have to.

If yes, I can send you the zip package by email.

Regards,

Dave

"A good scientist is a person with original ideas. A good engineer is a person who makes a design that works with as few original ideas as possible." - Freeman Dyson