0

I'm trying hard to accomplish and understand the following 'monstercode' that I wrote. Basically, this function should fire when the File input dialog (HTML) was fired. But the code goes well only a few lines. It loads the image, and then in the first alert() it shows me the base64 of the original image, but then, later in the code, when the actual image should be loaded in a canvas, it returns (in another alert()) height 0, probably meaning that the image wasn't loaded correctly or at all.

The HTML input form (simplified) looks like this:

<input type='File' accept='image/*' onChange='changeBtn(this);' /> 

And the function below:

function changeBtn(elem) { selfile = document.getElementById(elem.id); if ('files' in selfile) { var file = selfile.files[0]; if ('name' in file) { str1 = file.name; } if ('size' in file) { str1 += ' (' + ((file.size / 1024) / 1024).toFixed(2) + 'MB)'; } document.getElementById("label_" + elem.id).innerHTML = str1; var FR= new FileReader(); var img = document.createElement("img"); FR.onload = function(e) { img.src = e.target.result; alert(e.target.result); // Returns B64 of the original image }; FR.readAsDataURL(file); var canvas = document.createElement('canvas'); var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); var MAX_WIDTH = 800; var MAX_HEIGHT = 600; var width = img.width; var height = img.height; alert(height); // Returns 0 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); var dataurl = canvas.toDataURL("image/png"); alert(dataurl); // Returns only "data; " and nothing more } } 

Thanks in advance for any help. Seems quite simple, but I don't get it. I rewrote the code at least 3 times, but I get always the same result.

8
  • Check your scoping of img. You define it, then use it outside of onload where it is still empty. Commented Oct 31, 2016 at 14:00
  • @J.Titus But when I put everything inside the onload, the onload seems to never complete.. (It shows no alerts) Commented Oct 31, 2016 at 14:08
  • It is not a scoping issue. You call FR.readAsDataURL(file); which will complete by issuing the callback to onload. However FR.readAsDataURL(file); returns immediately and continues executing your code whether the img variable got set up or not. If you move all the code that follows FR.readAsDataURL(file); inside the onload, it should work. It may not be the best way to do it but it is a start. Commented Oct 31, 2016 at 14:10
  • @markbernard "It is not a scoping issue.... If you move all the code that follows FR.readAsDataURL(file); inside the onload, it should work." - Code operating outside of a callback when it should be inside is not a scoping issue? :) When OP uses img for img.width and img.height it's still operating as a new <img>, so the width and height are 0. Inside the callback, this would be different. Commented Oct 31, 2016 at 14:17
  • @Fusseldieb Define "everything." As markbernard stated, readAsDataURL() should stay outside the callback. Everything after that should go inside. Commented Oct 31, 2016 at 14:18

1 Answer 1

1

Figured it out! I was calling FR.readAsDataURL(file); before loading the image into it, leading it to load an undefined file.

If we look at following code that has failed:

var FR= new FileReader(); var img = document.createElement("img"); FR.onload = function(e) { img.src = e.target.result; alert(e.target.result); // Returns B64 of the original image }; FR.readAsDataURL(file); 

we now know why. First var FR= new FileReader(); is called, then FR.readAsDataURL(file); and then, at last, when the onload fires: img.src = e.target.result;. That's the wrong order. The right order is:

function changeBtn(elem) { selfile = document.getElementById(elem.id); if ('files' in selfile) { var file = selfile.files[0]; if ('name' in file) { str1 = file.name; } if ('size' in file) { str1 += ' (' + ((file.size / 1024) / 1024).toFixed(2) + 'MB)'; } document.getElementById("label_" + elem.id).innerHTML = str1; var FR= new FileReader(); FR.readAsDataURL(file); var img = document.createElement("img"); FR.onload = function(e) { img.src = e.target.result; alert(e.target.result); var canvas = document.createElement('canvas'); var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); var MAX_WIDTH = 800; var MAX_HEIGHT = 600; var width = img.width; var height = img.height; alert(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); var dataurl = canvas.toDataURL("image/png"); alert(dataurl); }; } } 
Sign up to request clarification or add additional context in comments.

1 Comment

I'll make that shortly, I am just correcting some minor spelling errors in my answer. :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.