Click here to Skip to main content
13,662,167 members
Click here to Skip to main content
Add your own
alternative version

Stats

3.6K views
6 bookmarked
Posted 27 May 2018
Licenced CPOL

JavaScript Image Upload for Async Server Processing

, 27 May 2018
Rate this:
Please Sign up or sign in to vote.
When uploading an image to a server, it will take few seconds to minutes to complete, depending on the complexity of the server operation and server performance. This article focuses on immediately displaying the image using JavaScript while it is being uploaded to the server.

Introduction

When uploading an image to a server using JavaScript, it can take from several seconds to minutes to complete the operation depending on the complexity of the server operation. In certain cases, even if the image is uploaded successfully it can take further time, depending on the server capacity to do additional processing of the image.

This article shows an approach with code samples to immediately show the image (using Base64 encoded version of the image), while it is being uploaded to a server without waiting for the operation to complete. The objective of this approach is to improve web application user experience without waiting for a server to do the entire processing of an image (e.g., Thumbnail Generation, Applying Filters, etc.) after the upload succeeds since it can use the image in Client Side for the immediate viewing inside the web application.

Background

This problem was initially encountered when using AWS S3 as the image storage. The image thumbnail setup was done using AWS Lambda, where after a successful image upload to S3 using JavaScript from the web application, S3 will trigger an AWS Lambda function asynchronously, which will generate the thumbnail of the image and store it in another S3 bucket. Although this is a highly scalable and reliable image thumbnail generation solution, it isn't realistic for the web application to wait till the thumbnail is generated to show it inside the immediate view of the application.

Using the Code

This code is written using VanillaJS without using any third-party JavaScript library so that if you are using any third-party frameworks, you can adapt the concept and implement it using the framework or library provided constructs.

Step 1: Load the Image to the Browser

<!DOCTYPE html>
<html>

<body>
    <img src="//:0" id="preview" />
    <input type="file" id="imageFileInput" accept=".jpg, .jpeg, .png" />
    <script>
        document.getElementById('imageFileInput').addEventListener('change', function() {
            var img = this.files[0];          
            // Image is accessible using JavaScript                  
        }, false);
    </script>
    ​​​​</body>

</html>

As shown in the above example, there are two HTML elements in the example. The <img> DOM element is there to show the selected image. The <input> DOM element is for the user to select the image file. Using JavaScript File API, it's possible to listen to the change event handler and load the image to access using JavaScript.

Step 2: Generate Base64 Thumbnail

<!DOCTYPE html>
<html>

<body>
    <img src="//:0" id="preview" />
    <input type="file" id="imageFileInput" accept=".jpg, .jpeg, .png" />
    <script>
        document.getElementById('imageFileInput').addEventListener('change', function() {
            var img = this.files[0];  
            // Image is accessible using JavaScript
            getBase64ImageUrl(img, function(getBase64ImageUrl) {
                setImageUrl(getBase64ImageUrl);
            });
        }, false);

        function setImageUrl(url) {
            document.getElementById('preview').setAttribute('src', url);
        };

        function getBase64ImageUrl(img, callback) {      
            var reader = new FileReader();      
            reader.readAsDataURL(img);      
            reader.onload = function() {        
                callback && callback(reader.result);      
            };      
            reader.onerror = function(error) {        
                console.log('Error: ', error);      
            };    
        };
    </script>
    ​​​​</body>

</html>

Once the image is accessible using JavaScript, it is loaded to the HTML5 FileReader and converted to the Base64 Data URL. Then the <img> DOM element is updated with the Base64 Data URL.

Step 3: Upload the File Using Ajax

<!DOCTYPE html>
<html>

<body>
    <img src="//:0" id="preview" />
    <input type="file" id="imageFileInput" accept=".jpg, .jpeg, .png" />
    <script>
        document.getElementById('imageFileInput').addEventListener('change', function() {
            var img = this.files[0];  
            // Image is accessible using JavaScript
            uploadImage(img, '/image/upload', function(response) {
                // Image upload to server response
                // Show the image using setImageUrl(URL)
            })
            getBase64ImageUrl(img, function(getBase64ImageUrl) {
                setImageUrl(getBase64ImageUrl);
            });
        }, false);

        function setImageUrl(url) {
            document.getElementById('preview').setAttribute('src', url);
        };

        function getBase64ImageUrl(img, callback) {      
            var reader = new FileReader();      
            reader.readAsDataURL(img);      
            reader.onload = function() {        
                callback && callback(reader.result);      
            };      
            reader.onerror = function(error) {        
                console.log('Error: ', error);      
            };    
        };

        function uploadImage(img, url, callback) {
            var xhr = new XMLHttpRequest();
            var fd = new FormData();
            xhr.open("POST", url, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    callback && callback(xhr.responseText);
                }
            };
            fd.append("upload_image", img);
            xhr.send(fd);
        };
    </script>
    ​​​​</body>

</html>

Using Ajax, the image upload is initiated to the server. Using JavaScript, an HTML form submission is asynchronously triggered and the exact code will differ based on the server implementation, especially in terms of HTTP method (e.g., here it is POST) and URL.

If the server, the response contains the image URL, it can be used to update the <img> DOM element accordingly or if the server maintains a proper image access path convention (e.g., /images/<image-file-name>), it can be used to load the image.

Step 4: (Optional) Client-side Thumbnail Generation

<!DOCTYPE html>
<html>

<body>
    <input type="file" id="imageFileInput" accept=".jpg, .jpeg, .png" />
    <img src="//:0" id="preview" />

    <script>
        document.getElementById('imageFileInput').addEventListener('change', function() {
            var img = this.files[0];
            uploadImage(img, '/image/upload', function(url) {
                // Image upload to server response
                // Show the image using setImageUrl(URL)
            });
            getBase64ImageUrl(img, function(base64ImageUrl) {
                var height = 100,
                    width = 100;
                getThumbnail(base64ImageUrl, height, width, function(base64ThumbnailUrl) {
                    setImageUrl(base64ThumbnailUrl);
                })
            });
        }, false);

        function setImageUrl(url) {
            document.getElementById('preview').setAttribute('src', url);
        };

        function uploadImage(img, url, callback) {
            var xhr = new XMLHttpRequest();
            var fd = new FormData();
            xhr.open("POST", url, true);
            xhr.onreadystatechange = function() {
                if (xhr.readyState == 4 && xhr.status == 200) {
                    callback && callback(xhr.responseText);
                }
            };
            fd.append("upload_image", img);
            xhr.send(fd);
        };

        function getBase64ImageUrl(img, callback) {
            var reader = new FileReader();
            reader.readAsDataURL(img);
            reader.onload = function() {
                callback && callback(reader.result);
            };
            reader.onerror = function(error) {
                console.log('Error: ', error);
            };
        };

        function getThumbnail(base64ImageUrl, height, width, callback) {
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext("2d");
            var image = new Image();
            image.src = base64ImageUrl;
            image.onload = function() {
                ctx.drawImage(image, 0, 0, width, height);
                callback && callback(canvas.toDataURL());
            };
        }
    </script>
</body>

</html>

It is also possible to generate the image thumbnail using HTML5 Canvas API. If your use case involves showing the thumbnail of the image in the web app immediately and if the thumbnail generation happens in the server asynchronously, it is still possible to show the thumbnail directly by resizing the image in Client-side using JavaScript.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ashan Fernando
Sri Lanka Sri Lanka
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180810.1 | Last Updated 28 May 2018
Article Copyright 2018 by Ashan Fernando
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid