【问题标题】:Convert HTML5 Canvas into File to be uploaded?将 HTML5 Canvas 转换为要上传的文件?
【发布时间】: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?

【问题讨论】:

标签: javascript jquery html5-canvas base64


【解决方案1】:

出于安全原因,您不能直接设置文件输入元素的值。

如果你想使用文件输入元素:

  1. 从画布创建一个图像(如您所做的那样)。
  2. 在新页面上显示该图像。
  3. 让用户右键单击并保存到他们的本地驱动器。
  4. 然后他们可以使用您的文件输入元素上传新创建的文件。

或者,您可以使用 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 将图像发送到您的服务器。这是有关使用该替代方法的 stackoverflow 帖子:stackoverflow.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" width="800" height="600"></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 中添加一些上下文。
          猜你喜欢
          • 2015-12-12
          • 1970-01-01
          • 1970-01-01
          • 2011-07-28
          • 1970-01-01
          • 2020-06-28
          • 1970-01-01
          • 2011-09-10
          相关资源
          最近更新 更多