HTML5 canvas javascript: toDataURL generates empty dataurl - javascript

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.

Related

How to input an image and use that as the cursor?

I am trying to make a cursor changer, where the user can upload an image, and it will be the cursor anywhere on the document <body>. However it doesn't seem to work. I have tried .append and .appendChild, but it doesn't seem to work. Where have I gone wrong?
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('#uploaded1').attr('src', e.target.result);
$("#upload-cursor").css("display", "block");
$("#upload-cursor").click(function() {
$("body").css("cursor", "url(" + e.target.result + "), auto");
});
};
reader.readAsDataURL(input.files[0]);
}
}
$("#imgInp").change(function() {
readURL(this);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h5>Upload Cursor</h5>
<form runat="server">
<input type='file' id="imgInp">
<img id="uploaded1" src="#" width="50px" height="50px">
<br>
</form>
<button id="upload-cursor" style="display: none;">Create Cursor</button>
As the above answer, you image size might be big so do resize the Image.
to resize use the File API, then you can process the images with the canvas element.
This Mozilla Hacks blog post walks you through most of the process. For reference here's the assembled source code from the blog post:
// from an input element
var filesToUpload = input.files;
var file = filesToUpload[0];
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);
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;
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");
//Post dataurl to the server with AJAX
Resizing before uploading:
HTML5 Pre-resize images before uploading

Reducing size of the image at Client Side in javascript before form submission

Im trying to reduce the size of the image after reading at client side, the javascript code is as below, I'm getting two issues here
1) The image preview is not showing up on the img id "img-upload"
2) The file that is being submitted via form submission "reader.readAsDataURL(input.files[0])" is not the reduced size one.
I did try changing code to move the reader inside the image onload and then pass e.target.files[0] but that didn't work either.
Pls advise how I can resize and then send it via form submission to my backend.
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#img-upload').attr('src', e.target.result);
img.onload = function () {
var MAX_WIDTH = 100;
var MAX_HEIGHT = 100;
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;
}
}
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(this, 0, 0, width, height);
img.src = e.target.result;
$('#img-upload').append(img);
}
}
reader.readAsDataURL(input.files[0]);
}
}
Your code is creating an infinite call to img.onload
because of this
img.src = e.target.result; statement inside onload.
Beside this you are not reading the resized image from the canvas.
You can do this the following way
canvas.toDataURL('image/png');
SNIPPET
var img = $('#img-upload')[0];
var show = $('#show')[0];
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
debugger;
$('#img-upload').attr('src', e.target.result);
img.onload = function() {
var MAX_WIDTH = 100;
var MAX_HEIGHT = 100;
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;
}
}
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
canvas.getContext("2d").drawImage(this, 0, 0, width, height);
//Causing Infinite Loop in your code
//img.src = e.target.result;
// Get dataURL of resized image from canvas
show.src = canvas.toDataURL('image/png');
}
}
reader.readAsDataURL(input.files[0]);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" onchange="readURL(this)">
<img id="img-upload">
<img id="show">

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

Canvas draw new image from daturl

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.

A canvas into which I would like to load a Base64 string that represents a png image but just displays a blank white box

I have a canvas into which I would like to load a Base64 string that represents a png image. However, the following code just displays a blank white box and I am baffled as to why. When I look at the data in the canvas, it looks identical to a canvas that gets its data from a FileReader object (also below). Any help deducing this issue is greatly appreciated!
This code shows a white canvas:
html
<canvas id="canvas" width="114" height="114" style="z-index: 999999; display: none; padding-left: 50px"></canvas>
javascript
var websiteIconData = $('#ctl00_ContentPlaceHolder1_websiteIcon');
if (websiteIconData.val() != '') {
var canvas = document.getElementById('canvas');
var ctx = document.getElementById('canvas').getContext('2d');
var loadedImg = new Image();
loadedImg.onload = function () {
ctx.drawImage(this, 0, 0);
Debugger.log(ctx);
};
loadedImg.src = websiteIconData.val();
canvas.style.display = 'block';
}
This code shows the image:
$('#loadWebsiteIcon').on({
change: function (ev) {
var reader = new FileReader();
reader.onload = function (e) {
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function () {
var MAX_WIDTH = 114;
var MAX_HEIGHT = 114;
var width = img.width;
var height = img.height;
if (width > MAX_WIDTH) {
width = MAX_WIDTH;
}
if (height > MAX_HEIGHT) {
height = MAX_HEIGHT;
}
ctx.drawImage(img, 0, 0, width, height);
for (var i = 0; i <= document.images.length; i++) {
}
Debugger.log(ctx);
};
img.src = e.target.result;
}
draw();
};
reader.readAsDataURL(ev.target.files[0]);
var canvas = document.getElementById('canvas');
canvas.style.display = 'block';
var imgData = canvas.toDataURL();
$('#ctl00_ContentPlaceHolder1_websiteIcon').val(imgData);
Debugger.log(imgData);
}
});
Be careful how Base64 is parsed. If it is parsed for email, it will insert a character ever 76 lines by default. Most Base64 encoders have an option to turn this off. I am looking at MIME::Base64
From that document :
The returned encoded string is broken into lines of no more than 76 characters each and it >will end with $eol unless it is empty.
where $eol was one of the arguments. In the case of this module, setting it to an empty string would prevent the base64 from being broken up.
It turns out the issue had little to do with the canvas API or the Base64 encoding. It was more an issue of the canvas.toDataURL(); function getting called before the image had been loaded in the canvas. Moving this line to within the img.onload function seemed to do the trick. Below is the correct code:
function initImageChange() {
//this is will be a string in Base64, in this case it is an <input type="text">... tag
var imageData = $('#imageData');
//this is a canvas tag in on the page
var canvas = document.getElementById('canvas');
//load the image from the imageData var if it exists
if (imageData.val() != '') {
var ctx2=canvas.getContext('2d');
var loadedImg = new Image();
loadedImg.onload = function() {
ctx2.drawImage(this, 0, 0);
};
loadedImg.src = imageData.val();
canvas.style.display = 'block';
}
//this is a function that loads an image from a file onto the canvas and
//sends the Base64 representation of this image to the text input tag. This
//could fairly easily be send directly to a post request or saved some other way
$('#loadImage').on({
change: function (ev) {
var ctx = document.getElementById('canvas').getContext('2d');
var dataURL = '';
var reader = new FileReader();
reader.onload = function (e) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
function draw() {
var img = new Image();
img.onload = function () {
var MAX_WIDTH = 130;
var MAX_HEIGHT = 110;
var width = img.width;
var height = img.height;
if (width > MAX_WIDTH) {
width = MAX_WIDTH;
}
if (height > MAX_HEIGHT) {
height = MAX_HEIGHT;
}
ctx.drawImage(img, 0, 0, width, height);
dataURL = canvas.toDataURL();
$('#ctl00_ContentPlaceHolder1_websiteIcon').val(dataURL);
ctx.restore();
};
img.src = e.target.result;
}
draw();
};
reader.readAsDataURL(ev.target.files[0]);
canvas.style.display = 'block';
}
});
}

Categories

Resources