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/>'; }