Mad_Griffith Posted October 12, 2015 Share Posted October 12, 2015 (edited) Hi, I created a simple badge generator app here. I am using the html5 file input and <canvas> to display a badge template and the user has to select the picture. The problem is that sometimes (randomly?), as soon as the image is selected, it doesn't show up in the pixels I designated it to appear in. A quick debug made clear that, when this occurs, the image object is there but it has width 0 and height 0 (see screenshot below). Edited October 12, 2015 by Mad_Griffith Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 12, 2015 Author Share Posted October 12, 2015 This is the JS I wrote: (function() { var badgeImg = new Image(); badgeImg.onload = function() { var canvas = $('#badge-image')[0], context = canvas.getContext('2d'); canvas.width = 451; canvas.height = 300; drawBaseBadge(); function drawBaseBadge() { badgeImg.width = '451'; badgeImg.height = '300'; context.drawImage(badgeImg, 0, 0); clipWidth = 90; clipHeight = 110; context.rect(44, 152, clipWidth, clipHeight); context.clip(); } function readUploadedImage(file) { var readFile = new FileReader(); readFile.onload = function(event) { drawBaseBadge(); profileImgUrl = event.target.result; profileImg = new Image(); profileImg.id = 'profile-image'; profileImg.src = profileImgUrl; originalAspectRatio = profileImg.width / profileImg.height; console.log('Img:', profileImg); console.log('Original:', profileImg.width, profileImg.height); profileImg.width = 90; profileImg.height = profileImg.width / originalAspectRatio; profileImgPosX = 44; profileImgPosY = 152; console.log('Resized:', profileImg.width, profileImg.height); context.drawImage(profileImg, profileImgPosX - ((profileImg.width - clipWidth) / 2), profileImgPosY - ((profileImg.height - clipHeight) / 2), profileImg.width, profileImg.height); }; readFile.readAsDataURL(file); } $('#badge-uploader input').change(function() { readUploadedImage(this.files[0]); }); document.getElementById('badge-download').addEventListener('click', function() { downloadCanvas(this, 'badge-image', 'myBadge.png'); }, false); function downloadCanvas(link, canvasId, filename) { link.href = document.getElementById(canvasId).toDataURL(); link.download = filename; } }; badgeImg.src = './img/badge.jpg';}()); Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 15, 2015 Author Share Posted October 15, 2015 Apparently I need to wait until the image width and height are loaded and then add the src. I need to return multiple values from the onload anonymous function and problem is the values doesn't seem to be returned (console.log(result) doesn't work)... what am I doing wrong? See code below (function() { var badgeImg = new Image(); badgeImg.onload = function() { var canvas = $('#badge-image')[0], context = canvas.getContext('2d'); canvas.width = 451; canvas.height = 300; drawBaseBadge(); function drawBaseBadge() { badgeImg.width = '451'; badgeImg.height = '300'; context.drawImage(badgeImg, 0, 0); clipWidth = 90; clipHeight = 110; context.rect(44, 152, clipWidth, clipHeight); context.clip(); } function readUploadedImage(file) { var readFile = new FileReader(); readFile.onload = function(event) { drawBaseBadge(); var profileImg = new Image(); profileImg.onload = function(profileImg) { profileImg.id = 'profile-image'; originalAspectRatio = profileImg.width / profileImg.height; console.log('Img:', profileImg); console.log('Original:', profileImg.width, profileImg.height); profileImg.width = 90; profileImg.height = profileImg.width / originalAspectRatio; profileImgPosX = 44; profileImgPosY = 152; result = { 'profileImg.width': profileImg.width, 'profileImg.height': profileImg.height, 'profileImgPosX': profileImgPosX, 'profileImgPosY': profileImgPosY, 'originalAspectRatio': originalAspectRatio }; profileImg.src = event.target.url; console.log(result); } console.log('Resized:', profileImg.width, profileImg.height); context.drawImage(profileImg, profileImg.profileImgPosX - ((profileImg.width - clipWidth) / 2), profileImg.profileImgPosY - ((profileImg.height - clipHeight) / 2), profileImg.width, profileImg.height); readFile.readAsDataURL(file); } } $('#badge-uploader input').change(function() { readUploadedImage(this.files[0]); }); document.getElementById('badge-download').addEventListener('click', function() { downloadCanvas(this, 'badge-image', 'myBadge.png'); }, false); function downloadCanvas(link, canvasId, filename) { link.href = document.getElementById(canvasId).toDataURL(); link.download = filename; } }; badgeImg.src = './img/badge.jpg';}()); Link to comment Share on other sites More sharing options...
justsomeguy Posted October 15, 2015 Share Posted October 15, 2015 The onload handler never gets called because you're not assigning a src for the image to load. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 15, 2015 Author Share Posted October 15, 2015 (edited) The onload handler never gets called because you're not assigning a src for the image to load. Thanks! What should it be like? Isn't it always profileImg which I have to assign the src value to? Edited October 15, 2015 by Mad_Griffith Link to comment Share on other sites More sharing options...
justsomeguy Posted October 15, 2015 Share Posted October 15, 2015 Yes, you have to assign the src after you assign the load handler. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 15, 2015 Author Share Posted October 15, 2015 Isn't it what I am doing already? Link to comment Share on other sites More sharing options...
justsomeguy Posted October 15, 2015 Share Posted October 15, 2015 No, you're assigning the src inside the load handler, and the load handler never gets called because the image doesn't get loaded because you don't assign a src to it. Assign the src outside the load handler, not inside. Changing the src inside a load handler isn't a great idea anyway because it's going to immediately fire the load handler again and start a loop. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 15, 2015 Author Share Posted October 15, 2015 I understand. I moved it outside the other curly brace, but still it does not work... what else can be wrong? (function() {var badgeImg = new Image();badgeImg.onload = function() {var canvas = $('#badge-image')[0],context = canvas.getContext('2d');canvas.width = 451;canvas.height = 300;drawBaseBadge();function drawBaseBadge() {badgeImg.width = '451';badgeImg.height = '300';context.drawImage(badgeImg, 0, 0);clipWidth = 90;clipHeight = 110;context.rect(44, 152, clipWidth, clipHeight);context.clip();}function readUploadedImage(file) {var readFile = new FileReader();readFile.onload = function(event) {drawBaseBadge();var profileImg = new Image();profileImg.onload = function(profileImg) {profileImg.id = 'profile-image';originalAspectRatio = profileImg.width / profileImg.height;console.log('Img:', profileImg);console.log('Original:', profileImg.width, profileImg.height);profileImg.width = 90;profileImg.height = profileImg.width / originalAspectRatio;profileImgPosX = 44;profileImgPosY = 152;result = {'profileImg.width': profileImg.width,'profileImg.height': profileImg.height,'profileImgPosX': profileImgPosX,'profileImgPosY': profileImgPosY,'originalAspectRatio': originalAspectRatio};}profileImg.src = event.target.url;console.log(result);console.log('Resized:', profileImg.width, profileImg.height);context.drawImage(profileImg, profileImg.profileImgPosX - ((profileImg.width - clipWidth) / 2), profileImg.profileImgPosY - ((profileImg.height - clipHeight) / 2), profileImg.width, profileImg.height);readFile.readAsDataURL(file);}}$('#badge-uploader input').change(function() {readUploadedImage(this.files[0]);});document.getElementById('badge-download').addEventListener('click', function() {downloadCanvas(this, 'badge-image', 'myBadge.png');}, false);function downloadCanvas(link, canvasId, filename) {link.href = document.getElementById(canvasId).toDataURL();link.download = filename;}};badgeImg.src = './img/badge.jpg';}()); Link to comment Share on other sites More sharing options...
justsomeguy Posted October 15, 2015 Share Posted October 15, 2015 What happens when you run it? Are you checking for error messages? Are you seeing the console.log statements inside the load handler? Note that everything you want to happen after the image loads goes inside the load handler. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 16, 2015 Author Share Posted October 16, 2015 Nothing is logged in the console... I don't know what I am doing wrong... Link to comment Share on other sites More sharing options...
dsonesuk Posted October 16, 2015 Share Posted October 16, 2015 Place var badgeImg = new Image(); and its applied src outside. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 16, 2015 Author Share Posted October 16, 2015 (edited) It's profileImg we are talking about... why should badgeImg be involved? badgeImg loads just fine. Edited October 16, 2015 by Mad_Griffith Link to comment Share on other sites More sharing options...
justsomeguy Posted October 16, 2015 Share Posted October 16, 2015 If nothing at all is appearing on the console then I would suggest using breakpoints to step through the code. Set breakpoints inside the various load handlers and other functions so that you can pause the code and step through to see what it's doing. You can look at the values of all of the variables while the code is paused and step into or out of functions to trace what it's doing. Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 16, 2015 Author Share Posted October 16, 2015 This version of readUploadeImage() works in the end... function readUploadedImage(file) {var readFile = new FileReader();readFile.onload = function (event) {drawBaseBadge();profileImgUrl = event.target.result;profileImg = new Image();profileImg.id = 'profile-image';profileImg.onload = function () {originalAspectRatio = profileImg.width / profileImg.height;console.log('Img:', profileImg);console.log('Original:', profileImg.width, profileImg.height);profileImg.width = 90;profileImg.height = profileImg.width / originalAspectRatio;profileImgPosX = 44;profileImgPosY = 152;console.log('Resized:', profileImg.width, profileImg.height);context.drawImage(profileImg, profileImgPosX - ((profileImg.width - clipWidth) / 2), profileImgPosY - ((profileImg.height - clipHeight) / 2), profileImg.width, profileImg.height);};profileImg.src = profileImgUrl;};readFile.readAsDataURL(file);} Link to comment Share on other sites More sharing options...
Mad_Griffith Posted October 18, 2015 Author Share Posted October 18, 2015 As somebody explained to me: [*]The image object is created. [*]The onload listener is registered. Code in the anonymous function is not yet executed. [*]src attribut is assigned to the image object. [*]Image is loaded. [*]onload event fires and code in the anonymous function is executed. [*]Calculations are done. [*]Image is drawn on the canvas. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now