An Image Combiner in JavaScript

The JavaScript code below, when run, presents an interface that allows the user to upload a collection of image files, and then display and download all those images as a single combined image incorporating the original images in a grid.


<html>

<body>

<div id="divUI">

	<h3>Image Combiner</h3>

	<p>Upload one or more images and click the button to combine them into a single image and download them.</p>

	<label>Image File to Upload:</label>
	<br />
	<input type="file" multiple="true" onchange="inputImageFileToUpload_Changed(this);"></input>
	<div id="divImagesUploaded"></div>

	<label>Images per Row:</label>
	<br />
	<input id="inputImagesPerRow" type="number"></input>
	<br />

	<button onclick="buttonRenderAsSingleImage_Clicked();">Render As Single Image</button>
	<button onclick="buttonDownloadAsSingleImage_Clicked();">Download As Single Image</button>
	<br />

	<label>Combined Image:</label>
	<div id="divImageCombined"></div>
</div>

<script type="text/javascript">

// UI event handlers.

function buttonDownloadAsSingleImage_Clicked()
{
	var d = document;

	this.buttonRenderAsSingleImage_Clicked();

	var divImageCombined = d.getElementById("divImageCombined");
	var imageCombinedAsCanvas = divImageCombined.children[0];
	if (imageCombinedAsCanvas != null)
	{
		var imageCombinedAsDataUrl =
			imageCombinedAsCanvas.toDataURL("image/png");
		var imageCombinedAsLink = d.createElement("a");
		imageCombinedAsLink.href = imageCombinedAsDataUrl;
		imageCombinedAsLink.download = "Combined.png";
		imageCombinedAsLink.click();
	}
}

function buttonRenderAsSingleImage_Clicked()
{
	var d = document;
	var divImagesUploaded = d.getElementById("divImagesUploaded");
	var inputImagesPerRow = d.getElementById("inputImagesPerRow");

	var imagesAsImgElements = divImagesUploaded.children;

	var imageCount = imagesAsImgElements.length;

	var imagesPerRow = parseInt(inputImagesPerRow.value);
	if (isNaN(imagesPerRow))
	{
		imagesPerRow = imageCount;
	}

	var imageWidthMaxSoFar = 0;
	var imageHeightMaxSoFar = 0;

	for (var i = 0; i < imageCount; i++)
	{
		var imageAsImgElement = imagesAsImgElements[i];
		if (imageAsImgElement.width > imageWidthMaxSoFar)
		{
			imageWidthMaxSoFar = imageAsImgElement.width;
		}
		if (imageAsImgElement.height > imageHeightMaxSoFar)
		{
			imageHeightMaxSoFar = imageAsImgElement.height;
		}
	}

	var rowCount = Math.ceil(imageCount / imagesPerRow);
	var combinedWidth = imageWidthMaxSoFar * imagesPerRow;
	var combinedHeight = imageHeightMaxSoFar * rowCount;

	var imageCombinedAsCanvas = d.createElement("canvas");
	imageCombinedAsCanvas.width = combinedWidth;
	imageCombinedAsCanvas.height = combinedHeight;

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

	for (var i = 0; i < imageCount; i++)
	{
		var imageAsImgElement = imagesAsImgElements[i];

		var drawPosInImagesX = i % imagesPerRow;
		var drawPosInImagesY = Math.floor(i / imagesPerRow);

		var drawPosInPixelsX =
			drawPosInImagesX * imageWidthMaxSoFar;
		var drawPosInPixelsY =
			drawPosInImagesY * imageHeightMaxSoFar;

		graphics.drawImage
		(
			imageAsImgElement, drawPosInPixelsX, drawPosInPixelsY
		);
	}

	var divImageCombined = d.getElementById("divImageCombined");
	divImageCombined.innerHTML = "";
	divImageCombined.appendChild(imageCombinedAsCanvas);
}

function inputImageFileToUpload_Changed(inputImageFileToUpload)
{
	var d = document;

	var filesToUpload = inputImageFileToUpload.files;

	for (var i = 0; i < filesToUpload.length; i++)
	{
		var file = filesToUpload[i];
		if (file != null && file.type.match("image.*"))
		{
			var fileReader = new FileReader();
			fileReader.onload = (event) =>
			{
				var imageUploadedAsImgElement =
					d.createElement("img");
				imageUploadedAsImgElement.src =
					event.target.result;
				var divImagesUploaded =
					d.getElementById("divImagesUploaded");
				divImagesUploaded.appendChild(imageUploadedAsImgElement);
			};
			fileReader.readAsDataURL(file);
		}
	}
}

</script>

</body>

</html>

This entry was posted in Uncategorized. Bookmark the permalink.

3 Responses to An Image Combiner in JavaScript

  1. Erick Marques - I love Brazil! says:

    Hello, congratulations on all your amazing projects, even more for sharing them with us.

    Would it be possible to create a directory system, where the user would create as many folders and files as desired and then save it, using Blob, to save in the downloads folder as .tar, using pure jscript?

    Example:

    | —- Folder_1
    | | —- SubFolder_1
    | | | — Image_1.jpeg
    | | | — Image_2.jpeg
    | | | — Image_3.jpeg
    | | | — Image_4.jpeg
    | | —- SubFolder_2
    | | | — Image_Final.jpeg

    1- “Folder_1” is where all the files that the client created and used are, and will be downloaded as a “.tar” file.

    2- The “SubFolder_1”, is the folder that the customer created, to save the images that will be combined; “Image_1.jpeg, Image_2.jpeg, Image_3.jpeg, Image_4.jpeg”.

    3- And finally “SubFolder_2”, is the folder that the client created, to save the “Imagem_Final.jpeg”, which was the name he gave to save the combined image.

    The Lord could, help me or give a tip. I hope it was clear, and that Google Translate, translated correctly, because I only have a command of Brazilian Portuguese.

    Thanks in advance for everything.

  2. Certainly it’s possible. I have written a Tar library in JavaScript that may or may not be helpful. It lets you load a .tar file, add or remove directories and files, and then download it again. It’s hosted on Github, at the URL https://github.com/thiscouldbebetter/TarFileExplorer.

    • Erick Marques - Eu amo o Brasil! says:

      Thank you for the speed of your response!

      But that’s what it is. Do you remember the multdoc editor, which by the way is very good: “https://thiscouldbebetter.wordpress.com/2017/03/24/a-multiple-text-document-editor-in-javascript/”.

      Well then it would be more or less like that model, in which you add the files, however, I would like to be able to create a folder too, according to the necessary needs.

      If not, that’s fine. I’ll take a closer look at your library.

      Thank you for the patience! 🙂

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s