Reputation: 18379
Ok, I'm at my whits end on this one. I am trying to resize uploaded images on the client with Javascript.
I'm using,
<script>
function uploadFiles() {
if (window.File && window.FileReader && window.FileList && window.Blob) {
if (!document.getElementById('confirm').checked) {
alert('You must click "confirm".');
return false;
}
alert('begin');
var files = document.getElementById('file').files;
for(var i = 0; i < files.length; i++) {
alert('start');
resizeAndUpload(files[i]);
}
return false;
} else {
alert('The File APIs are not fully supported in this browser.');
return false;
}
}
function resizeAndUpload(file) {
var reader = new FileReader();
reader.onloadend = function() {
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function() {
var MAX_WIDTH = 300;
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 fd = new FormData();
fd.append("upload-avatar", "Upload");
var confirm = 'off';
if (document.getElementById('confirm').checked) {
confirm = 'on';
}
fd.append("confirm", confirm);
fd.append("file", canvas.mozGetAsFile("image.jpg"));
fd.append("license", document.getElementById('license').value);
fd.append("name", document.getElementById('name').value);
var share = 'off';
if (document.getElementById('share').checked) {
share = 'on';
}
fd.append("share", share);
var xhr = new XMLHttpRequest();
xhr.open("POST", "MyUploadServlet");
xhr.send(fd);
alert('done');
}
}
reader.readAsDataURL(file);
}
</script>
Then in my html I have,
<form onsubmit="return uploadFiles()" method="post" enctype="multipart/form-data">
<input id="file" type="file" name="file" multiple/><br/>
<input id="confirm" type="checkbox" name="confirm">confirm</input><br/>
...
<input name="upload-resize" value="Upload and resize" type="submit"/><br/>
</form>
This actually works, sort of, but the page does not reload, which I want it to do to show the uploaded images. If I return true from the function which I think will cause a reload then it does not work, it never seems to call the post and hangs. I also tried location.reload() but similar issue.
Ok I guess I have a few questions on this code:
1 - How to reload the page?
-> The answer seems to be call "history.go(0);", this seemed to work,
2 - This only works on Firefox, not Chrome, IE, or Safari I assume because of the usage of "canvas.mozGetAsFile("image.jpg")", any idea how to get it to work on Chrome?
-> using toBlob seems to work, but seems to break with the page reload, works on Firefox but not others (without polyfill which I have not tried yet)
3 - Ideally I would have two buttons, one that does the resize, and one that does the normal form submit, no idea how to do that either. Currently I have two complete copies of the form, one for resize, and one for normal file submit.
4 - The images are uploaded as png format, how to compress as jpeg, or compress in general, even with the resize, some images show up bigger than the were as they loose their compression.
-> using toBlob seems to give you jpg, but seems to break with the page reload, works on Firefox but not others (without polyfill which I have not tried yet)
Sorry for the multi-part question, but I think anyone wanting to do this will need all of the answers.
Upvotes: 0
Views: 420
Reputation: 15420
Q2 use canvas.toBlob instead of canvas.mozGetAsFile. There is a polyfill to increase browser compatibility.
Usage as show in their page
var canvas = document.createElement('canvas');
canvas.toBlob(
function (blob) {
// the blob is the jpeg file
var formData = new FormData();
formData.append('file', blob, fileName);
/* ... */
},
'image/jpeg'
);
Q4
specify canvas.toBlob(callback, 'image/jpeg', quality)
where quality is from 0.0 to 1.0 (highest quality)
Q3 you can have multiple buttons in a form.
<form>
<input id="file" type="file" name="file" multiple/><br/>
<input id="confirm" type="checkbox" name="confirm">confirm</input><br/>
...
<input name="upload" value="Upload" type="button"/>
<input name="upload-resize" value="Upload and resize" type="button"/>
</form>
Note that the form tag doesn't contain the onsubmit attribute and the input type is now button instead of submit.
<input name="upload" value="Upload" type="button" onclick="myfunction()"/>
or instead of onclick attribute, you can use addEventListener, etc.
Q1 You shoudn't go back in the history. Your location.reload() is correct but it must be done after the send/upload is completed.
xhr.onreadystatechange = function() {
if (xhr.readyState != 4) { return; }
location.reload();
}
XMLHttpRequest is asynchronous so the send method returns even before the upload has completed! To know if the send has finished, use onreadystatechange as shown above.
Note: you may want to check the response status code too.
Upvotes: 1