admin管理员组文章数量:1134570
The standard HTML file upload works as follows:
<g:form method="post" accept-charset="utf-8" enctype="multipart/form-data"
name="form" url="someurl">
<input type="file" name="file" id="file" />
</form>
In my case I loaded an image into a html5 canvas and want to submit it as a file to the server. I can do:
var canvas; // some canvas with an image
var url = canvas.toDataURL();
This gives me a image/png as base64.
How can I send the base64 image to the server the same way it is done with the input type file?
The problem is that the base64 file is not of the same type as the file, which is inside the input type="file".
Can I convert the base64 that the types are the same for the server somehow?
The standard HTML file upload works as follows:
<g:form method="post" accept-charset="utf-8" enctype="multipart/form-data"
name="form" url="someurl">
<input type="file" name="file" id="file" />
</form>
In my case I loaded an image into a html5 canvas and want to submit it as a file to the server. I can do:
var canvas; // some canvas with an image
var url = canvas.toDataURL();
This gives me a image/png as base64.
How can I send the base64 image to the server the same way it is done with the input type file?
The problem is that the base64 file is not of the same type as the file, which is inside the input type="file".
Can I convert the base64 that the types are the same for the server somehow?
Share Improve this question edited Jan 12, 2018 at 3:28 Robert Caden 1911 bronze badges asked Sep 26, 2013 at 15:28 MichaelMichael 33.3k50 gold badges222 silver badges374 bronze badges 14 | Show 9 more comments8 Answers
Reset to default 79For security reasons, you can't set the value of a file-input element directly.
If you want to use a file-input element:
- Create an image from the canvas (as you've done).
- Display that image on a new page.
- Have the user right-click-save-as to their local drive.
- Then they can use your file-input element to upload that newly created file.
Alternatively, you can use Ajax to POST the canvas data:
You asked about blob:
var blobBin = atob(dataURL.split(',')[1]);
var array = [];
for(var i = 0; i < blobBin.length; i++) {
array.push(blobBin.charCodeAt(i));
}
var file=new Blob([new Uint8Array(array)], {type: 'image/png'});
var formdata = new FormData();
formdata.append("myNewFileName", file);
$.ajax({
url: "uploadFile.php",
type: "POST",
data: formdata,
processData: false,
contentType: false,
}).done(function(respond){
alert(respond);
});
Note: blob is generally supported in the latest browsers.
This is what worked for me in the end.
canvas.toBlob((blob) => {
let file = new File([blob], "fileName.jpg", { type: "image/jpeg" })
}, 'image/jpeg');
The canvas image needs to be converted to base64 and then from base64 in to binary. This is done using .toDataURL()
and dataURItoBlob()
It was a pretty fiddly process which required piecing together several SO answers, various blog posts and tutorials.
I've created a tutorial you can follow which walks you through the process.
In response to Ateik's comment here's a fiddle which replicates the original post in case you're having trouble viewing the original link. You can also fork my project here.
There's a lot of code but the core of what I'm doing is take a canvas element:
<canvas id="flatten" width="800" height="600"></canvas>
Set it's context to 2D
var snap = document.getElementById('flatten');
var flatten = snap.getContext('2d');
Canvas => Base64 => Binary
function postCanvasToURL() {
// Convert canvas image to Base64
var img = snap.toDataURL();
// Convert Base64 image to binary
var file = dataURItoBlob(img);
}
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
You could stop at base64 if that's all you need, in my case I needed to convert again to binary so that I could pass the data over to twitter (using OAuth) without use of a db. It turns out you can tweet binary which is pretty cool, twitter will convert it back in to an image.
Currently in spec (very little support as of april '17)
Canvas.toBlob();
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
EDIT :
The link provides a polyfill (which seems to be slower from the wording), which code is roughtly equivalent to the @pixelomo answer, but with the same api as the native toBlob
method :
A low performance polyfill based on toDataURL :
if (!HTMLCanvasElement.prototype.toBlob) {
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
value: function (callback, type, quality) {
var canvas = this;
setTimeout(function() {
var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] ),
len = binStr.length,
arr = new Uint8Array(len);
for (var i = 0; i < len; i++ ) {
arr[i] = binStr.charCodeAt(i);
}
callback( new Blob( [arr], {type: type || 'image/png'} ) );
});
}
});
}
To be used this way :
canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95); // JPEG at 95% quality
or
canvas.toBlob(function(blob){...}); // PNG
const canvas = document.querySelector("canvas");
canvas.toBlob(blob => {
const file = new File([blob], "image.png");
});
Another solution: send the data in var url in a hidden field, decode and save it on the server.
Example in Python Django:
if form.is_valid():
url = form.cleaned_data['url']
url_decoded = b64decode(url.encode())
content = ContentFile(url_decoded)
your_model.model_field.save('image.png', content)
I used to do it quite simply
var formData = new FormData(),
uploadedImageName = 'selfie.png';
canvas.toBlob(function (blob) {
formData.append('user_picture', blob, uploadedImageName);
$.ajax({
data: formData,
type: "POST",
dataType: "JSON",
url: '',
processData: false,
contentType: false,
});
});
2023 answer using toBlob
and TypeScript:
const dataBlob = await new Promise<Blob | null>(
(resolve) => canvas.toBlob(
(blob) => resolve(blob),
"image/png",
)
);
本文标签: javascriptConvert HTML5 Canvas into File to be uploadedStack Overflow
版权声明:本文标题:javascript - Convert HTML5 Canvas into File to be uploaded? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736833606a1954805.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
canvas.toBlob()
. Read more at developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement – Ray Nicholus Commented Sep 26, 2013 at 15:36