FileReader onload callback - javascript

my main goal is to return false out of _validateFile if a File (that is a jpeg) does not have the minimum dimensions. The issue I am having is that it looks like code underneath is getting hit and I can't return false out of _validateFile. I think I have to use a closure but I am not sure. Here is some code:
_validateFile: function(file){
var validDim = 1;
this._helper(file, function(x,y){
if(x < 682 || y < 459){
validDim = 2;
} else{
validDim = 3;
}
});
if(validDim == 2) return false;
else if(validDim == 3) return true;
return true;
},
_helper: function(file, callback){
var fr = new FileReader;
fr.onload = function() {
var img = new Image;
img.onload = function(){
var x = img.width;
var y = img.height;
callback(x,y);
}
img.src = fr.result;
};
fr.readAsDataURL(file);
},
Any pointers in the right direction are greatly appreciated.
Thank you!

you missing '()' to invoke a constructor
var fr = new FileReader();
var img = new Image();
Could you give some detail code about the way you use this object method (_validateFile)?

Related

javascript Callback function fail

So I am having a code which using callback due to async script,, and now when I try it, i got lost can somebody help me how to fix my code? this script was to check if a picture dimension was less than 300x300 or not
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; // url.createObjectURL(file);
image.onload = function() {
width = this.width;
height = this.height;
if (width <= 300 && height <= 300) {
callback(true);
} else {
callback(false);
}
};
};
}
validate_dimention(fileName, function (result) {
return function (result);
});

javascript drawImage() issues

Currently having some issues with drawImage();. Namely it wont actually draw. I tried it out with fillRect(); and it worked aswell as putting the drawImage(); inside the the onload function aswell (which worked).
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 640;
canvas.height = 400;
document.body.appendChild(canvas);
var tileArray = [
[0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,0,0,1,0,0,0],
[0,0,0,1,1,1,1,0,1,1,1,0,0],
[0,0,0,1,1,1,0,0,0,0,1,1,0],
[0,0,0,1,1,1,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0]
];
var grassReady = false;
var grass = new Image();
grass.onload = function() {
grassReady = true;
};
grass.src = "images/grass.png";
var sandReady = false;
var sand = new Image();
sand.onload = function() {
sandReady = true;
};
sand.src = "images/sand.png";
var posX = 0;
var posY = 0;
if(grassReady) {
ctx.drawImage(grass, posX, posY);
}
Any pointers as to why this is would be greatly appreciated and I appologize in advance if messed up the code section in anyway. I went through other similar posts and coulden't find a solution that seemed to work.
As #Suman Bogati correctly says, you must wait for your images to load before using them in drawImage.
A Demo: http://jsfiddle.net/m1erickson/jGPGj/
Here's an image loader that preloads all images and then calls the start() function where you can use drawImage because all the images are fully loaded.
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgs=[];
imageURLs.push("images/grass.png");
imageURLs.push("images/sand.png");
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
function start(){
// the imgs[] array holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
// grass.png is in imgs[0]
// sand.png is in imgs[1]
}
This statement ctx.drawImage(); should be inside the grass.onload = function() {} function, something like
grass.onload = function() {
ctx.drawImage(grass, posX, posY);
}
If you define drawImage() outside the grass.onload() function, then that statment would executed first, so at that point grassReady is false, So the condition is not satisfied.
Bascially it's related to asynchronous concept.
Your code is running into order
1) First
var grassReady = false;
if(grassReady) {
//grassReady is false, this condition is not satisfied
ctx.drawImage(grass, posX, posY);
}
2) Second
grass.onload = function() {
grassReady = true;
};

Check image width and height before upload with Javascript

I have a JPS with a form in which a user can put an image:
<div class="photo">
<div>Photo (max 240x240 and 100 kb):</div>
<input type="file" name="photo" id="photoInput" onchange="checkPhoto(this)"/>
</div>
I have written this js:
function checkPhoto(target) {
if(target.files[0].type.indexOf("image") == -1) {
document.getElementById("photoLabel").innerHTML = "File not supported";
return false;
}
if(target.files[0].size > 102400) {
document.getElementById("photoLabel").innerHTML = "Image too big (max 100kb)";
return false;
}
document.getElementById("photoLabel").innerHTML = "";
return true;
}
which works fine to check file type and size. Now I want to check image width and height but I cannot do it.
I have tried with target.files[0].width but I get undefined. With other ways I get 0.
Any suggestions?
The file is just a file, you need to create an image like so:
var _URL = window.URL || window.webkitURL;
$("#file").change(function (e) {
var file, img;
if ((file = this.files[0])) {
img = new Image();
var objectUrl = _URL.createObjectURL(file);
img.onload = function () {
alert(this.width + " " + this.height);
_URL.revokeObjectURL(objectUrl);
};
img.src = objectUrl;
}
});
Demo: http://jsfiddle.net/4N6D9/1/
I take it you realize this is only supported in a few browsers. Mostly firefox and chrome, could be opera as well by now.
P.S. The URL.createObjectURL() method has been removed from the MediaStream interface. This method has been deprecated in 2013 and superseded by assigning streams to HTMLMediaElement.srcObject. The old method was removed because it is less safe, requiring a call to URL.revokeOjbectURL() to end the stream. Other user agents have either deprecated (Firefox) or removed (Safari) this feature feature.
For more information, please refer here.
In my view the perfect answer you must required is
var reader = new FileReader();
//Read the contents of Image File.
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {
//Initiate the JavaScript Image object.
var image = new Image();
//Set the Base64 string return from FileReader as source.
image.src = e.target.result;
//Validate the File Height and Width.
image.onload = function () {
var height = this.height;
var width = this.width;
if (height > 100 || width > 100) {
alert("Height and Width must not exceed 100px.");
return false;
}
alert("Uploaded image has valid Height and Width.");
return true;
};
};
I agree. Once it is uploaded to somewhere the user's browser can access then it is pretty easy to get the size. As you need to wait for the image to load you'll want to hook into the onload event for img.
Updated example:
// async/promise function for retrieving image dimensions for a URL
function imageSize(url) {
const img = document.createElement("img");
const promise = new Promise((resolve, reject) => {
img.onload = () => {
// Natural size is the actual image size regardless of rendering.
// The 'normal' `width`/`height` are for the **rendered** size.
const width = img.naturalWidth;
const height = img.naturalHeight;
// Resolve promise with the width and height
resolve({width, height});
};
// Reject promise on error
img.onerror = reject;
});
// Setting the source makes it start downloading and eventually call `onload`
img.src = url;
return promise;
}
// How to use in an async function
(async() => {
const imageUrl = 'http://your.website.com/userUploadedImage.jpg';
const imageDimensions = await imageSize(imageUrl);
console.info(imageDimensions); // {width: 1337, height: 42}
})();
Older example:
var width, height;
var img = document.createElement("img");
img.onload = function() {
// `naturalWidth`/`naturalHeight` aren't supported on <IE9. Fallback to normal width/height
// The natural size is the actual image size regardless of rendering.
// The 'normal' width/height are for the **rendered** size.
width = img.naturalWidth || img.width;
height = img.naturalHeight || img.height;
// Do something with the width and height
}
// Setting the source makes it start downloading and eventually call `onload`
img.src = "http://your.website.com/userUploadedImage.jpg";
This is the easiest way to check the size
let img = new Image()
img.src = window.URL.createObjectURL(event.target.files[0])
img.onload = () => {
alert(img.width + " " + img.height);
}
Check for specific size. Using 100 x 100 as example
let img = new Image()
img.src = window.URL.createObjectURL(event.target.files[0])
img.onload = () => {
if(img.width === 100 && img.height === 100){
alert(`Nice, image is the right size. It can be uploaded`)
// upload logic here
} else {
alert(`Sorry, this image doesn't look like the size we wanted. It's
${img.width} x ${img.height} but we require 100 x 100 size image.`);
}
}
Attach the function to the onchange method of the input type file /onchange="validateimg(this)"/
function validateimg(ctrl) {
var fileUpload = ctrl;
var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.gif)$");
if (regex.test(fileUpload.value.toLowerCase())) {
if (typeof (fileUpload.files) != "undefined") {
var reader = new FileReader();
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {
var image = new Image();
image.src = e.target.result;
image.onload = function () {
var height = this.height;
var width = this.width;
if (height < 1100 || width < 750) {
alert("At least you can upload a 1100*750 photo size.");
return false;
}else{
alert("Uploaded image has valid Height and Width.");
return true;
}
};
}
} else {
alert("This browser does not support HTML5.");
return false;
}
} else {
alert("Please select a valid Image file.");
return false;
}
}
const ValidateImg = (file) =>{
let img = new Image()
img.src = window.URL.createObjectURL(file)
img.onload = () => {
if(img.width === 100 && img.height ===100){
alert("Correct size");
return true;
}
alert("Incorrect size");
return true;
}
}
I think this may be the simplest for uploads if you want to use it other functions.
async function getImageDimensions(file) {
let img = new Image();
img.src = URL.createObjectURL(file);
await img.decode();
let width = img.width;
let height = img.height;
return {
width,
height,
}
}
Use like
const {width, height } = await getImageDimensions(file)
Suppose you were storing an image for Tiger taken in Kenya. So you could use it like to upload to cloud storage and then store photo information.
const addImage = async (file, title, location) => {
const { width, height } = await getImageDimensions(file)
const url = await uploadToCloudStorage(file) // returns storage url
await addToDatabase(url, width, height, title, location)
}
function validateimg(ctrl) {
var fileUpload = $("#txtPostImg")[0];
var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.gif)$");
if (regex.test(fileUpload.value.toLowerCase())) {
if (typeof (fileUpload.files) != "undefined") {
var reader = new FileReader();
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {
var image = new Image();
image.src = e.target.result;
image.onload = function () {
var height = this.height;
var width = this.width;
console.log(this);
if ((height >= 1024 || height <= 1100) && (width >= 750 || width <= 800)) {
alert("Height and Width must not exceed 1100*800.");
return false;
}
alert("Uploaded image has valid Height and Width.");
return true;
};
}
} else {
alert("This browser does not support HTML5.");
return false;
}
} else {
alert("Please select a valid Image file.");
return false;
}
}
You can do the steps for previewing the image without showing it which is supported on all browsers. Following js code shows you how to check the width and height :
var file = e.target.files[0];
if (/\.(jpe?g|png|gif)$/i.test(file.name)) {
var reader = new FileReader();
reader.addEventListener("load", function () {
var image = new Image();
image.src = this.result as string;
image.addEventListener('load', function () {
console.log(`height: ${this.height}, width: ${this.width}`);
});
}, false);
reader.readAsDataURL(file);
}
Based on Mozilla docs:
The readAsDataURL method is used to read the contents of the specified
Blob or File. When the read operation is finished, the readyState
becomes DONE, and the loadend is triggered. At that time, the result
attribute contains the data as a data: URL representing the file's
data as a base64 encoded string.
And the browser compatibility is listed too.
In my case, I needed to also prevent the form from being submited, so here is the solution that worked for me.
The preventDefault will stop the form action, then we check the size and dimensions of the image in the onload function.
If all good, we allow the submit.
As the submit button gets disabled if a user still tries to submit the form with an invalid image, I also had to re-able the submit button once a valid image is inputted.
const validateMaxImageFileSize = (e) => {
e.preventDefault();
const el = $("input[type='file']")[0];
if (el.files && el.files[0]) {
const file = el.files[0];
const maxFileSize = 5242880; // 5 MB
const maxWidth = 1920;
const maxHeight = 1080;
const img = new Image();
img.src = window.URL.createObjectURL(file);
img.onload = () => {
if (file.type.match('image.*') && file.size > maxFileSize) {
alert('The selected image file is too big. Please choose one that is smaller than 5 MB.');
} else if (file.type.match('image.*') && (img.width > maxWidth || img.height > maxHeight)) {
alert(`The selected image is too big. Please choose one with maximum dimensions of ${maxWidth}x${maxHeight}.`);
} else {
e.target.nodeName === 'INPUT'
? (e.target.form.querySelector("input[type='submit']").disabled = false)
: e.target.submit();
}
};
}
};
$('form.validate-image-size').on('submit', validateMaxImageFileSize);
$("form.validate-image-size input[type='file']").on('change', validateMaxImageFileSize);
function uploadfile(ctrl) {
var validate = validateimg(ctrl);
if (validate) {
if (window.FormData !== undefined) {
ShowLoading();
var fileUpload = $(ctrl).get(0);
var files = fileUpload.files;
var fileData = new FormData();
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
fileData.append('username', 'Wishes');
$.ajax({
url: 'UploadWishesFiles',
type: "POST",
contentType: false,
processData: false,
data: fileData,
success: function(result) {
var id = $(ctrl).attr('id');
$('#' + id.replace('txt', 'hdn')).val(result);
$('#imgPictureEn').attr('src', '../Data/Wishes/' + result).show();
HideLoading();
},
error: function(err) {
alert(err.statusText);
HideLoading();
}
});
} else {
alert("FormData is not supported.");
}
}

getImageData always returning 0

I have been trying to make a script that compares two images in HTML5 and Javascript. But for some odd reason, it always returns that the images are completely the same.
And when looking at what the problem could be, I found out that every data value of every pixel returned, for some odd reason, "0".
So, any idea of what I have done wrong? :)
For some reason I feel like it's something very simple, but I just learned about the canvas element, so yeah.
This is my code:
function compareImg() {
var c1 = document.getElementById("c");
var ctx1 = c1.getContext("2d");
var c2 = document.getElementById("c2");
var ctx2 = c2.getContext("2d");
var match = 0;
var img1 = new Image();
img1.src = "cat.jpg";
img1.onload = function() {
ctx1.drawImage(img1, 0, 0);
}
var img2 = new Image();
img2.src = "bird.jpg";
img2.onload = function() {
ctx2.drawImage(img2, 0, 0);
}
for(var x = 0; x<c1.width; x++) { // For each x value
for(var y = 0; y<c1.height; y++) { // For each y value
var data1 = ctx1.getImageData(x, y, 1, 1);
var data2 = ctx2.getImageData(x, y, 1, 1);
if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
match++;
}
}
}
var pixels = c1.width*c1.height;
match = match/pixels*100;
document.getElementById("match").innerHTML = match + "%";
}
You are not waiting until your images have loaded and drawn before performing your comparison. Try this:
var img = new Image;
img.onload = function(){
ctx1.drawImage(img,0,0);
var img = new Image;
img.onload = function(){
ctx2.drawImage(img,0,0);
// diff them here
};
img.src = 'cat.jpg';
};
img.src = 'cat.jpg';
As shown above, you should always set your src after your onload.
I suspect that the problem is that your image data is probably not ready at the point you try to use it for the canvas. If you defer that code to the onload handlers, that will (probably) help:
var img1 = new Image(), count = 2;
img1.src = "cat.jpg";
img1.onload = function() {
ctx1.drawImage(img1, 0, 0);
checkReadiness();
}
var img2 = new Image();
img2.src = "bird.jpg";
img2.onload = function() {
ctx2.drawImage(img2, 0, 0);
checkReadiness();
}
function checkReadiness() {
if (--count !== 0) return;
for(var x = 0; x<c1.width; x++) { // For each x value
for(var y = 0; y<c1.height; y++) { // For each y value
var data1 = ctx1.getImageData(x, y, 1, 1);
var data2 = ctx2.getImageData(x, y, 1, 1);
if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
match++;
}
}
}
var pixels = c1.width*c1.height;
match = match/pixels*100;
document.getElementById("match").innerHTML = match + "%";
}
All I did was add a function wrapper around your code. That function checks the image count variable I added, and only when it's zero (i.e., only after both images have loaded) will it do the work.
(This may be superstition, but I always assign the "onload" handler before I set the "src" attribute. I have this idea that, perhaps only in the past, browsers might fail to run the handler if the image is already in the cache.)
Now another thing: you probably should just get the image data once, and then iterate over the returned data. Calling "getImageData()" for every single pixel is going to be a lot of work for the browser to do.

checking image size before upload

I noticed when uploading a profile pic to Twitter that its size is checked before upload. Can anyone point me to a solution like this?
Thanks
If you're checking the file size you can use something like uploadify to check the file size before upload.
Checking the actual file dimensions (height / width) may need to be done on the server.
I think it is impossible unless you use a flash. You can use uploadify or swfupload for such things.
I have tested this code in chrome and it works fine.
var x = document.getElementById('APP_LOGO'); // get the file input element in your form
var f = x.files.item(0); // get only the first file from the list of files
var filesize = f.size;
alert("the size of the image is : "+filesize+" bytes");
var i = new Image();
var reader = new FileReader();
reader.readAsDataURL(f);
i.src=reader.result;
var imageWidth = i.width;
var imageHeight = i.height;
alert("the width of the image is : "+imageWidth);
alert("the height of the image is : "+imageHeight);
Something like this should cope with forms loaded asynchronously, inputs with or without "multiple" set and avoid the race conditions that happen when using FileReader.readAsDataURL and Image.src.
$('#formContainer').on('change', '#inputFileUpload', function(event) {
var file, _fn, _i, _len, _ref;
_ref = event.target.files;
_fn = function(file) {
var reader = new FileReader();
reader.onload = (function(f) {
return function() {
var i = new Image();
i.onload = (function(e) {
var height, width;
width = e.target.width;
height = e.target.height;
return doSomethingWith(width, height);
});
return i.src = reader.result;
};
})(file);
return reader.readAsDataURL(file);
};
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
file = _ref[_i];
_fn(file);
}
});
Note: Needs jQuery, HTML5, hooks to a structure like:
<div id="formContainer">
<form ...>
...
<input type="file" id="inputFileUpload"></input>
...
</form>
</div>
You need check image Width and Height when Image onload.
var img = new Image;
img.src = URL.createObjectURL(file);
img.onload = function() {
var picWidth = this.width;
var picHeight = this.height;
if (Number(picWidth) > maxwidth || Number(picHeight) > maxheight) {
alert("Maximum dimension of the image to be 1024px by 768px");
return false;
}
}
This works perfectly for me
var _URL = window.URL || window.webkitURL;
$("#file").change(function(e) {
var file, img;
if ((file = this.files[0])) {
img = new Image();
img.onload = function() {
if((this.width < 800)||(this.height < 400)){
alert('Image too small. Images must be bigger than 800 x 400');
$('#file').val('');
}
};
img.onerror = function() {
alert( "not a valid file: " + file.type);
};
img.src = _URL.createObjectURL(file);
}
});
Kudos to the original creator: http://jsfiddle.net/4N6D9/1/
I modified this to specify the min width and height of an upload.

Categories