Loop: images land on the last field only - javascript

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);

Related

convert image from cordova imagepicker to base64

I am using the following snippet for my conversion operation (images from cordova image picker to base64 and store them in an array) but due to the async behavior, it is assigning same string as of the first image to all images. I tried while loop but then, the app crashed. Any suggestion how can I solve this problem.
Edit: results[ 0 ] is defined but all other results[ i ] are 'undefined', hence image source remains same for all iteration
window.imagePicker.getPictures(
function(results) {
for (var i = 0; i < results.length; i++) {
var img = new Image();
img.crossOrigin = 'Anonymous';
img.src = results[i];
img.onload = function(){
var canvas = <HTMLCanvasElement>document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage( img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg').slice(23);
Attachments.push(dataURL); // array for storing base64 equivalent of all images
canvas = null;
};
}
img.src = results[ i ] starts reading the file at results[ i ] async, so when loop continues for i=1, results[ 1 ] is undefined because the file system is still reading for results[0]. Hence all iteration returns dataURL of the first image.
To avoid it use callbacks which solve this problem with the concept of closures.
window.imagePicker.getPictures(
function(results) {
console.log(results);
for (var i = 0; i < results.length; i++) {
parent.tobase64(results[i],function(dataURL){
parent.email_data.Attachments.push(dataURL);
});
}
}, function (error) {
console.log('Error: ' + error);
}
}
tobase64(file,callback){
var parent=this;
var img = new Image();
img.crossOrigin = 'Anonymous';
img.src = file;
img.onload = function(){
var canvas = <HTMLCanvasElement>document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage( img, 0, 0);
var dataURL = canvas.toDataURL('image/jpeg').slice(23);
canvas = null;
callback.call(this,dataURL);
}
}

On loading Image, getImageData delivers some zeros

I'm loading a PNG and try to check, whether it is fully opaque, meaning alpha channel is near 100% over the whole image. Therefore, I use the canvas and 2D-Context to get the pixel data and loop through it checking the alpha value.
To my surprise i get whole areas of zeros (RGBA = [0000]) where it obviously shouldn't.
Browser in focus: chrome 50.0.2661.87
Here is my code, it is embedded in a ThreeJS environment:
var imageData = zipHandler.zip.file(src); // binary image data
var texture = new THREE.Texture();
var img = new Image();
img.addEventListener( 'load', function ( event ) {
texture.imageHasTransparency = false; // extend THREEJS Texture by a flag
if (img.src.substring(imgSrc.length-4).toLowerCase().indexOf("png") > -1
|| img.src.substring(0, 15).toLowerCase().indexOf("image/png") > -1) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// search for pixel.alpha < 250
for (var pix = 0, pixDataLen = pixData.length; pix < pixDataLen; pix += 4) {
if (pixData[pix+3] < 250) {
texture.imageHasTransparency = true;
break;
}
}
}
texture.image = img;
texture.needsUpdate = true;
this.removeEventListener('load', arguments.callee, false);
}, false );
var fileExtension = src.substr(src.lastIndexOf(".") + 1);
img.src = "data:image/"+fileExtension+";base64,"+ btoa(imageData.asBinary());
The order is correct: first define new Image(), then the onload function and then the source.
Solved. The image was larger than the canvas, so when context.drawImage() was started, only parts of the area was filled. I've set the canvas dimensions according to the image size, so now it works and we have
// ...
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.width = img.width; // !!!!!
canvas.height = img.height; // !!!!
context.drawImage(img, 0, 0, img.width, img.height );
var pixDataContainer = context.getImageData(0, 0, img.width, img.height);
var pixData = pixDataContainer.data;
// ...

Javascript Image-Resize before upload

I'm trying to resize big/large images on client and upload the smaller image. This works perfectly with one or ten images. But i want to upload mybe 50+ images. This will work but it slows down my cpu and memory. The code for the resized images is this:
var MAX_WIDTH = 1920;
var MAX_HEIGHT = 1920;
var loaded = 0;
var URL = window.URL || window.webkitURL;
function loadImage(file) {
var mime = file.type;
var src = URL.createObjectURL(file);
var img = new Image();
img.onload = (function (image) {
return function () {
var newHeight = MAX_WIDTH;
var newWidth = MAX_HEIGHT;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = newWidth;
canvas.height = newHeight;
ctx.drawImage(image, 0, 0, this.width, this.height, 0, 0, newWidth, newHeight);
URL.revokeObjectURL(this.src);
var dataURI = canvas.toDataURL(mime);
var blob = dataURLToBlob(dataURI);
imagesToUpload.push(blob);
loaded++;
if (loaded < checkedFiles.length) {
loadImage(checkedFiles[loaded]);
} else {
//DO UPLOAD
input.value = "";
}
}
})(img);
img.src = src;
image = null;
}
loadImage(checkedFiles[0]);
While resizing and uploading, i want to show a loading animation. And this anmiation is very slow.
I think the problem is while resizing the image on the canvas-object, but i have no idea to solve this issue.
The MAX-PICTURE-WITH is 1920px and the MAX-PICTURE-HEIGHT is 1920px.
It would be great if someone can give me a clue?

Dynamically add multiple images from input

I have the following code:
var imageLoader = document.getElementById('imageLoader');
var patternLoader = document.getElementById("patternLoader");
var canvas = document.getElementById('imageCanvas');
var ctx = canvas.getContext('2d');
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
var img = new Image();
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
};
imageLoader.addEventListener("change", handleImage, false);
patternLoader.addEventListener("change", handleImage, false);
How can I load one image over another from inputs and not replace them?
I want it to be like that http://i.gyazo.com/85c8c6bdcd2efcdd6a1c1b156000f204.png
Here's a crude way to add images dynamically. Declare an array to keep track on all your images and scale the canvas based on the largest image.
Since I didn't konw what kind of DOM elements the OP used for "imageLoader" and "patternLoader", I simply used an <input>-tag.
Just keep pasting URLs for images to add images to your canvas. The images will be drawn in the order as you add them.
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var maxWidth = 0;
var maxHeight = 0;
var images = [];
var myInput = document.getElementById("myInput");
myInput.addEventListener('change',handleImage,false);
function handleImage(e) {
var myImage = new Image();
myImage.onload = function () {
if (myImage.width > maxWidth) {
maxWidth = myImage.width;
}
if (myImage.height > maxHeight) {
maxHeight = myImage.height;
}
canvas.width = maxWidth;
canvas.height = maxHeight;
images.push(myImage);
drawImages();
}
myImage.src = e.target.value;
}
function drawImages() {
for (var i = 0; i<images.length; i++) {
ctx.drawImage(images[i],canvas.width/2-images[i].width/2,canvas.height/2-images[i].height/2);
}
}
<input type="text" id="myInput"><br />
<canvas id="canvas"></canvas>

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];
}

Categories