Upload an Image and Resize it Client-Side Before Posting

Allow User to Choose / "Upload" an Image and Resize it Client-Side Before Posting

This example shows you how to upload a jpg/jpeg or png image, resize it, and save it as a file.

This can also helpful when you wish to resize files before sending them to storage services like AWS S3, by reducing or eliminating the need for your server to handle resizing or image processing, outside of verification, etc..

Just follow the steps below to create the 3 files in your PHP environment.  Note, you can easily use any server-side handler since all is done client-side before posting!

Create a new file named form.html:

<!DOCTYPE html>

<html>
    <head>
        <script src="https://code.jquery.com/jquery-3.6.3.min.js" integrity="sha256-pvPw+upLPUjgMXY0G+8O0xUf+/Im1MZjXxxgOcBQBXU=" crossorigin="anonymous"></script>
        <script src="custom.js"></script>
    </head>
    <body>
        <form enctype="multipart/form-data" method="post" id="uploadImageForm" action="save.php">

            <div class="row">
                <div class="col-3"><label>Image</label></div>
                <div class="col-9">
                    <div class="input file">
                        <input type="file" name="imagefile" id="imagefile" class="form-control" 
                            onChange="uploadPhotos( $(this),'#{imageUploadUrl}')" 
                            multiple="NOT-IMPLEMENTED">
                    </div>
                </div>
            </div>

            <div class="row">
                <button type="submit" value="Upload" class="btn btn-primary btn-small btn-block">Upload</button>
            </div>
            <div>
                <label for="imageblob">Small: </label>
                <input type="blob" name="imageblob-sm" id="imageblob-sm" />
            </div>
            <div>
                <label for="imageblob">Medium: </label>
                <input type="blob" name="imageblob-md" id="imageblob-md" />
            </div>
            <div>
                <label for="imageblob">Large: </label>
                <input type="blob" name="imageblob-lg" id="imageblob-lg" />
            </div>
            
            <img src="" id="preview-sm" style="" />
            <img src="" id="preview-lg" style=""/>
            <img src="" id="preview-md" style="" />

        </form>
    </body>
</html>

 

Create a new file named custom.js and add the following to handle the file events for choosing the file:

window.uploadPhotos = function (formControl, url) {

    console.log('ATTR: ' + $(formControl).attr('data-target-lg') );

    //orig file desination
    console.log(url);
    
    // Read in file
    var file = event.target.files[0]; //first file only

    console.log(file);

    // Ensure it's an image
    //if (file.type.match('text.*|image.*|application.*')) {
    if (file.type.match('image.*')) {
        console.log('An image has been loaded');

        console.log('File Size: ' + file.size);

        // Load the image
        var reader = new FileReader();
        reader.onload = function (readerEvent) {
            var image = new Image();
            image.onload = function (imageEvent) {

                console.log(image.width);
                console.log(image.height);

                dataURL = resizeImage(image, file, 'imageblob-lg', null, 1, null); //original size, no preview
                dataURL = resizeImage(image, file, 'imageblob-md', null, .8, 1024); //med size, no preview
                dataURL = resizeImage(image, file, 'imageblob-sm', 'preview-sm', .7, 600); //small size, with preview


                //optional: trigger a custom event to let the app know the image has been resized
                /* $.event.trigger({
                    type: "imageResized",
                    blob: resizedImage,
                    url: dataUrl
                }); */
            }
            image.src = readerEvent.target.result;
        }
        reader.readAsDataURL(file);
    }
};

 

Next, add the following function to custom.js, to handle the actual image resize, preview image source, and populate the form fields for posting:

//resizes image, populates data field, and previews image
function resizeImage(image, file, dataTarget, previewTarget=null, previewQuality, previewSize=null) {

    if(previewSize == null) {
        //no resize
        var canvas = document.createElement('canvas');
        canvas.width = image.width;
        canvas.height = image.height;
        canvas.getContext('2d').drawImage(image, 0, 0, image.width, image.height);
    } else {
        //resize
        var canvas = document.createElement('canvas'),
            max_size = previewSize,// TODO : pull max size from a site config
            width = image.width,
            height = image.height;
        if (width > height) {
            if (width > max_size) {
                height *= max_size / width;
                width = max_size;
            }
        } else {
            if (height > max_size) {
                width *= max_size / height;
                height = max_size;
            }
        }
        canvas.width = width;
        canvas.height = height;
        canvas.getContext('2d').drawImage(image, 0, 0, width, height);
    }
    
    var dataUrl = canvas.toDataURL(file.type);
    var resizedImage = dataURLToBlob(dataUrl);

    var dataURL = canvas.toDataURL(file.type, previewQuality); //quality of the image
    var fd = new FormData(document.forms[0]);
    fd.append("canvasImage", resizedImage);

    //data field to populate for posting
    var resizeFileDestElement = '#' + dataTarget;
    $(resizeFileDestElement).val(dataURL);

    //image to preview
    if (previewTarget != null) {
        var origFilePreviewElement = '#' + previewTarget;
        $(origFilePreviewElement).attr('src', dataURL);
    }

    return dataUrl;

}

 

Next, add this utility to custom.js which converts canvas to a BLOB for posting:

/* Utility function to convert a canvas to a BLOB */
var dataURLToBlob = function (dataURL) {
    var BASE64_MARKER = ';base64,';
    if (dataURL.indexOf(BASE64_MARKER) == -1) {
        var parts = dataURL.split(',');
        var contentType = parts[0].split(':')[1];
        var raw = parts[1];

        return new Blob([raw], { type: contentType });
    }

    var parts = dataURL.split(BASE64_MARKER);
    var contentType = parts[0].split(':')[1];
    var raw = window.atob(parts[1]);
    var rawLength = raw.length;

    var uInt8Array = new Uint8Array(rawLength);

    for (var i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i);
    }

    return new Blob([uInt8Array], { type: contentType });
}
/* End Utility function to convert a canvas to a BLOB      */

 

Finally, in the custom.js file, add the following which will optionally handle client-side posting for your images (not discussed here):

/* Optional: Handle image resized events */
$(document).on("imageResized", function (event) {

    var data = new FormData($("form[id*='uploadImageForm']")[0]);
    if (event.blob && event.url) {
        data.append('image_data', event.blob); //append the blob to the form data
        /*
                $.ajax({
                    url: event.url,
                    data: data,
                    cache: false,
                    contentType: false,
                    processData: false,
                    type: 'POST',
                    success: function(data){
                    console.log(data);
                    }
                });
                */
    }

});

 

Lastly, create a file named save.php, and add the following to handle and save the posted & resized images:

<?php

//small
$data = $_POST['imageblob-sm'];
base64ToImage($data, 'sm');

//medium
$data = $_POST['imageblob-md'];
base64ToImage($data, 'md');

//large
$data = $_POST['imageblob-lg'];
base64ToImage($data, 'lg');

function base64ToImage($imageData, $size){

    list($type, $imageData) = explode(';', $imageData);
    list(,$extension) = explode('/',$type);
    list(,$imageData)      = explode(',', $imageData);
    $fileName = date("Y-m-d-h-i-s") . '-'. $size.'.'.$extension;
    $imageData = base64_decode($imageData);
    file_put_contents($fileName, $imageData);
}

echo 'done!';
echo '<br/><br/>Files List:<br/>';
$files = glob('*.*');
foreach($files as $file){
    echo $file . '<br/>';
}

Share this Post