将 HTML5 Canvas 转换为要上传的文件?
Posted
技术标签:
【中文标题】将 HTML5 Canvas 转换为要上传的文件?【英文标题】:Convert HTML5 Canvas into File to be uploaded? 【发布时间】:2013-10-02 16:01:18 【问题描述】:标准的 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>
在我的情况下,我将图像加载到 html5 画布中,并希望将其作为文件提交到服务器。 我能做到:
var canvas; // some canvas with an image
var url = canvas.toDataURL();
这给了我一个 base64 格式的图像/png。
如何将 base64 图像发送到服务器,就像使用输入类型文件一样?
问题是base64文件和文件的类型不一样,在input type="file"里面。
能否以某种方式转换服务器类型相同的base64?
【问题讨论】:
canvas.toBlob()
。阅读更多developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement
@RayNicholus 以及如何将 blob 放入文件输入中?
你没有。通过 ajax 请求发送。
@RayNicholus 那么如何将 blob 发送到服务器?
如我所说,通过 ajax 请求发送。
【参考方案1】:
出于安全原因,您不能直接设置文件输入元素的值。
如果你想使用文件输入元素:
-
从画布创建一个图像(如您所做的那样)。
在新页面上显示该图像。
让用户右键单击并保存到他们的本地驱动器。
然后他们可以使用您的文件输入元素上传新创建的文件。
或者,您可以使用 Ajax 发布画布数据:
你问的是 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);
);
注意:最新的浏览器一般都支持 blob。
【讨论】:
我要发送图片到服务器! 明白!如果要使用 html 文件输入元素,请使用我的答案中的方法。或者,您可以使用 Ajax 将图像发送到您的服务器。这是有关使用该替代方法的 *** 帖子:***.com/questions/13198131/… 它在 Chrome 中有效,但在 Firefox 中无效。服务器端的数据始终为空。有什么想法吗? Firefox 的问题是脚本中断了。 如果图像太大,FireFox 会中断。 (例如,7MB)【参考方案2】:另一种解决方案:将 var url 中的数据发送到隐藏字段中,解码并保存在服务器上。
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)
【讨论】:
【参考方案3】:画布图像需要先转换为base64,然后再从base64转换为二进制。这是使用.toDataURL()
和dataURItoBlob()
完成的
这是一个非常繁琐的过程,需要拼凑几个 SO 答案、各种博客文章和教程。
I've created a tutorial you can follow which walks you through the process。
为了回应 Ateik 的评论,这里是 a fiddle,它复制了原始帖子,以防您在查看原始链接时遇到问题。你也可以fork my project here。
有很多代码,但我所做的核心是获取一个画布元素:
<canvas id="flatten" ></canvas>
将其上下文设置为 2D
var snap = document.getElementById('flatten');
var flatten = snap.getContext('2d');
画布 => 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);
如果这就是你所需要的,你可以在 base64 处停下来,在我的情况下,我需要再次转换为二进制,以便我可以在不使用数据库的情况下将数据传递给 twitter(使用 OAuth)。事实证明,你可以推特二进制文件,这很酷,推特会将其转换回图像。
【讨论】:
我收到错误 502:您发布的链接的网关错误 修复了链接! 帮了我很多忙!谢谢! @Michael Chaney 这是在 toBlob 之前这样做的方法,不要居高临下,如果有更简单的方法现在写一个答案 @pixelomo 不想居高临下。但你是对的,它应该得到一个更新的答案。【参考方案4】:目前在规范中(截至 17 年 4 月支持很少)
Canvas.toBlob();
https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
编辑:
该链接提供了一个 polyfill(从措辞上似乎更慢),该代码大致相当于 @pixelomo 的答案,但与原生 toBlob
方法具有相同的 api:
一个基于 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' ) );
);
);
这样使用:
canvas.toBlob(function(blob)..., 'image/jpeg', 0.95); // JPEG at 95% quality
或
canvas.toBlob(function(blob)...); // PNG
【讨论】:
【参考方案5】:这最终对我有用。
canvas.toBlob((blob) =>
let file = new File([blob], "fileName.jpg", type: "image/jpeg" )
, 'image/jpeg');
【讨论】:
【参考方案6】:我以前做的很简单
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,
);
);
【讨论】:
【参考方案7】:const canvas = document.querySelector("canvas");
canvas.toBlob(blob =>
const file = new File([blob], "image.png");
);
【讨论】:
请在上面添加的代码 sn-p 中添加一些上下文。以上是关于将 HTML5 Canvas 转换为要上传的文件?的主要内容,如果未能解决你的问题,请参考以下文章