-
-
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> |
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.
@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!
great