66 Votes

HTML5: Upload Images with Client Side Resize

Tutorial by Stefan Trost | 2016-10-23 at 23:49

Images and pictures are becoming larger and larger today - often they are too big for reasonably displaying them on a website. Of course, it is possible to reduce the image after an upload via PHP, but this can be very resource consuming and should therefore be avoided in most cases.

This was the reason, I have written a tutorial in which I have described how to resize an image directly on client side in the browser for sending a reduced version of it to the server without using a server-side PHP script. However, the script introduced in that tutorial could only upload one image at once. Now, I want to explain how to upload multiple images at the same time in this tutorial.

Because large parts of the scripts are identical, I only want to describe the changes here. Please refer to the first tutorial linked above for all other explanations. Of course, you will find the full code at the end of this tutorial in complete length.

HTML

In our HTML, we only need to change one thing. We have to add the attribute "multiple" to our file input field.

<input id="inp_files" type="file" multiple="multiple">

With this, we are allowing the user to select multiple files.

JavaScript

Also the JavaScript code remains identical to the greatest extent. The first tutorial, we have read out the files using var file = e.target.files[0]. With doing that, we have only read out the first element of the array e.target.files (the first element has the index 0).

for (var i = 0; i < e.target.files.length; i++) { 
   var file = e.target.files[i];
}

Because now, we want to prepare for an arbitrary number of files, we have added a loop at this point beginning at the start index 0 and ending at the number of selected files at e.target.files.length. Within the loop, we are referring to the current file with var file = e.target.files[i]. Otherwise, we are proceeding like before.

document.getElementById('inp_img').value = dataURL;
document.getElementById('inp_img').value += dataURL + '|';

While in the first tutorial, we have directly stored the base64 encoded dataURL in the hidden field, now, we are instead appending the variable at the end of the existing content of the field. For this, we are using the delimiter "|" so that we can store multiple images in only one field.

PHP

We have extended our PHP code by a loop, too. However, first, we are using the function explode() to separate the single image data attached to each other again. After that, we are looping over all individual data sets in order to store each image individually.

$img = explode('|', $_POST['img']);

for ($i = 0; $i < count($img) - 1; $i++) {
   $image = $img[$i];
   // ...
   $file = 'uploads/img'.date("YmdHis").'_'.$i.$ext;
   // ...    
}

To ensure that the images do not have the same name (which would result in mutually overwriting), we are appending the counting variable $i is image number at the end of each filename.

The entire Page

Finally, here is the full changed and adjusted page for the multi-image-upload. This page contains the complete HTML, PHP and JavaScript code that is necessary.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
</head><body>

<?php

if (count($_POST)) {
	
  $img = explode('|', $_POST['img']);

  for ($i = 0; $i < count($img) - 1; $i++) {
	  
     if (strpos($img[$i], 'data:image/jpeg;base64,') === 0) {
        $img[$i] = str_replace('data:image/jpeg;base64,', '', $img[$i]);  
        $ext = '.jpg';
     }
     if (strpos($img[$i], 'data:image/png;base64,') === 0) { 
        $img[$i] = str_replace('data:image/png;base64,', '', $img[$i]); 
        $ext = '.png';
     }
	  
     $img[$i] = str_replace(' ', '+', $img[$i]);
     $data = base64_decode($img[$i]);
     $file = 'uploads/img'.date("YmdHis").'_'.$i.$ext;
	  
     if (file_put_contents($file, $data)) {
        echo "<p>Image $i was saved as $file.</p>";
     } else {
        echo '<p>Image $i could not be saved.</p>';
     }	
	  
  }
  
}
					 
?>


<input id="inp_files" type="file" multiple="multiple">

<form method="post" action="">
  <input id="inp_img" name="img" type="hidden" value="">
  <input id="bt_save" type="submit" value="Upload">
</form>


<script>

  function fileChange(e) { 
     document.getElementById('inp_img').value = '';

     for (var i = 0; i < e.target.files.length; i++) { 
	
        var file = e.target.files[i];

        if (file.type == "image/jpeg" || file.type == "image/png") {

           var reader = new FileReader();  
           reader.onload = function(readerEvent) {

              var image = new Image();
              image.onload = function(imageEvent) {	

                 var max_size = 300;
                 var w = image.width;
                 var h = image.height;
				  
                 if (w > h) {  if (w > max_size) { h*=max_size/w; w=max_size; }
                 } else     {  if (h > max_size) { w*=max_size/h; h=max_size; } }
			  
                 var canvas = document.createElement('canvas');
                 canvas.width = w;
                 canvas.height = h;
                 canvas.getContext('2d').drawImage(image, 0, 0, w, h);
                 if (file.type == "image/jpeg") {
                    var dataURL = canvas.toDataURL("image/jpeg", 1.0);
                 } else {
                    var dataURL = canvas.toDataURL("image/png");	
                 }
                 document.getElementById('inp_img').value += dataURL + '|';
              }
              image.src = readerEvent.target.result;
           }
           reader.readAsDataURL(file);
        } else {
           document.getElementById('inp_files').value = '';	
           alert('Please only select images in JPG- or PNG-format.');	
           return false;
        }
     }

  }

  document.getElementById('inp_files').addEventListener('change', fileChange, false);	
		
</script>

</body></html>

The page can be named as "upload_resize_multiple.php", for example.

ReplyPositiveNegativeDateVotes
Avatar
11 Vote

Really appreciated to you.

It is a very good job.
2018-02-17 at 18:58

ReplyPositive Negative
Avatar
00 Votes

Thank you so much, it's simple, clean and effective.... You're a life saver.
2018-03-18 at 04:29

ReplyPositive Negative
Avatar
11 Vote

Excellent... Very simple, clean and effective, you're a life saver, thank you so much.
2018-03-18 at 04:35

ReplyPositive Negative
Avatar
00 Votes

I must be doing something wrong, cause I can't get it to upload multiple images... It only uploads a single image each time...
2018-05-26 at 01:57

ReplyPositive Negative
Avatar
11 Vote

I want to save every image with it's original name. Tried with file.name but it's sending only the last image's file name. Please help.
2018-11-11 at 09:45

ReplyPositive Negative
Avatar
11 Vote

I'm not sure this is the best way.. But here's my quick fix for keeping the file name:

Add this hidden input to form:

<input id="inp_img_name" name="img_name" type="hidden" value="">

Then to javascript after "reader.readAsDataURL(file);" add:

document.getElementById('inp_img_name').value += file.name + '|';

In the php post after "$img = explode('|', $_POST['img']);" add:

$img_name = explode('|', $_POST['img_name']);

Finally change the file name assignment from "$file = 'uploads/img'.date("YmdHis").'_'.$i.$ext;" to:

$file = '../uploads/'.$img_name[$i];

That's it is.
2019-07-11 at 20:21

Positive Negative
Reply
Avatar
00 Votes

Hello, thanx a lot for this inspiration, I was near to it, but could not solve one detail.

Your solution brought me to a new way.

One question: I would need THE NAME OF THE SOURCE FOLDER (client side) passed to PHP to create the same folder on the server.

I can identify the single images in the loop:

var file = e.target.files[i];
alert("Filename " + file.name);

But how could I retrieve the name of the containing folder (or the whole path) and pass it to the server?

Thanx for helping. Stan
2019-01-26 at 20:19

ReplyPositive Negative
Avatar
00 Votes

I have a problem when I try to upload more than 2 images. Sometimes just 1 image upload. Do you know why?
2019-08-20 at 18:35

ReplyPositive Negative
Avatar
00 Votes

This is a very nice, but has one massive flaw. Uploading original files of 5 megs each causes a limit on how many images can be uploaded. Works fine with images already compressed and resized.
2020-09-14 at 16:31

ReplyPositive Negative
Reply

About the Author

AvatarYou can find Software by Stefan Trost on sttmedia.com. Do you need an individual software solution according to your needs? - sttmedia.com/contact
Show Profile

 

Related Topics

Important Note

Please note: The contributions published on askingbox.com are contributions of users and should not substitute professional advice. They are not verified by independents and do not necessarily reflect the opinion of askingbox.com. Learn more.

Participate

Ask your own question or write your own article on askingbox.com. That’s how it’s done.