77

标准的 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文件与输入类型=“file”内的文件类型不同。

我可以以某种方式转换服务器类型相同的base64吗?

4

7 回答 7

77

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

如果要使用文件输入元素:

  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。

于 2013-09-26T15:41:44.067 回答
40

画布图像需要转换为base64,然后从base64转换为二进制。这是使用.toDataURL()dataURItoBlob()

这是一个非常繁琐的过程,需要拼凑几个 SO 答案、各种博客文章和教程。

我创建了一个教程,您可以按照该教程指导您完成整个过程

作为对 Ateik 评论的回应,这里有一个复制原始帖子的小提琴,以防您在查看原始链接时遇到问题。你也可以在这里 fork 我的项目

有很多代码,但我正在做的核心是使用画布元素:

<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)。事实证明,您可以推特二进制文件,这非常酷,推特会将其转换回图像。

于 2016-02-12T15:47:16.677 回答
13

目前在规范中(截至 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
于 2017-04-22T12:06:44.343 回答
12

这最终对我有用。

canvas.toBlob((blob) => {
  let file = new File([blob], "fileName.jpg", { type: "image/jpeg" })
}, 'image/jpeg');

于 2020-10-21T12:00:48.147 回答
9

另一种解决方案:将 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)
于 2014-10-24T15:41:16.340 回答
4

我以前做的很简单

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,
    });
});
于 2020-11-29T00:50:29.447 回答
2
const canvas = document.querySelector("canvas");
canvas.toBlob(blob => {
  const file = new File([blob], "image.png");
});
于 2021-03-24T14:40:03.937 回答