Building an Image from Text in JavaScript

The code included below builds and displays an image from an array of strings whose individual characters represent the pixels in that image.

To see it in action, copy the code into an .html file and open that file in a web browser that supports HTML5 and JavaScript.

<html>
<body>
<script type='text/javascript'>

// application

function TextToImageConverter()
{
	this.main = function()
	{
		var imageManWearingHat = ImageHelper.buildImageFromStrings
		(
			4, // scaleMultiplier
			new Array
			(
				"................................",
				".............bb..bb.............",
				"............b..bb..b............",
				"............b......b............",
				"..........bbbbbbbbbbbb..........",
				"............b......b............",
				"............b......b............",
				"............b......b............",
				"............b......b............",
				".............bbbbbb.............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"........bbbbbbbbbbbbbbbbb.......",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"...............bb...............",
				"..............b..b..............",
				".............b....b.............",
				"............b......b............",
				"...........b........b...........",
				"..........b..........b..........",
				".........b............b.........",
				"........b..............b........",
				".......b................b.......",
				"......b..................b......",
				"................................"
			)
		);

		document.body.appendChild(imageManWearingHat.htmlElement);
	}

}

// classes

function Color(name, symbol, systemColor)
{
	this.name = name;
	this.symbol = symbol;
	this.systemColor = systemColor;
}
{
	// static methods

	Color.getBySymbol = function(symbolToGet)
	{
		var returnValue = Color.Instances._SymbolToColorLookup.getByKey(symbolToGet);
		return returnValue;
	}

	// instances

	// Color.Instances = new Color_Instances(); // must defer this

	function Color_Instances()
	{
		// Not sure why rgba is necessary, but it is.
		this.Transparent = new Color("Transparent", ".", "rgba(0, 0, 0, 0)");

		this.Black 	= new Color("Black", 	"k", "#000000");
		this.Blue 	= new Color("Blue", 	"b", "#0000ff");
		this.Gray 	= new Color("Gray", 	"a", "#808080");
		this.Green 	= new Color("Green", 	"g", "#00ff00");
		this.Orange 	= new Color("Orange", 	"o", "#ff8800");
		this.Purple 	= new Color("Purple", 	"p", "#ff00ff");
		this.Red 	= new Color("Red", 	"r", "#ff0000");
		this.White 	= new Color("White", 	"w", "#ffffff");
		this.Yellow 	= new Color("Yellow", 	"y", "#ffff00");

		this._All = new Array
		(
			this.Transparent,

			this.Black,
			this.Blue,
			this.Gray,
			this.Green,
			this.Orange,
			this.Purple,
			this.Red,
			this.White,
			this.Yellow	
		);

		this._SymbolToColorLookup = new Lookup().addMany(this._All, "symbol", null);
	}	
}

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}
{
	// constants

	Coords.NumberOfDimensions = 2;

	// instance methods

	var prototype = Coords.prototype;

	prototype.absolute = function()
	{
		this.x = Math.abs(this.x);
		this.y = Math.abs(this.y);

		return this;
	}

	prototype.add = function(other)
	{
		this.x += other.x;
		this.y += other.y;

		return this;
	}

	prototype.clear = function()
	{
		this.x = 0;
		this.y = 0;

		return this;
	}

	prototype.clone = function()
	{
		var returnValue = new Coords(this.x, this.y);

		return returnValue;
	}

	prototype.dimension = function(dimensionIndex)
	{
		var returnValue;

		if (dimensionIndex == 0)
		{
			returnValue = this.x;
		}
		else
		{
			returnValue = this.y;
		}

		return returnValue;
	}

	prototype.directions = function()
	{
		if (this.x > 0)
		{
			this.x = 1;
		}
		else if (this.x < 0)
		{
			this.x = -1;
		}

		if (this.y > 0)
		{
			this.y = 1;
		}
		else if (this.y < 0)
		{
			this.y = -1;
		}

		return this;
	}

	prototype.divide = function(other)
	{
		this.x /= other.x;
		this.y /= other.y;

		return this;
	}

	prototype.divideScalar = function(scalar)
	{
		this.x /= scalar;
		this.y /= scalar;

		return this;
	}

	prototype.equals = function(other)
	{
		return (this.x == other.x && this.y == other.y);
	}

	prototype.floor = function()
	{
		this.x = Math.floor(this.x);
		this.y = Math.floor(this.y);

		return this;
	}

	prototype.magnitude = function()
	{
		var returnValue = Math.sqrt(this.x * this.x + this.y * this.y);

		return returnValue;
	}

	prototype.multiply = function(other)
	{
		this.x *= other.x;
		this.y *= other.y;

		return this;
	}

	prototype.multiplyScalar = function(scalar)
	{
		this.x *= scalar;
		this.y *= scalar;

		return this;
	}

	prototype.normalize = function()
	{
		return this.divideScalar(this.magnitude());
	}

	prototype.overwriteWith = function(other)
	{
		this.x = other.x;
		this.y = other.y;

		return this;
	}

	prototype.overwriteWithDimensions = function(x, y)
	{
		this.x = x;
		this.y = y;

		return this;
	}

	prototype.round = function()
	{
		this.x = Math.round(this.x);
		this.y = Math.round(this.y);

		return this;
	}

	prototype.subtract = function(other)
	{
		this.x -= other.x;
		this.y -= other.y;

		return this;
	}

	prototype.sumOfXAndY = function()
	{
		return this.x + this.y;
	}

	prototype.toString = function()
	{
		return "<Coords x='" + this.x + "' y='" + this.y + "' />"
	}

	prototype.trimToRange = function(rangeToTrimTo)
	{
		if (this.x < 0)
		{
			this.x = 0;
		}
		else if (this.x > rangeToTrimTo.x)
		{
			this.x = rangeToTrimTo.x;
		}

		if (this.y < 0)
		{
			this.y = 0;
		}
		else if (this.y > rangeToTrimTo.y)
		{
			this.y = rangeToTrimTo.y;
		}

		return this;
	}
}

function Image(systemImage)
{
	this.htmlElement = systemImage;
	this.filePath = systemImage.src;
}
{
	// instance methods

	Image.prototype.clone = function()
	{
		var returnValue = new Image();

		returnValue.filePath = this.filePath;
		returnValue.htmlElement = document.createElement("img");
		returnValue.htmlElement.src = this.htmlElement.src;

		return returnValue;
	}
}

function ImageHelper()
{}
{
	// static methods

	ImageHelper.buildImageFromStrings = function(scaleMultiplier, stringsForPixels)
	{
		var sizeInPixels = new Coords
		(
			stringsForPixels[0].length, stringsForPixels.length
		);

		var canvas = document.createElement("canvas");
		canvas.width = sizeInPixels.x * scaleMultiplier;
		canvas.height = sizeInPixels.y * scaleMultiplier;

		var graphics = canvas.getContext("2d");

		var pixelPos = new Coords(0, 0);
		var colorForPixel = Color.Instances.Transparent;

		for (var y = 0; y < sizeInPixels.y; y ++)
		{
			var stringForPixelRow = stringsForPixels[y];
			pixelPos.y = y * scaleMultiplier;

			for (var x = 0; x < sizeInPixels.x; x ++)
			{
				var charForPixel = stringForPixelRow[x];
				pixelPos.x = x * scaleMultiplier;

				colorForPixel = Color.getBySymbol(charForPixel);
				
				graphics.fillStyle = colorForPixel.systemColor;
				graphics.fillRect
				(
					pixelPos.x, pixelPos.y, 
					scaleMultiplier, scaleMultiplier
				);				
			}
		}

		var imageFromCanvasURL = canvas.toDataURL("image/png");
		var htmlImageFromCanvas = document.createElement("img");
		htmlImageFromCanvas.width = canvas.width;
		htmlImageFromCanvas.height = canvas.height;
		htmlImageFromCanvas.src = imageFromCanvasURL;

		var returnValue = new Image(htmlImageFromCanvas);

		return returnValue;
	}
}

function Lookup()
{
	this.systemArray = new Array();
	this.systemLookup = new Array();
}
{
	Lookup.prototype.add = function(key, value)
	{
		this.systemArray.push(value);
		this.systemLookup[key] = value;
	}

	Lookup.prototype.addMany = function(itemsToAdd, keyName, valueName)
	{
		for (var i = 0; i < itemsToAdd.length; i++)
		{
			var item = itemsToAdd[i];
	
			this.add(item[keyName], (valueName == null ? item : item[valueName]));
		}

		return this;
	}

	Lookup.prototype.containsKey = function(key)
	{
		return (this.systemLookup[key] != null);
	}

	Lookup.prototype.getByIndex = function(index)
	{
		return this.systemArray[index];
	}

	Lookup.prototype.getByKey = function(key)
	{
		return this.systemLookup[key];
	}

	Lookup.prototype.length = function()
	{
		return this.systemArray.length;
	}

	Lookup.prototype.removeKey = function(key)
	{
		var value = this.systemLookup[key];
		this.systemArray.splice(this.systemArray.indexOf(value), 1);
		delete this.systemLookup[key];
	}
}

// deferred

Color.Instances = new Color_Instances();

// run

new TextToImageConverter().main();

</script>
</body>
</html>
Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

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