将 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 转换为要上传的文件?的主要内容,如果未能解决你的问题,请参考以下文章

将html转换成canvas

HTML5——Canvas 高级操作

前端HTML页面转PDF(html2canvas+jspdf)

如何将 SVG 文件转换为 HTML5 的画布?

HTML5 画布转 PNG 文件

jCrop HTML5 Canvas Base64