Images not loaded on first call in html canvas - javascript

I want to load the sorted array images in canvas in a same sequence, for that i created a load function and I am calling it from there.
Every thing works fine, but the problem is that it does not draw the images on canvas at first call.
Here is a fiddle
With my current code, it does not show you an image , but when you run it again, it will create and show the canvas image.
I am facing the same issue in my local host where i load the images with ajax.
var ImagesArray = new Array("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
//alert(ImagesArray.length);
MainMethods(ImagesArray);
function MainMethods(responseImages) {
//alert(responseImages.length);
var canvas = document.getElementById("product-image");
canvas.height = ($(window).height()) - 120;
canvas.width = canvas.height * 0.75;
var heightscreen = ($(window).height()) - 120;
var canvasheight = heightscreen;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
var returnedImages = loadImages(responseImages);
for (i = 0; i < returnedImages.length; i++) {
console.log(returnedImages[i]);
context.drawImage(returnedImages[i], canvaswidthdiv4, 55, widthNeeded, canvasheight);
}
// Image loading global variables
var loadcount = 0;
var loadtotal = 0;
var preloaded = false;
// Load images
function loadImages(imagefiles) {
// Initialize variables
loadcount = 0;
loadtotal = imagefiles.length;
preloaded = false;
// Load the images
var loadedimages = [];
for (var i = 0; i < imagefiles.length; i++) {
// Create the image object
var image = new Image();
// Add onload event handler
image.onload = function() {
loadcount++;
if (loadcount == loadtotal) {
// Done loading
preloaded = true;
}
};
// Set the source url of the image
image.src = imagefiles[i];
// Save to the image array
loadedimages[i] = image;
}
// Return an array of images
return loadedimages;
}
}
<canvas id="product-image" width="700" height="823"></canvas>

The problem is that your images are not loaded yet when you try to draw it.
Wrap the drawImage part in a function and call it when preloaded becomes true, here your boolean does nothing.
I refactored your code a little bit, you also had an issue with loadtotal being reset to 0 after your call to loadImage() function. So loadcountwon't ever be === loadtotal and your useless preloaded never switched to true.
var ImagesArray = new Array ("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
function MainMethods(responseImages) {
var canvas = document.getElementById("product-image");
canvas.height = ($(window).height()) - 120;
canvas.width = canvas.height * 0.75;
var canvasheight = ($(window).height()) - 120;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
// an other error, if you set loadtotal to 0 after calling loadImages(), it will be set to 0 when images are loaded.
// and loadcount won't ever be === loadtotal.
var loadcount;
var loadtotal;
function loadImages(imagefiles) {
loadcount = 0;
loadtotal = imagefiles.length;
var loadedimages = [];
for (var i=0; i<imagefiles.length; i++) {
var image = new Image();
image.onload = function () {
loadcount++;
console.log(loadcount+'/'+ loadtotal);
if (loadcount == loadtotal) {
// done loading all the images
draw(loadedimages);
}
};
image.src = imagefiles[i];
loadedimages[i] = image;
}
}
// Wrap your drawing in a function that will be called asynchronously
function draw(loadedimages){
for (var i = 0; i < loadedimages.length; i++) {
console.log(loadedimages[i]);
context.drawImage(loadedimages[i], canvaswidthdiv4, 55, widthNeeded, canvasheight);
}
}
// Once all your variables are set, you can load the images
loadImages(responseImages);
}
MainMethods(ImagesArray);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="product-image"></canvas>

Since it appears to be a browser specific issue, here's a hack to get it to work:
Replace : MainMethods(ImagesArray);
with : setTimeout(function () { MainMethods(ImagesArray); }, 0);
With timeout set to 0 ms, it would virtually execute instantaneously.
JsFiddle : http://jsfiddle.net/wdfrrayh/3/
Tested on IE, FF, Chrome

image src needs to be called after drawImage which i was doing before I have updated my function which is working fine,
below is working code for this
function loadImages(sources, callback, jsondata) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('product-image');
canvas.height = (jQuery(window).height()) -120;
canvas.width = canvas.height * 0.75;
var heightscreen = (jQuery(window).height()) -120;
var canvasheight = heightscreen;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
var sources = new Array ("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
loadImages(sources, function(images) {
for(var i=0; i < sources.length; i++){
context.drawImage(images[i], canvaswidthdiv4, 55,widthNeeded,canvasheight);
}
});

Related

Refresh the image without reloading the page

Each new image should be with different src. Untill reloading all images have single src. It is can be add location.reload(); until adding new image, then scr will change. But reloading very seen. Does it exist way to reload only scr?
var cvs;
var ctx;
cvs = document.getElementById("canvas");
ctx = cvs.getContext("2d");
var width_path_near = 80,
width_path_far = 30;
var tree1 = new Image();
var tree2 = new Image();
var tree3 = new Image();
var tree4 = new Image();
tree1.src = "https://png.pngtree.com/element_origin_min_pic/00/02/61/6156839a2a633b7.jpg";
tree2.src = "http://s02.yapfiles.ru/files/457732/derevo_1.png";
tree3.src = "http://www.grafamania.net/uploads/posts/2014-06/1401644723_1-9.jpg";
tree4.src = "http://img11.txapela.ru/e/c/c/4/f/52e052f118c7b8ff9317385f581.jpg";
var masTree=[tree1, tree2, tree3, tree4];
var randTree=Math.floor(Math.random()*masTree.length);
var tree_size = 100;
var grow = 0.2;
var gap = 100;
var forest = [];
forest[0] = {
x : cvs.width/2-width_path_near-tree_size/2,
y : cvs.height/2-tree_size+10,
size : tree_size
}
function draw() {
ctx.fillStyle = "rgb(84,209,216)";
ctx.fillRect(0, 0, 1000, 600);
for (var i=0; i<forest.length; i++){
ctx.drawImage(masTree[randTree], forest[i].x, forest[i].y, forest[i].size, forest[i].size);
if(forest[i].y == 3*cvs.height/4){
forest.push({
y : cvs.height/2-tree_size+10,
x : cvs.width/2-width_path_near-tree_size/2,
size : tree_size
});
}
forest[i].y += 0.5;
forest[i].x -= 0.4;
forest[i].size += 0.4;
}
requestAnimationFrame(draw);
}
masTree[randTree].onload = draw;
http://jsfiddle.net/Nata_Hamster/ugyb1fd0/

Loop: images land on the last field only

I have a little problem with a loop. I am building a little tool, where a user must upload 12 images. The images are cropped in rectangles and placed on buttons. I am almost ready, but somehow the loop doesn't work well. All images land on the last button. Maybe something wrong in the loop here?
JS/JQuery:
for (var i = 0; i < 12; i++) {
var j=i+1;
var reader = new FileReader();
reader.onload = function (e) {
var img = new Image();
img.src = e.target.result;
img.onload = function () {
var getimage= '#getimage'+j;
// CREATE A CANVAS ELEMENT AND ASSIGN THE IMAGES TO IT.
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height)
var posh, posw;
var factheight=img.height;
var factwidth=img.width;
if(factwidth<factheight){
canvas.width = img.width;
canvas.height= img.width;
posh=(img.height-img.width)/2;
posw=0;
}
else if(factheight<factwidth){
canvas.height = img.height;
canvas.width = img.height;
posh=0;
posw=(img.width-img.height)/2;
}
else{
canvas.width = img.width;
canvas.height= img.height;
posh=0;
posw=0;
}
ctx.drawImage(img, posw, posh, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
var cropped=canvas.toDataURL("image/png");
$(getimage).attr("src",cropped); // SHOW THE IMAGES OF THE BROWSER.
}
}
reader.readAsDataURL($('.multiupload')[0].files[i]);
}
Here is also a link to the JSFiddle. Appreciate your help, since I don't know exactly how reader.readAsDataURL($('.multiupload')[0].files[i]); and target.result works
I'm guessing that your loop has finished before any of the images are fully loaded so j will be 11 before its used to find the relevant button. Try changing
img.onload = function () { .... }
to
img.onload = myFunction(id)
Then move everything out of the inline function into its own function with an input parameter. Then pass j as the id param.
I've done an example for you. As I answered in comments
var reader = new FileReader();
reader.onload = (function(j){return function (e) {
var img = new Image();
...
https://jsfiddle.net/ykze3f9r/
The main issue with the code was the j variable. It was always set to the last number because of the way for loops work. You have to instead bind that number. I broke up into separate functions to make it easier to read. Here's the working JSFiddler: https://jsfiddle.net/eh6pr7ee/2/
Processes the image...
var processImg = function( img, imgNum ) {
var getimage= '#getimage' + imgNum;
// CREATE A CANVAS ELEMENT AND ASSIGN THE IMAGES TO IT.
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height)
var posh, posw;
var factheight = img.height;
var factwidth = img.width;
if (factwidth < factheight) {
canvas.width = img.width;
canvas.height = img.width;
posh = (img.height-img.width)/2;
posw = 0;
}
else if (factheight < factwidth) {
canvas.height = img.height;
canvas.width = img.height;
posh = 0;
posw = (img.width-img.height)/2;
}
else {
canvas.width = img.width;
canvas.height= img.height;
posh = 0;
posw = 0;
}
ctx.drawImage(img, posw, posh, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
var cropped = canvas.toDataURL("image/png");
$(getimage).attr("src",cropped); // SHOW THE IMAGES OF THE BROWSER.
};
Creates image and sets source...
var setImage = function( imgNum, e ) {
var img = new Image();
img.src = e.target.result;
img.onload = processImg.bind( this, img, imgNum );
};
Create a handler function for image uploads...
var handleImageUploads = function() {
if (parseInt($(this).get(0).files.length) > 12 || parseInt($(this).get(0).files.length) < 12) {
alert("Please upload 12 photos");
}
else {
//loop for each file selected for uploaded.
for (var i = 0; i < 12; i++) {
var reader = new FileReader();
reader.onload = setImage.bind( this, i+1 );
reader.readAsDataURL($('.multiupload')[0].files[i]);
} // for
console.log("done");
$('body').removeClass("loading");
}; // else
}
Binds the handler function.
$('.multiupload').on("change", handleImageUploads);

Converting images to base64 within a loop before adding to jspdf - javascript

I have researched issues with the base64 conversion and jspdf function quite a bit. ( PS this is my first question on stackoverflow, please bare with any rookie mistakes ).
All seems to work fine with the below code except that the pdf is generated and saved before the loop where the images are converted to base64 and placed to the document is finished. I added a couple alerts to check timing. Would the solution be to check when the loop is finished, the images placed before continuing with the pdf function? if so, how? please help.
$(document).ready(function(){
$("a#getdoc").click(function(){
var doc = new jsPDF('landscape, in, legal');
var myimages = 'img1.jpg|img2.jpg|img3.png';
var myimgarray = myimages.split('|');
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/jpeg");
var dataURL = canvas.toDataURL("image/jpeg");
callback(dataURL);
canvas = null;
}
for(var i = 0; i < myimgarray.length; i++)
{
icount.count = i;
var img = new Image();
alert(checkoutimgarray);
img.src = '/Portals/0/repair-images/' + myimgarray[i];
img.onload = function(){
newData = convertImgToBase64(img);
alert(newData);
doc.addImage(newData, 'JPEG', (icount * 100), 10, 70, 15); // would doc be undefined here? out of scope?
};
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
});
});
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
function convertImgToBase64(img, outputFormat){
// clear canvas
canvas.width = img.width;
canvas.height = img.height;
// draw image
ctx.drawImage(img, 0, 0);
// get data url of output format or defaults to jpeg if not set
return canvas.toDataURL("image/" + (outputFormat || "jpeg"));
}
var images = [];
for(var i = 0; i < myimgarray.length; i++) {
var img = new Image();
img.onload = function() {
images.push({
base64: convertImgToBase64(this),
width: this.width,
height: this.height
});
// all images loaded
if(images.length === myimgarray.length) {
for(var j = 0; j < images.length; j++) {
doc.addImage(images[j].base64, 'JPEG', (j * 100), 10, 70, 15);
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
}
};
img.src = '/Portals/0/repair-images/' + myimgarray[i];
}

load image inside JavaScript function

i have function to get image pixels color
function getImage(imgsrc){
var img = $( "<img>", {
src: imgsrc
});
var imageMap = new Object();
img.load(function() {
var canvas = $('<canvas/>')[0].getContext('2d');
canvas.width = this.width;
canvas.height = this.height;
canvas.drawImage(this, 0, 0, this.width, this.height);
for(var i = 0;i < this.width;i++){
imageMap[i] = new Object();
for(var j = 0;j < this.width;j++){
var pixelData = canvas.getImageData(i, j, 1, 1).data;
imageMap[i][j] = rgbToHex(pixelData[0],pixelData[1],pixelData[2]);
}
}
console.log(imageMap[40][40]);
});
console.log(imageMap[40][40]);
return imageMap;
}
but it return undefined(it print 2nd console.log first)
what's wrong?
thx.
Your function is returning undefined because load is asynchronous. getImage is trying to return something before load finished loading.
You'll need to pass a callback to execute when the image has loaded, to getImage:
function getImage(imgsrc, callback){
var img = $( "<img>", {
src: imgsrc
});
var imageMap = new Object();
img.load(function() {
var canvas = $('<canvas/>')[0].getContext('2d');
canvas.width = this.width;
canvas.height = this.height;
canvas.drawImage(this, 0, 0, this.width, this.height);
for(var i = 0;i < this.width;i++){
imageMap[i] = new Object();
for(var j = 0;j < this.width;j++){
var pixelData = canvas.getImageData(i, j, 1, 1).data;
imageMap[i][j] = rgbToHex(pixelData[0],pixelData[1],pixelData[2]);
}
}
console.log(imageMap[40][40]);
callback(imageMap)
});
}
Then you just call the function like this:
getImage("http://some.src.jpg", function(imageMap){
// Do stuff with imageMap here;
});
Of course, you can also define the callback elsewhere:
var myCallback = function(imageMap){
// Do stuff with imageMap here;
};
getImage("http://some.src.jpg", myCallback);
Now that promises starts to get [have] wide support you can do this instead:
// Define a common load function:
function loadImage(url) {
return new Promise(function(resolve, reject) {
var img = new Image;
img.onload = function() { resolve(this) };
img.onerror = img.onabort = function() { reject("Error loading image") };
img.src = url;
})
}
// Usage:
loadImage("https://i.stack.imgur.com/ynBVu.gif").then(function(image) {
// Use the `image` here
document.body.appendChild(image);
})
The promise will take the callback, states etc. internally. IE will get support in next version (there exists polyfill for it).
jQuery.load() is asynchronous, meaning the code will continue while it goes of working away.
If you want to process the imagemap, one option could be to pass a callback you execute ones the imagemap is populated, similar to:
function yourCallback(imageMap){
// ...process imageMap;
}
function getImage(imgsrc, yourCallback) {
var img = $("<img>", {
src: imgsrc
});
var imageMap = new Object();
img.load(function () {
var canvas = $('<canvas/>')[0].getContext('2d');
canvas.width = this.width;
canvas.height = this.height;
canvas.drawImage(this, 0, 0, this.width, this.height);
for (var i = 0; i < this.width; i++) {
imageMap[i] = new Object();
for (var j = 0; j < this.width; j++) {
var pixelData = canvas.getImageData(i, j, 1, 1).data;
imageMap[i][j] = rgbToHex(pixelData[0], pixelData[1], pixelData[2]);
}
}
yourCallback(imageMap);
});
}
getImage(imgsrc,yourCallback);

draw array of images to the canvas

I am trying to draw an array of images to the canvas element, my data:image is returning an empty image.
var imgArray = ['images/image1.png','images/image2.png'];
for(i = 0; i < 2; i++){
var canvas = document.getElementById('textCanvas');
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};
}
img = canvas.toDataURL("image/png");
You never set the images' source:
var imageObj = new Image();
imageObj.src = imgArray[i]; // << addeed
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};

Categories