Old Skool Trippin’, Part III

What the-? Part 3? But it was supposed to be only a two part-er.
Yeah, but there are a couple of things I wanted to talk about.

Wim Hollebrandse remarks that there’s the HttpUtility.HtmlEncode method, and that I don’t need the MakeSafe method.
My response to that was “Holy hidden methods, Batman!” I was looking for a method like this for a long time now. Thanks. :D Shame about the 15 minutes I had copy/pasting the list.
I read through the method using Reflector and found out that the method takes the easy way: Anything that’s above the normal letter range is passed as a numeric representation. So I made a few adjustments, included the whole range of the Unicode spectrum of characters, and now we can get better results, even though it would take a lot longer (creating the table, checking the options at hand, etc.)

Here’s the revised code:

#region The Code
using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Collections;
namespace AnsiStuff
{
class AsciiMaker2x2Take2
{
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);
}
}
[STAThread]
static void Main(string[] args)
{
if (args.Length == 1)
{
string fileName = args[0];
Console.Write("Creating font table...");
Hashtable fontTable = CreateFontTable();
Console.WriteLine("done.");
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(System.Web.HttpUtility.HtmlEncode(FindBestCharacter(fontTable, topLeft, topRight, bottomLeft, bottomRight).ToString()));
}
sw.WriteLine();
}
}
sw.Write("</pre>");
}
}
}
}
#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 AsciiMaker2x2Take2.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.
totalDiffs.Sort();
return ((AsciiMaker2x2Take2.CharDiff)(totalDiffs[0])).Char;
}
#endregion

#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))
{
// Going for the whole unicode range ;)
for (int i = 0; i <= Math.Pow(2.0, 16.0); 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 AsciiMaker2x2Take2().kek), IntPtr.Zero))
{
brightnessMatrix[horHalf, verHalf] = ((Bitmap)(img)).GetPixel(0, 0).GetBrightness();
}
}
}
charBrightnessMap.Add(i, brightnessMatrix);
}
}
}
}
}
}
return charBrightnessMap;
}
#endregion

public bool kek()
{
return false;
}
}
}
#endregion

Oh, and Peli, the only way for me to create the System.Drawing.Ascii is if I work for Microsoft. *cough cough* At best I could create DotNetZen.Drawing.Ascii.
I’ll have to think about it.

In the meantime, does someone know of a fixed-width font for unicode (16 bit)? Courier New isn’t really fixed-width for all characters.

p.s. All code was run through webifyOnline for coloring.

Advertisements

4 thoughts on “Old Skool Trippin’, Part III

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