This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 7 years ago.
I have this script which work (not in the if part) to check a picture dimension. the picture have to under 300x300 and this script always return false (even for 100x100 picture)
function validate_dimention(fileName) {
input = document.getElementById("profilepic");
file = input.files[0];
var reader = new FileReader();
var image = new Image();
var width;
var height;
reader.readAsDataURL(file);
reader.onload = function(pic) {
image.src = pic.target.result;
image.onload = function() {
width = this.width; //panjang
height = this.height; //lebar
}
}
if (width <= 300 && height <= 300) {
return true;
} else {
console.log(width);
console.log(height);
return false;
}
}
the console log always return both as undefined (so the code have no syntax eror),, is there a way so width equals to //panjang and height equals to //lebar??
This is because onload is an event, and is asynchronous. It will be called after the image loaded. Just move the condition inside the onload function to solve this. But, because of that asynchronous call, you'll not be able to return any value directly. You'll have to use a callback, where you'll do the code depending on the result:
function validate_dimention(fileName, callback) {
input = document.getElementById("profilepic");
file = input.files[0];
var reader = new FileReader();
var image = new Image();
var width;
var height;
reader.readAsDataURL(file);
reader.onload = function(pic) {
image.src = pic.target.result;
image.onload = function() {
width = this.width; //panjang
height = this.height; //lebar
if (width <= 300 && height <= 300) {
callback(true);
} else {
callback(false);
}
}
}
}
// And you call it that way :
validate_dimention(fileName, function (result) {
// Do whatever you want, using result as the result of your function. It 'll be either true or false.
});
Related
I just want to image being upload on my website must portrait or square and I don't want to crop image, image to be uploaded must be portrait or square by default I have searched number of website \ number method use but none worked
know I am trying this method but it also not working because it is running async
if give landscape image in given code it runs if which should not run as
hasError must be true but doesn't because if condition run before the above code could complete so what can I do
let hasError = false;
image = event.target.files[0];
if (image) {
var img = new Image();
img.src = window.URL.createObjectURL(image);
img.onload = function () {
height = img.naturalHeight;
width = img.naturalWidth;
console.log(hasError); // prints false
if (height < width) {
hasError = true; // prints true
console.log(hasError);
}
window.URL.revokeObjectURL(img.src);
}
console.log(hasError); //prints flase
}
if(!hasError){
....
}
I think you should create a function and move your image validation into your function and use a callback to find out the image has error or not.
var fileInput = document.querySelector('input[type="file"]');
var preview = document.getElementById('preview'); //img tag
previewImage(function(hasError){
if (!hasError){
//do something
}
});
function previewImage(callback){
fileInput.addEventListener('change', function(e) {
preview.onload = function() {
height = this.naturalHeight;
width = this.naturalWidth;
if (height < width) {
callback(true);
}
window.URL.revokeObjectURL(this.src);
callback(false);
};
var url = URL.createObjectURL(e.target.files[0]);
preview.setAttribute('src', url);
}, false);
}
So, i created the following function to check the file uploaded by user is
1) Image only
2) Size less than maxSize KBs
3) Dimensions less than maxWidth and maxHeight
All else is working fine except that the condition where I check dimensions. The value in dimensions is indeed the correct value but the condition if(dimensions) doesn't run even when dimensions=true.
Is there something I am doing wrong?
var maxThumbnailWidth = '1050';
var maxThumbnailHeight = '700';
var maxThumbnailSize = '60';
function imageFileChecks(file, type) // type here refers to either Image or Banner or Thumbnail
{
var maxSize;
var maxWidth;
var maxHeight;
var dimensions = false;
if (type == 'image') {
maxSize = maxImageSize;
maxWidth = maxImageWidth;
maxHeight = maxImageHeight;
}
if (type == 'banner') {
maxSize = maxBannerSize;
maxWidth = maxBannerWidth;
maxHeight = maxBannerHeight;
}
if (type == 'thumbnail') {
maxSize = maxThumbnailSize;
maxWidth = maxThumbnailWidth;
maxHeight = maxThumbnailHeight;
}
//First check file type.. Allow only images
if (file.type.match('image.*')) {
var size = (file.size / 1024).toFixed(0);
size = parseInt(size);
console.log('size is ' + size + ' and max size is ' + maxSize);
if (size <= maxSize) {
var img = new Image();
img.onload = function() {
var sizes = {
width: this.width,
height: this.height
};
URL.revokeObjectURL(this.src);
//console.log('onload sizes', sizes);
console.log('onload width sizes', sizes.width);
console.log('onload height sizes', sizes.height);
var width = parseInt(sizes.width);
var height = parseInt(sizes.height);
if (width <= maxWidth && height <= maxHeight) {
dimensions = true;
console.log('dimensions = ', dimensions);
}
}
var objectURL = URL.createObjectURL(file);
img.src = objectURL;
if (dimensions) {
alert('here in dimensions true');
sign_request(file, function(response) {
upload(file, response.signed_request, response.url, function() {
imageURL = response.url;
alert('all went well and image uploaded!');
return imageURL;
})
})
} else {
return errorMsg = 'Image dimensions not correct!';
}
} else {
return errorMsg = 'Image size not correct!';
}
} else {
return errorMsg = 'Image Type not correct!';
}
}
<div class="form-group">
<label class="col-md-6 col-xs-12 control-label">Thumbnail</label>
<div class="col-md-6 col-xs-12">
<input type="file" id="thumbnail" class="file" required>
<br>
</div>
</div>
<script type="text/javascript">
document.getElementById('thumbnail').onchange = function() {
var file = document.getElementById('thumbnail').files[0];
if (!file) {
console.log("ji");
return;
}
var type = 'thumbnail';
var thumbnailURL = imageFileChecks(file, type);
}
</script>
This seems like an async issue -- your if(dimensions) statement is running before your img.onload function finishes, in which case dimensions would be equal to false when you get to that part in your code, despite the img.onload function and its logic executing correctly.
You could try nesting the if(dimensions) condition in the img.onload function.
You set your dimension property inside the img.onload callback function.
This will not be executed directly. Then you check the value directly below, which will not be set yet. This is the nature of JavaScript: async functions being queued up to run at some time (example when an image finished loading).
To solve your problem, you need to make the rest of your function execute after img load. This can be done with either callback functions or promises.
I would read up on the asynchronous behavior a bit. Sorry for not providing a link, but should be plenty out there!
#William is right.You can handle it like that
function loadImage(src,callback){
var img = new Image();
img.onload = function() {
if (callback) {
callback(img);
}
}
img.src = src;
}
i've image uploader which using canvas and trying to get orientation using load-image.all.min.js is fine. but when i choose multiple image orientation parsing function saving data not one by one.
which means if i choose 1 image. it transferring data to 'upload_canvas.php?ori='+ori with correct ori variable.
but when i choose multiple image to upload example 3 images (with orientation 1, 1, 8)
it passing data to server upload_canvas.php?ori=8, upload_canvas.php?ori=8, upload_canvas.php?ori=8. only last ori variable.
maybe orientation parsing function already looped before uploading image data to server one by one.
how to transfer image with correct orientation to server?
below my using code.
document.querySelector('form input[type=file]').addEventListener('change', function(event){
// Read files
var files = event.target.files;
var ori = 1;
// Iterate through files
for (var i = 0; i < files.length; i++) {
// Ensure it's an image
if (files[i].type.match(/image.*/)) {
//Get image orienatation
loadImage.parseMetaData(files[i], function (data) {
if (data.exif) {
ori = data.exif.get('Orientation');
console.log("ori: "+ori);
} else {ori = 1;}
});
// Load image
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
canvas.width = image.width;
canvas.height = image.height;
drawImageIOSFix(canvas.getContext('2d'),image, 0, 0, image.width, image.height, 0, 0, width, height);
// Upload image
var xhr = new XMLHttpRequest();
if (xhr.upload) {
// Update progress
xhr.upload.addEventListener('progress', function(event) {
var percent = parseInt(event.loaded / event.total * 100);
progressElement.style.width = percent+'%';
}, false);
// File uploaded / failed
xhr.onreadystatechange = function(event) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
//some code
} else {
imageElement.parentNode.removeChild(imageElement);
}
}
}
xhr.open('post', 'upload_canvas.php?t=' + Math.random()+'&ori='+ori, true);
xhr.send(canvas.toDataURL('image/jpeg'));
}
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(files[i]);
}
}
// Clear files
event.target.value = '';});
Your variable ori is a global variable, that is shared between all images. The code in the .onload functions aren't run immediately, but only after your for() loop has gone through all the images. At this point ori will contain the orientation of the last image.
To fix, move the variable and parseMetaData into the reader.onload function.
...
var reader = new FileReader();
reader.onload = function (readerEvent) {
var ori;
loadImage.parseMetaData(files[i], ...)
var image = new Image();
image.onload = function (imageEvent) {
...
Warning: Not tested!
This is my each loop:-
var image_obj = {};
$(".wrapper").each(function (index, data) {
var dfile = this.getElementsByClassName('image')[0];
file = dfile.files[0];
if(file != null) {
var fr = new FileReader();
fr.onload = function (e) {
img = new Image();
img.onload = function (k) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
objindex = "obj_" + index;
image_obj[objindex] = canvas.toDataURL("image/jpeg");
};
img.src = fr.result;
};
fr.readAsDataURL(file);
}
});
I need the index of my each loop to save base_64 encoded image to an object.
But the index is not showing up in order as each loop execution finishes before reaching canvas.getContext("2d");.
One big problem is that you need to declare img inside your outer function:
$(".wrapper").each(function (index, data) {
var img;
The reason is that otherwise, img is a global. The img variable captured in your onload function just contains the current value of that global, which is just whatever the most recent each call assigned it to (likely the last wrapper in the jquery object). Then when onload is called, it writes the wrong image into the canvas. By declaring the variable, you ensure that each outer function scope has its very own img variable for your onload functions to capture, which they'll then use when they're actually applied.
Edit If you want to ensure that the outputed order is right, you should just sort it out at the end, since you don't control when onload runs; that's actually the beauty of it. I'd do something like this:
ctx.drawImage(img, 0, 0);
if (typeof(image_obj.images) == "undefined")
image_obj.images = [];
image_obj.images[index] = canvas.toDataURL("image/jpeg");
Or just make image_obj itself an array and just do:
ctx.drawImage(img, 0, 0);
image_arr[index] = canvas.toDataURL("image/jpeg");
Depending on whether you need the object as a container for other stuff.
Since that's an array, not an object, the images will be in order.
Edit 2
So the problem now is that you get holes in your array if some of the files aren't there. Let's make that not happen:
var index = -1;
$(".wrapper").each(function (_, data) {
...
if(file != null) {
var fr = new FileReader();
index++;
var localIndex = index; //to capture locally
fr.onload = function (e) {
...
ctx.drawImage(img, 0, 0);
image_arr[localIndex] = canvas.toDataURL("image/jpeg");
..
The below handleFiles method is being passed files from both drag and drop and a file input. After it gets the data url for a given file it passes it to the processImage function. This function creates a new image and sets the src and file for that image. I then take different actions based on the width of the incoming image and insert the image into the dom. However, I noticed when dropping in a bunch of images imageWidth will get set to 0. I have confirmed the image.src is correctly set and that dropping the same image in by itself works fine. I also have confirmed that if I remove the width calculations the image does display correctly on the page. When I enter the debugger I can confirm that immediately after imageWidth is set to 0 i.width returns a correct value. At first I thought it might be a threading issue in Chrome, but then when I saw it happen in FireFox as well I became alarmed. I have not been able to pinpoint a certain threshold, but the more load you put on the browser the less likely it is to correctly get the width.
I am seeing the problem in both FireFox 16.0.2 and Chrome 23.0.1271.95.
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
if( !isImage(file) ) {
continue;
}
var reader = new FileReader();
reader.onloadend = function(e) {
var dataURL = e.target.result;
processImage(file, dataURL);
}
reader.readAsDataURL(file);
}
}
function processImage(file, dataURL) {
var i = new Image();
i.src = dataURL;
i.file = file;
//console.log(i);
var maxWidth = 600;
var imageWidth = i.width;
......
}
As with all images, they may need time to load before they will tell you their width:
var i = new Image();
i.onload = function() {
//console.log(i);
var maxWidth = 600;
var imageWidth = this.width;
}
i.src = dataURL;
i.file = file;
The width (and height) might be 0 because it's not loaded yet.
Try adding the load event like so:
function processImage(file, dataURL) {
var i = new Image();
i.addEventListener("load", function () {
var maxWidth = 600;
var imageWidth = i.width;
......
});
i.src = dataURL;
i.file = file;
}