jQuery 将 HTML5 Canvas 转换为要上传的文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19032406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert HTML5 Canvas into File to be uploaded?
提问by confile
The standard HTML file upload works as follows:
标准的 HTML 文件上传工作如下:
<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:
就我而言,我将图像加载到 html5 画布中,并希望将其作为文件提交到服务器。我可以:
var canvas; // some canvas with an image
var url = canvas.toDataURL();
This gives me a image/png as base64.
这给了我一个图像/png 作为 base64。
How can I send the base64 image to the server the same way it is done with the input type file?
如何以与输入类型文件相同的方式将 base64 图像发送到服务器?
The problem is that the base64 file is not of the same type as the file, which is inside the input type="file".
问题是base64文件与输入类型=“文件”中的文件的类型不同。
Can I convert the base64 that the types are the same for the server somehow?
我可以以某种方式转换服务器的类型相同的 base64 吗?
回答by markE
For 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:
或者,您可以使用 Ajax POST 画布数据:
You asked about blob:
你问过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.
注意:最新的浏览器通常支持 blob。
回答by Pixelomo
The canvas image needs to be converted to base64 and then from base64 in to binary. This is done using .toDataURL()
and dataURItoBlob()
画布图像需要先转为base64,然后再从base64转成二进制。这是使用.toDataURL()
和完成的dataURItoBlob()
It was a pretty fiddly process which required piecing together several SO answers, various blog posts and tutorials.
这是一个非常繁琐的过程,需要将几个 SO 答案、各种博客文章和教程拼凑在一起。
I've created a tutorial you can follow which walks you through the process.
In response to Ateik's comment here's a fiddlewhich replicates the original post in case you're having trouble viewing the original link. You can also fork my project here.
为了回应 Ateik 的评论,这里有一个小提琴,它复制了原始帖子,以防您在查看原始链接时遇到问题。你也可以在这里 fork 我的项目。
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
将其上下文设置为 2D
var snap = document.getElementById('flatten');
var flatten = snap.getContext('2d');
Canvas => Base64 => Binary
画布 => Base64 => 二进制
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.
如果这就是你所需要的,你可以停在 base64,在我的情况下,我需要再次转换为二进制,以便我可以将数据传递到 twitter(使用 OAuth)而不使用数据库。事实证明,您可以发送非常酷的二进制推文,推特会将其转换回图像。
回答by Danie A
Currently in spec (very little support as of april '17)
目前在规范中(截至 17 年 4 月几乎没有支持)
Canvas.toBlob();
Canvas.toBlob();
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/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 :
该链接提供了一个 polyfill(从措辞上看似乎更慢),该代码大致相当于@pixelomo 的答案,但具有与本机toBlob
方法相同的 api :
A low performance polyfill based on toDataURL :
基于 toDataURL 的低性能 polyfill:
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
回答by Ardine
Another solution: send the data in var url in a hidden field, decode and save it on the server.
另一种解决方案:将 var url 中的数据发送到隐藏字段中,解码并保存在服务器上。
Example in Python Django:
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)