Slicing an Image into Tiles in JavaScript

When dealing with a large number of images, sometimes it’s easier to group all of them in a single file rather than making a file for each image. This may make it easier to track related images, say, a group of sprites for a video game character. It can also make for more efficient compression, since you don’t need to store as much overhead as you would for a bunch of individual image files. Coincidentally, it also makes it easier to download test images for programs listed in blog posts.

The program shown loads a single image file (provided below as “RedGreenBlueYellow.png”) and breaks it into a bunch of equally sized tiles. To see it in action, copy the code into an .html file, save the image “redgreenblueyellow.png” from this post into the same directory, and then open the html file in a web browser that runs JavaScript.

Note that certain browsers may have security features that throw errors if the HTML5 Canvas object’s toDataURL() function is called under certain circumstances. For example, to run the program in Google’s Chrome browser, it is necessary to run “chrome.exe” with the “–allow-file-access-from-files” switch.

UPDATE 2016/05/24 – I have cleaned up this code somewhat to more closely adhere to the way I do things now.

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

// main

function ImageSlicingTest()
{
	// main class
}
{
	ImageSlicingTest.prototype.main = function()
	{	
		var imageToSlice = new Image();
		imageToSlice.onload = this.main2.bind(this);
		imageToSlice.src = "RedGreenBlueYellow.png";
	}

	ImageSlicingTest.prototype.main2 = function(event)
	{
		var imageToSlice = event.target;

		var imageTiles = new ImageHelper().sliceImageIntoTiles
		(
			imageToSlice,
			new Coords(4, 1)
		);

		var imageTileSize = new Coords(imageTiles[0].width, imageTiles[0].height);

		for (var i = 0; i < imageTiles.length; i++)
		{
			var imageTile = imageTiles[i];

			var drawPos = new Coords(i * 2, 0).multiply(imageTileSize);

			imageTile.style.left = drawPos.x;
			imageTile.style.top = drawPos.y;
			document.body.appendChild(imageTile);	
		}				
	}
}

// classes

function Coords(x, y)
{
	this.x = x;
	this.y = y;
}
{
	Coords.prototype.clone = function()
	{
		return new Coords(this.x, this.y);
	}

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

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

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

	Coords.prototype.toString = function()
	{
		return "(" + this.x + "," + this.y + ")";
	}
}

function ImageHelper()
{
	// do nothing
}
{
	ImageHelper.prototype.sliceImageIntoTiles = function(imageToSlice, sizeInTiles)
	{
		var returnImages = [];

		var imageToSliceSize = new Coords(imageToSlice.width, imageToSlice.height);
		var tileSize = imageToSliceSize.clone().divide(sizeInTiles);

		var tilePos = new Coords(0, 0);
		var sourcePos = new Coords(0, 0);

		for (var y = 0; y < sizeInTiles.y; y++)
		{
			tilePos.y = y;

			for (var x = 0; x < sizeInTiles.x; x++)
			{							
				tilePos.x = x;

				var canvas		 = document.createElement("canvas");
				canvas.id		 = "tile_" + x + "_" + y;
				canvas.width		 = tileSize.x;
				canvas.height		 = tileSize.y;
				canvas.style.position	 = "absolute";

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

				sourcePos.overwriteWith(tilePos).multiply(tileSize);

				graphics.drawImage
				(
					imageToSlice,
					sourcePos.x, sourcePos.y, // source pos
					tileSize.x, tileSize.y, // source size
					0, 0, // destination pos
					tileSize.x, tileSize.y // destination size
				);

				// browser dependent?
				var imageFromCanvasURL = canvas.toDataURL("image/png");
				var imageFromCanvas = document.createElement("img");
				imageFromCanvas.width = canvas.width;
				imageFromCanvas.height = canvas.height;
				imageFromCanvas.style.position = "absolute";
				imageFromCanvas.src = imageFromCanvasURL;

				returnImages.push(imageFromCanvas);
			}
		}

		return returnImages;
	}
}

// run

var program = new ImageSlicingTest();
program.main();

</script>
</body>
</html>

This entry was posted in Uncategorized and tagged , , . 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