Old Skool Trippin’, Part II

So what’s this part 2 all about?
I have to give it to Raj for finding out, but not even knowing it.

Ami Dudu (no weblog… yet) came into my office the other day and I showed him some output from the app. He then ‘challanged’ me to step it up a notch and make each pixel into a different letter.
I can’t really refuse a challange from Ami, so I sat down for a couple of hours and wrote an application that found out how much each letter’s lightness is and created an HTML based on the image from that.

I decided to step it up a notch as well: I would take every letter and check for the brightness in each of its quadrants (dividing the letter into four parts – top left, top right, bottom left and bottom right) and work with 4 pixel groups that get represented by those letters.
True, the algorithm isn’t perfect, but I didn’t want to spend any more time into it than I already have.

Here’s an example of what came out when I ran a lighter version of the image I used in the previous post.

#region 2x2 Code
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Collections;
namespace AnsiStuff
class AsciiMaker2x2
class CharDiff : IComparable
public readonly char Char;
public readonly float Diff;
public CharDiff(char c, float diff)
Char = c;
Diff = diff;
public int CompareTo(object obj)
return Diff.CompareTo(((CharDiff)(obj)).Diff);
static void Main(string[] args)
if (args.Length == 1)
string fileName = args[0];
Hashtable fontTable = CreateFontTable();
using (Image originalImage = Image.FromFile(fileName))
using (StreamWriter sw = File.CreateText(fileName + ".htm"))
sw.Write("<pre style=\"font-family: Courier New; font-size: 1px; letter-spacing: 0mm; line-height: 1px; font-weight: bold\">");
using (Bitmap newBmp = new Bitmap(originalImage))
int x, y;
for (y = 0; y < newBmp.Height; y += 2)
for (x = 0; x < newBmp.Width; x += 2)
Color topLeft = newBmp.GetPixel(x, y), topRight = Color.White, bottomLeft = Color.White, bottomRight = Color.White;
if (x + 1 < newBmp.Width)
topRight = newBmp.GetPixel(x + 1, y);
if (y + 1 < newBmp.Height)
bottomRight = newBmp.GetPixel(x + 1, y + 1);
if (y + 1 < newBmp.Height)
bottomLeft = newBmp.GetPixel(x, y + 1);
sw.Write(MakeSafe(FindBestCharacter(fontTable, topLeft, topRight, bottomLeft, bottomRight).ToString()));
#region FindBestCharacter
        static char FindBestCharacter(Hashtable fontTable, Color topLeft, Color topRight, Color bottomLeft, Color bottomRight)
float tlb = topLeft.GetBrightness(), trb = topRight.GetBrightness(), blb = bottomLeft.GetBrightness(), brb = bottomRight.GetBrightness();
ArrayList totalDiffs = new ArrayList(fontTable.Count);
// Create the differences list.
foreach (DictionaryEntry entry in fontTable)
totalDiffs.Add(new AsciiMaker2x2.CharDiff(((char)(((int)(entry.Key)))),
Math.Abs(tlb - Convert.ToSingle(((float[,])(entry.Value))[0, 0])) +
Math.Abs(trb - Convert.ToSingle(((float[,])(entry.Value))[1, 0])) +
Math.Abs(blb - Convert.ToSingle(((float[,])(entry.Value))[0, 1])) +
Math.Abs(brb - Convert.ToSingle(((float[,])(entry.Value))[1, 1]))));
// Sort it according to the letter that's closest in lighting to the lighting we need.
// If we are about to return any type of space, let's just return the conventional space.
if (Char.IsWhiteSpace(((AsciiMaker2x2.CharDiff)(totalDiffs[0])).Char))
return ' ';
return ((AsciiMaker2x2.CharDiff)(totalDiffs[0])).Char;

#region CreateFontTable
        static Hashtable CreateFontTable()
Hashtable charBrightnessMap = new Hashtable();
// All Courier New 10px letters occupy an 8x16 square at best.
using (Bitmap newBmp = new Bitmap(8, 16))
using (Font font = new Font("Courier New", 10f))
using (SolidBrush wb = new SolidBrush(Color.White))
using (Graphics g = Graphics.FromImage(newBmp))
// I didn't want to exceed the 256 letters range.
for (int i = 0; i <= 256; i++)
char c = (char)i;
g.FillRectangle(wb, new Rectangle(new Point(0, 0), newBmp.Size));
using (SolidBrush b = new SolidBrush(Color.Black))
// There's a 2 pixel horizontal padding for each letter.
// We want to get rid of it.
g.DrawString(c.ToString(), font, b, -2, 0);
using (Bitmap smallBmp = new Bitmap(4, 8))
float[,] brightnessMatrix = new float[2, 2];
for (int horHalf = 0; horHalf < 2; horHalf++)
for (int verHalf = 0; verHalf < 2; verHalf++)
for (int x = 0; x < 4; x++)
for (int y = 0; y < 8; y++)
smallBmp.SetPixel(x, y, newBmp.GetPixel(x + horHalf * 4, y + verHalf * 4));
using (Image img = smallBmp.GetThumbnailImage(1, 1, new Image.GetThumbnailImageAbort(new AsciiMaker2x2().kek), IntPtr.Zero))
brightnessMatrix[horHalf, verHalf] = ((Bitmap)(img)).GetPixel(0, 0).GetBrightness();
charBrightnessMap.Add(i, brightnessMatrix);
return charBrightnessMap;

#region MakeSafe
        static string MakeSafe(string value)
return value
.Replace("&", "&amp;")
.Replace("<", "&lt;")
.Replace(">", "&gt;")
.Replace("¡", "&iexcl;")
.Replace("¢", "&cent;")
.Replace("£", "&pound;")
.Replace("¤", "&curren;")
.Replace("¥", "&yen;")
.Replace("¦", "&brvbar;")
.Replace("§", "&sect;")
.Replace("¨", "&uml;")
.Replace("©", "&copy;")
.Replace("ª", "&ordf;")
.Replace("«", "&laquo;")
.Replace("¬", "&not;")
.Replace("­", "&shy;")
.Replace("®", "&reg;")
.Replace("¯", "&macr;")
.Replace("°", "&deg;")
.Replace("±", "&plusmn;")
.Replace("&sup2;", "&sup2;")
.Replace("&sup3;", "&sup3;")
.Replace("´", "&acute;")
.Replace("µ", "&micro;")
.Replace("¶", "&para;")
.Replace("·", "&middot;")
.Replace("¸", "&cedil;")
.Replace("&sup1;", "&sup1;")
.Replace("º", "&ordm;")
.Replace("»", "&raquo;")
.Replace("&frac14;", "&frac14;")
.Replace("&frac12;", "&frac12;")
.Replace("&frac34;", "&frac34;")
.Replace("¿", "&iquest;")
.Replace("À", "&Agrave;")
.Replace("Á", "&Aacute;")
.Replace("Â", "&Acirc;")
.Replace("Ã", "&Atilde;")
.Replace("Ä", "&Auml;")
.Replace("Å", "&Aring;")
.Replace("Æ", "&AElig;")
.Replace("Ç", "&Ccedil;")
.Replace("È", "&Egrave;")
.Replace("É", "&Eacute;")
.Replace("Ê", "&Ecirc;")
.Replace("Ë", "&Euml;")
.Replace("Ì", "&Igrave;")
.Replace("Í", "&Iacute;")
.Replace("Î", "&Icirc;")
.Replace("Ï", "&Iuml;")
.Replace("Ð", "&ETH;")
.Replace("Ñ", "&Ntilde;")
.Replace("Ò", "&Ograve;")
.Replace("Ó", "&Oacute;")
.Replace("Ô", "&Ocirc;")
.Replace("Õ", "&Otilde;")
.Replace("Ö", "&Ouml;")
.Replace("×", "&times;")
.Replace("Ø", "&Oslash;")
.Replace("Ù", "&Ugrave;")
.Replace("Ú", "&Uacute;")
.Replace("Û", "&Ucirc;")
.Replace("Ü", "&Uuml;")
.Replace("Ý", "&Yacute;")
.Replace("Þ", "&THORN;")
.Replace("ß", "&szlig;")
.Replace("à", "&agrave;")
.Replace("á", "&aacute;")
.Replace("â", "&acirc;")
.Replace("ã", "&atilde;")
.Replace("ä", "&auml;")
.Replace("å", "&aring;")
.Replace("æ", "&aelig;")
.Replace("ç", "&ccedil;")
.Replace("è", "&egrave;")
.Replace("é", "&eacute;")
.Replace("ê", "&ecirc;")
.Replace("ë", "&euml;")
.Replace("ì", "&igrave;")
.Replace("í", "&iacute;")
.Replace("î", "&icirc;")
.Replace("ï", "&iuml;")
.Replace("ð", "&eth;")
.Replace("ñ", "&ntilde;")
.Replace("ò", "&ograve;")
.Replace("ó", "&oacute;")
.Replace("ô", "&ocirc;")
.Replace("õ", "&otilde;")
.Replace("ö", "&ouml;")
.Replace("÷", "&divide;")
.Replace("ø", "&oslash;")
.Replace("ù", "&ugrave;")
.Replace("ú", "&uacute;")
.Replace("û", "&ucirc;")
.Replace("ü", "&uuml;")
.Replace("ý", "&yacute;")
.Replace("þ", "&thorn;")
.Replace("ÿ", "&yuml;");

public bool kek()
return false;


3 thoughts on “Old Skool Trippin’, Part II

  1. Holy Fricken String.Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()Replace()

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