PROWAREtech

articles » current » javascript » download-images-with-progress-indicator

JavaScript: Download Images with Progress Indicator Bar

How to download images to the browser while showing the user a percent completion of the download while they wait.

This prototype function Image.progressload() will download an image and issue calls to a progress callback function while the download is happening. See code notes for more information.

This code is compatible with Internet Explorer 11 (IE11) if still developing for this browser.


// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
	var this_img = this, xhr = new XMLHttpRequest();

	xhr.open("get", image_url, true);
	xhr.responseType = "arraybuffer";

	xhr.onload = function () {

		var blob = new Blob([this.response]);
		this_img.src = URL.createObjectURL(blob);

		if (typeof done_callback == "function") {
			done_callback(this_img);
		}
		setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
	};

	xhr.onprogress = function (ev) {
		if (ev.lengthComputable && typeof progress_callback == "function") {
			progress_callback((ev.loaded / ev.total) * 100);
		}
	};

	xhr.onloadstart = function () {
		if (typeof progress_callback == "function") {
			progress_callback(0);
		}
	};

	xhr.onloadend = function () {
		if (typeof progress_callback == "function") {
			progress_callback(100);
		}
	}

	xhr.send();
};

Here is an alternate version that, under heavy load and usage is not as reliable due to a bug in Chrome/Edge, but it should work best, certainly if and when the bug is fixed. This is the best code!


// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
	var this_img = this, xhr = new XMLHttpRequest();

	if (typeof done_callback == "function") {
		this_img.onload = function () {
			done_callback(this_img);
		};
	}

	xhr.open("get", image_url, true);
	xhr.responseType = "arraybuffer";

	xhr.onload = function () {

		var blob = new Blob([this.response]);
		this_img.src = URL.createObjectURL(blob);
		setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
	};

	xhr.onprogress = function (ev) {
		if (ev.lengthComputable && typeof progress_callback == "function") {
			progress_callback((ev.loaded / ev.total) * 100);
		}
	};

	xhr.onloadstart = function () {
		if (typeof progress_callback == "function") {
			progress_callback(0);
		}
	};

	xhr.onloadend = function () {
		if (typeof progress_callback == "function") {
			progress_callback(100);
		}
	}

	xhr.send();
};

An example HTML page using the above prototype. It has a very much not elegant red progress bar that shows the progress of the download and then displays the image when it is done with its download. NOTE: this only works well on large images.


<!DOCTYPE html>
<html lang="en-us">
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>Download Images with Progress Using JavaScript</title>
	<style>
		body {
			margin: 0;
			padding: 0;
		}
		img {
			width: 100%;
			height: auto;
		}
	</style>
</head>
<body>
	<div class="page">
<script type="text/javascript">
// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
	var this_img = this, xhr= new XMLHttpRequest();

	xhr.open("get", image_url, true);
	xhr.responseType = "arraybuffer";

	xhr.onload = function () {

		var blob = new Blob([this.response]);
		this_img.src = URL.createObjectURL(blob);

		if (typeof done_callback == "function") {
			done_callback(this_img);
		}
		setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
	};

	xhr.onprogress = function (ev) {
		if (ev.lengthComputable && typeof progress_callback == "function") {
			progress_callback((ev.loaded / ev.total) * 100);
		}
	};

	xhr.onloadstart = function () {
		if (typeof progress_callback == "function") {
			progress_callback(0);
		}
	};

	xhr.onloadend = function () {
		if (typeof progress_callback == "function") {
			progress_callback(100);
		}
	}

	xhr.send();
};

window.onload = function () {
	var img = new Image();
	img.progressload("/img/blob.jpg?v=" + Number(new Date()), function (percent) { // NOTE: specify a parameter to force a new download
		var prog = document.getElementById("progress");
		prog.style.width = percent + "%";
		prog.innerText = Math.round(percent) + "%";
	}, function (image) {
		document.body.appendChild(image);
	});
};
</script>
<div style="background-color:transparent;height:25px;width:100%;text-align:left;">
	<div id="progress" style="display:inline-block;background-color:red;color:white;height:inherit;width:0;overflow:hidden;line-height:25px;"></div>
</div>

</body>
</html>

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE