Canvas draw new image from daturl - javascript

I'm using the function below to resize and image using canvas
var img = new Image();
img.src = reader.result;
img.onload = function() {
var max_width = 800;
var max_height = 800;
var tempW = img.width;
var tempH = img.height;
var aspect_ratio = 1;
if (tempW > tempH) {
if (tempH > max_height){
var aspect_ratio = tempH / max_height
}
} else {
if (tempW > max_width){
var aspect_ratio = tempW / max_width
}
}
tempH = tempH / aspect_ratio;
tempW = tempW / aspect_ratio;
var canvas = document.createElement('canvas')
canvas.id = "uploadedcanvas";
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
ctx.fillStyle="#FFFFFF";
ctx.fillRect(0,0,tempW,tempH);
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = canvas.toDataURL("image/jpeg");
createsecondimage(dataURL,tempW,tempH,max_width,max_height,canvas)
}
This is able to resize an image from taken from file reader. I would like to create a second image in the same canvas using the dataURL as the image source but this it does not seem to work this is what I'm doing
function createsecondimage(dataURL,tempW,tempH,max_width,max_height,canvas){
var copy = document.createElement('canvas');
copy.width = max_width;
copy.height = max_height;
var copyctx = copy.getContext("2d");
var sx = (tempW - max_width) / 2
var sy = (tempH - max_height) /2
copyctx.fillStyle="#FFFFFF";
copyctx.fillRect(0,0,max_width,max_height);
var imgcopy = new Image();
imgcopy.src = dataURL;
imgcopy.onload = function() {
copyctx.drawImage(imgcopy, sx, sy, 800, 800,0, 0, 800, 800);
var dataURL_ = copy.toDataURL("image/jpeg");
}
However datURL_ appears to be empty. I'm not sure why this is the case. Ideally I would want to create a new image using the image that was just resized.

You can do the following two changes and it should work:
set imgcpy.src after onload.
Use copyctx.drawImage(this, ...) instead of imgcopy.
This way you are making sure decoding and setting of image is not completed before onload is called, and this will have a valid reference to the image being decoded.

Related

JS multiselect images and draw them into canvas - sometimes canvas blank or same image drawn

I am using JS and a multi select field.
A user can select multiple images from a folder and then each image should be drawn into a canvas. Each image has a predefined canvas and a predefined input field where then the decoded base64 dataurl is placed in.
The multiselect field:
<input id="bild" multiple="" name="bild" type="file">
In my example there are 3 different canvas elements and 3 different dataurl input fields:
$( "input#bild" ).change(function() {
console.log("multiple");
// from an input element
var filesToUpload = this.files;
//console.log(filesToUpload);
if(typeof this.files[0] !== "undefined") {
console.log("multiple-1");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[0]);
$( img ).load(function() {
console.log("multiple-1-loaded");
canvas = $("#uploading_canvas_image_1").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.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/jpg");
$( "#dataurl_image_1" ).val(dataurl);
});
}
if(typeof this.files[1] !== "undefined") {
console.log("multiple-2");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[1]);
$( img ).load(function() {
console.log("multiple-2-loaded");
canvas = $("#uploading_canvas_image_2").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.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/jpg");
$( "#dataurl_image_2" ).val(dataurl);
});
}
if(typeof this.files[2] !== "undefined") {
console.log("multiple-3");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[2]);
$( img ).load(function() {
console.log("multiple-3-loaded");
canvas = $("#uploading_canvas_image_3").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.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/jpg");
$( "#dataurl_image_3" ).val(dataurl);
});
}
For each image I am checking if it is really there and not undefined. Then it is drawn into the canvas and the corresponding field for dataurl is populated with the dataurl.
The Problem is:
I do not get any errors.
The behaviour is different with different sets of images but its always the same with the same set. For example: I am marking 3 different images in the folder which I want to upload, but always all 3 canvas show the same image (3rd) one also all 3 dataurls are the same.
Sometimes some canvas are blank.
Sometimes it works
It seems like a general problem, but I havent managed to locate why this happens. My guess is it maybe has something to do with the onload function for the image and that the dataurl is created in the same steps. The dataurl itself is insanly long. I am looking at this atm. Maybe someone here has an idea.
I found the issue. The img was causing these problems. Because I always used the same img, eventhough it is in the if condition block. It seems that the function itself is stronger then the if condition?
I had to create a new img variable for every image selected, which means I needed this for image 1:
var img1 = document.createElement("img");
img1.src = window.URL.createObjectURL(this.files[0]);
$( img1 ).load(function() {
//...
ctx.drawImage(img1, 0, 0, width, height);
});
For image 2:
var img2 = document.createElement("img");
img2.src = window.URL.createObjectURL(this.files[1]);
$( img2 ).load(function() {
//...
ctx.drawImage(img2, 0, 0, width, height);
});
For image 3:
var img3 = document.createElement("img");
img3.src = window.URL.createObjectURL(this.files[2]);
$( img3 ).load(function() {
//...
ctx.drawImage(img3, 0, 0, width, height);
});

Show resized Base64 output of an image

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

image.onError on jquery-mobile while uploading images

I am using PhoneGap to run my JQuery Mobile Hybrid App.
I am following this tutorial in order to upload image from my Device (Samsung Note4, Android 6.0.1) to the canvas, I have tried with different types of images but I am always getting the execution result of the image.onError.
What could be the reason of getting the image.onError execution?
Here is the code from the tutorial:
function processFile(dataURL, fileType) {
var maxWidth = 800;
var maxHeight = 800;
var image = new Image();
image.src = dataURL;
image.onload = function () {
var width = image.width;
var height = image.height;
var shouldResize = (width > maxWidth) || (height > maxHeight);
if (!shouldResize) {
sendFile(dataURL);
return;
}
var newWidth;
var newHeight;
if (width > height) {
newHeight = height * (maxWidth / width);
newWidth = maxWidth;
} else {
newWidth = width * (maxHeight / height);
newHeight = maxHeight;
}
var canvas = document.createElement('canvas');
canvas.width = newWidth;
canvas.height = newHeight;
var context = canvas.getContext('2d');
context.drawImage(this, 0, 0, newWidth, newHeight);
dataURL = canvas.toDataURL(fileType);
sendFile(dataURL);
};
image.onerror = function () {
alert('There was an error processing your file!');
};
}

HTML5 canvas javascript: toDataURL generates empty dataurl

I have the following form:
<form style="margin:5px;" id="submit-image" method="post" action="/site/recognize" enctype="multipart/form-data">
<input name="photo" id="upload-image" type="file" accept="image/*;capture=camera" >
<input name="photo-resized" id="upload-image-resized" type="hidden">
</form>
Then I have the following javascript:
<script>
var myInput = document.getElementById('upload-image');
function sendPic() {
//var file = myInput.files[0];
// functionality to rezise image BEFORE upload needs to go here
// from an input element
var filesToUpload = document.getElementById("upload-image").files;
var file = filesToUpload[0];
console.log(file);
var canvas = document.createElement('canvas');
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);
console.log(img); // This still outputs a proper image
var MAX_WIDTH = 1000;
var MAX_HEIGHT = 1000;
var width = img.width;
var height = img.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");
var dataurl;
img.onload = function () {
canvas.getContext("2d").drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL();
console.log(dataurl); // Somehow this STILL outputs an empty dataurl, need to find out why
};
document.getElementById('upload-image-resized').value= dataurl;
document.getElementById('submit-image').submit();
var loader = document.getElementsByClassName('ui-loader');
loader[0].style.display = "block";
loader[0].style.opacity = 0.7;
}
myInput.addEventListener('change', sendPic, false);
</script>
As you can see there I have several console.log() statements to help me understand where things are going wrong. I've put a comment there saying "// Somehow this outputs an empty dataurl, need to find out why". That's the point where I'm lost.
I don't understand why the dataurl variable is empty. It just contains "data: , " or something like that.
Any help appreciated.

Multiple image resize with canvas

I've built a drag and drop image uploader.
I want to automatically create thumbnails of each image.
I used html5 canvas, but when I'm uploading 20 or more 2MB images at once, the browser (safari) crashes. When I leave the resize function out, everything works fine.
Any suggestions on how to handle this? Thank you very much!
this is the resize function that is called on every image:
if(this.hasFileReader){
var reader = new FileReader();
reader.readAsDataURL(this.file);
var file = this.file;
reader.onloadend = function(e){
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function() {
var MAX_WIDTH = 348;
var MAX_HEIGHT = 300;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH) {
if (tempW > MAX_WIDTH) {
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
} else {
if (tempH > MAX_HEIGHT) {
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
var canvas = document.createElement('canvas');
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = canvas.toDataURL("image/jpeg");
var xhr = new XMLHttpRequest();
xhr.open('POST', 'uploadResized.php', true);
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
var data = 'image=' + dataURL + '&name=' + file.name + '&type=' + file.type;
xhr.send(data);
}
}
You are creating a new canvas element for each image in your batch and canvases are expensive.
Instead, do `var canvas=document.createElement('canvas') once outside the loop.
That way only 1 canvas element is created instead of many.
BTW, when you do canvas.width=tempW inside the loop your canvas is automatically cleared so you don't need to add clearRect.

Categories

Resources