-
-
Save ORESoftware/ba5d03f3e1826dc15d5ad2bcec37f7bf to your computer and use it in GitHub Desktop.
// Using this code, we can retrieve an image from a user's filesystem, resize the image, and then upload the image | |
// to a server using AJAX. Because we use base64 encoding, we can just include the image data as just another string value | |
// in a JSON payload. | |
// So we can use AJAX to send the file to a server, which is convenient. | |
// We have one line of relevant html | |
// get file in the first place => <input type="file" custom-on-change="onAcqImageFileChange" class="form-control"> | |
$scope.onAcqImageFileChange = function (e) { | |
e.preventDefault(); | |
var file = e.target.files[0]; | |
$scope.acqImageFile = file; // store reference to file | |
}; | |
function convertToBase64(file, cb) { | |
var reader = new FileReader(); | |
reader.onload = function (e) { | |
cb(null, e.target.result) | |
}; | |
reader.onerror = function (e) { | |
cb(e); | |
}; | |
reader.readAsDataURL(file); | |
} | |
function resizeImage(base64Str) { | |
var img = new Image(); | |
img.src = base64Str; | |
var canvas = document.createElement('canvas'); | |
var MAX_WIDTH = 400; | |
var MAX_HEIGHT = 350; | |
var width = img.width; | |
var height = img.height; | |
if (width > height) { | |
if (width > MAX_WIDTH) { | |
height *= MAX_WIDTH / width; | |
width = MAX_WIDTH; | |
} | |
} else { | |
if (height > MAX_HEIGHT) { | |
width *= MAX_HEIGHT / height; | |
height = MAX_HEIGHT; | |
} | |
} | |
canvas.width = width; | |
canvas.height = height; | |
var ctx = canvas.getContext('2d'); | |
ctx.drawImage(img, 0, 0, width, height); | |
return canvas.toDataURL(); | |
} | |
$scope.submitImageSelection = function () { | |
// when the user finally selects the image they want, and clicks submit, we run this fn | |
var imgFile = $scope.acqImageFile; | |
convertToBase64(imgFile, function (err, data) { | |
if (err) { | |
/// handle error | |
return; | |
} | |
// resize the image like a boss | |
data = resizeImage(data); | |
// finally we can send the data to a server as | |
// just another field in a JSON payload | |
SomeService.sendDataToServer(data, function(err){ | |
// voila | |
}); | |
}); | |
}; | |
// note that to display the image selection back to the user before they choose their final selection, you may want to convert to | |
// base64 each time they change selections. | |
// to display the image, you can use ng-src: | |
// <img class="overlay-image" ng-src="{{acqImageData ? acqImageData : '/assets/img/placeholder.png'}}"> | |
// <the end> |
@odyssic No, this doesn't make yout file size smaller (it should even decrease, but very little) so that i recommend is compress your file with any compressor that you find in the internet (like this https://compressjpeg.com/) or make your compressor (like this https://stackoverflow.com/questions/14672746/how-to-compress-an-image-via-javascript-in-the-browser)
Does this preserve image quality? Reducing dimensions of a canvas destroys the image quality when you're scale it down.
@sadikyalcin it depends on how much you're going to compress, in my tests the quality hasn't changed that much
Here are the image tests I did. Logically, the more I change its scaling, the more quality is lost, but the loss is not so much.
@gs-nasc That is acceptable. I've done a few myself and got slightly better results by passing the native type and 1
to toDataUrl
method (canvas.toDataURL('image/png', 1)
.
and how to make unit tests for this function ?
Hello, it wasn't work for me, so i change somethings:
function
resizeImage
:function resizeImage(base64Str, maxWidth = 400, maxHeight = 350) { return new Promise((resolve) => { let img = new Image() img.src = base64Str img.onload = () => { let canvas = document.createElement('canvas') const MAX_WIDTH = maxWidth const MAX_HEIGHT = maxHeight let width = img.width let height = img.height if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width width = MAX_WIDTH } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height height = MAX_HEIGHT } } canvas.width = width canvas.height = height let ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, width, height) resolve(canvas.toDataURL()) } }) }Usage:
resizeImage(e.target.result, 1000, 1000).then((result) => { console.log(result); });Thanks for the code
Except this doesn't make the file size smaller, correct? Because it is still a string regardless of the image dimensions? I'm working with base64 but the page loads so slowly and I see a loooong string loading.
It does make the file size smaller because a smaller dimensioned image means less pixels. If you want to further reduce file size, use canvas.toDataURL('image/jpeg', 0.8)
instead of just canvas.toDataURL()
, since by default it saves it as a PNG with max quality. Using JPEG format at 80% quality is hardly noticeable in terms of image appearance, but the image size is much much smaller.
This is awesome, thanks!
amazing, thanks!
Except this doesn't make the file size smaller, correct? Because it is still a string regardless of the image dimensions? I'm working with base64 but the page loads so slowly and I see a loooong string loading.