Use sprites to reduce number of requests on website – Javascript, PHP

Generate sprite image

Sprite is a computer graphics term for a two-dimensional bitmap that is integrated into a larger scene, most often in a 2D video game. Which means that small images are combined into one large image to reduce the number of requests on your server.

Sprites helps a lot in reducing HTTP requests. In CSS sprites, we combine multiple images into a single image. So, if you are using 12 small images in your CSS, it will take 12 requests without sprite. Now if you combine all these images into one image, you will need only 1 request.

The basic principle is, you will combine multiple images into one large image. When you try to access it, the web server will not fetch the new copy of each image everytime you request it. Instead it will fetch just one image which contains all images and you can display them by specifying their position. Same as the image above.

So we will first combine all necessary images into one image and save it as a “sprite.png”. Then we will display the image by telling it’s position. We will be using two files, 1st for combining multiple images into one (save-sprite.php) and 2nd to display the images from sprite.

Generate sprites

First we create an HTML5 canvas tag where all images will be drawn. Give it unique ID to be accessible in Javascript and give it appropriate width and height.

Then we create an array of images which holds width, height and path (src) of each image. We will be looping through this array to automatically draw image on canvas. Also a counter variable to tell the number of current image under process.

Then we get the canvas object and 2D context of canvas. Create a variable named marginLeft to automatically draw the image after the previous one. If this is not specified, then all images will be placed on top of other.

After that, you will create a recursive function that will draw all images inside the array. Inside this function, create a new Image() object and set the image path in src attribute. Call onload function with this image object to wait for the image to fully loaded. The draw the image using drawImage(imageObj, x, y, width, height) function that will render the image on canvas.

Increase margin from left for next image, increment the counter. If there is more images in array then recursion occurs by calling the function itself inside the function. Otherwise if all images are rendered then we will convert that canvas into image and call an AJAX function to save this image data as a sprite.

<!-- Canvas where all images will be drawn -->
<canvas id="myCanvas" width="1000" height="500"></canvas>

<script>

	// An array where all images should be entered
	var images = [{
		width: 308,
		height: 183,
		src: "image1.png"
	}, {
		width: 206,
		height: 260,
		src: "image2.png"
	}];

	// A variable used to get the number of current image
	var count = 0;

	// Get canvas element
	var c = document.getElementById("myCanvas");

	// Get canvas context used for drawing
	var ctx = c.getContext("2d");

	// Give margin to each image so they will be aligned horizontally
	var marginLeft = 0;

	// A recursive function which will keep calling itself
	// until all images are drawn on canvas
	function loadImage() {
		// Create new image object
		var imageObj = new Image();

		// Set the path of image
		imageObj.src = images[count].src;

		// Wait till image fully loaded
		imageObj.onload = function() {
			// Draw image on canvas given image object, x, y, width & height
			ctx.drawImage(imageObj, marginLeft, 0, images[count].width, images[count].height);

			// Increase margin from left
			marginLeft += images[count].width;

			// Increment to next image
			count++;

			// If there is more image to draw
			if (count < images.length) {
				// Recursive occur here
				loadImage();
			} else {
				// All images has been drawn on canvas
				console.log("All images loaded");

				// Convert the canvas into PNG image
				var image = c.toDataURL("image/png", 1);

				// Create AJAX request object
      			var ajax = new XMLHttpRequest();

      			// Set method to POST, file name and asynchnronous
				ajax.open("POST", "save-sprite.php", true);

				// Set headers in POST request
				ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

				// Send the request and pass image data
				ajax.send("image=" + image);

				// Listen for server request changes
				ajax.onreadystatechange = function () {

					// Request is successful if ready state is 4 and status is 200
					if (this.readyState == 4 && this.status == 200) {
						// Print response sent from server
						console.log(this.responseText);
					}
				};
			}
		}
	}

	loadImage();
</script>

Save sprite image

Create a new file named “save-sprite.php” and paste the following code in it. This will give the image data from client and remove the “base64” part from it as that is not necessary. When using AJAX post request we should also convert all spaces into plus sign and then decode the base64 string. Finally you can save the image as separate file.

<?php

$image = $_POST["image"];
$image = explode(";", $image)[1];
$image = explode(",", $image)[1];
$image = str_replace(" ", "+", $image);

$image = base64_decode($image);
file_put_contents("sprite.png", $image);

echo "Done";
?>

Display image from sprite

To display an image we will create a <div> tag and set the background image as sprite. Given the background position allow you to display specific portion of sprite image. For example, if your sprite has 3 images of 100px width each, then your total sprite will be of 300px in width. To display the second image you have give the background position as -100px so it will move the image from left to right.

<style>
	#home {
		width: 308px;
		height: 183px;
		background: url('sprite.png');
		background-repeat: no-repeat;
	}

	#next {
		width: 206px;
		height: 260px;
		background: url('sprite.png');
		background-repeat: no-repeat;
		background-position: -308px 0px;
	}
</style>
<div id="home"></div>
<br>
<div id="next"></div>

Conclusion

Sprites are very useful specially in video games where optimization and performance is very important. So instead of loading all car’s types (Lamborghini, Bugatti, Ferrari, Mclaren) as 4 images they create a single sprite named “cars-sprite.png” which holds all the images of cars. This is just an example, you can categories the sprites as much as required. The point is to send minimum requests on the server.

Hope that helps you in your upcoming or legacy projects to reduce the number of HTTP requests using sprites. If you face any problem, feel free to ask in the comment’s section below.

Leave a Reply

Please disable your adblocker or whitelist this site!