首页 文章

将数据URI转换为File然后附加到FormData

提问于
浏览
253

我一直在尝试重新实现像一个on the Mozilla Hacks网站的HTML5图像上传器,但它适用于WebKit浏览器 . 部分任务是从 canvas 对象中提取图像文件,并将其附加到FormData对象以进行上载 .

问题是,虽然 canvas 具有 toDataURL 函数来返回图像文件的表示,但FormData对象仅接受来自File API的文件或Blob对象 .

Mozilla解决方案在 canvas 上使用了以下仅限Firefox的功能:

var file = canvas.mozGetAsFile("foo.png");

...在WebKit浏览器上不可用 . 我能想到的最好的解决方案是找到一种方法将数据URI转换为File对象,我认为它可能是File API的一部分,但我不能为我的生活找到一些东西 .

可能吗?如果没有,任何替代方案?

谢谢 .

14 回答

  • 0

    通过更改最后一行以适应Blob,Stoive的原始答案很容易解决:

    function dataURItoBlob (dataURI) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs
        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 an ArrayBuffer
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
    
        // write the ArrayBuffer to a blob, and you're done
        return new Blob([ab],{type: mimeString});
    }
    
  • 3

    现在不推荐使用BlobBuilder和ArrayBuffer,这是使用Blob构造函数更新的顶级注释代码:

    function dataURItoBlob(dataURI) {
        var binary = atob(dataURI.split(',')[1]);
        var array = [];
        for(var i = 0; i < binary.length; i++) {
            array.push(binary.charCodeAt(i));
        }
        return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
    }
    
  • 19

    我的首选方式是canvas.toBlob()

    但无论如何这里是使用fetch ^^将base64转换为blob的另一种方法,

    var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
    
    fetch(url)
    .then(res => res.blob())
    .then(blob => {
      var fd = new FormData()
      fd.append('image', blob, 'filename')
      
      console.log(blob)
    
      // Upload
      // fetch('upload', {method: 'POST', body: fd})
    })
    
  • 1

    简单说明:D

    function dataURItoBlob(dataURI,mime) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs
    
        var byteString = window.atob(dataURI);
    
        // separate out the mime component
    
    
        // write the bytes of the string to an ArrayBuffer
        //var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
    
        // write the ArrayBuffer to a blob, and you're done
        var blob = new Blob([ia], { type: mime });
    
        return blob;
    }
    
  • -4
    var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);
    

    可以在没有try catch的情况下使用 .

    感谢check_ca . 做得好 .

  • 19

    在玩了几件事之后,我设法自己解决了这个问题 .

    首先,这会将dataURI转换为Blob:

    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});
    }
    

    从那里,将数据附加到表单以便将其作为文件上载很容易:

    var dataURL = canvas.toDataURL('image/jpeg', 0.5);
    var blob = dataURItoBlob(dataURL);
    var fd = new FormData(document.forms[0]);
    fd.append("canvasImage", blob);
    
  • 23

    感谢@Stoive和@ vava720我以这种方式结合了两者,避免使用不推荐使用的BlobBuilder和ArrayBuffer

    function dataURItoBlob(dataURI) {
        'use strict'
        var byteString, 
            mimestring 
    
        if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
            byteString = atob(dataURI.split(',')[1])
        } else {
            byteString = decodeURI(dataURI.split(',')[1])
        }
    
        mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]
    
        var content = new Array();
        for (var i = 0; i < byteString.length; i++) {
            content[i] = byteString.charCodeAt(i)
        }
    
        return new Blob([new Uint8Array(content)], {type: mimestring});
    }
    
  • 4

    这是Stoive's answer的ES6版本:

    export class ImageDataConverter {
      constructor(dataURI) {
        this.dataURI = dataURI;
      }
    
      getByteString() {
        let byteString;
        if (this.dataURI.split(',')[0].indexOf('base64') >= 0) {
          byteString = atob(this.dataURI.split(',')[1]);
        } else {
          byteString = decodeURI(this.dataURI.split(',')[1]);
        }
        return byteString;
      }
    
      getMimeString() {
        return this.dataURI.split(',')[0].split(':')[1].split(';')[0];
      }
    
      convertToTypedArray() {
        let byteString = this.getByteString();
        let ia = new Uint8Array(byteString.length);
        for (let i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
        }
        return ia;
      }
    
      dataURItoBlob() {
        let mimeString = this.getMimeString();
        let intArray = this.convertToTypedArray();
        return new Blob([intArray], {type: mimeString});
      }
    }
    

    用法:

    const dataURL = canvas.toDataURL('image/jpeg', 0.5);
    const blob = new ImageDataConverter(dataURL).dataURItoBlob();
    let fd = new FormData(document.forms[0]);
    fd.append("canvasImage", blob);
    
  • 138

    不断发展的标准似乎是canvas.toBlob()而不是像Mozilla猜测的canvas.getAsFile() .

    我没有看到任何支持它的浏览器:(

    谢谢你这个伟大的线程!

    此外,任何尝试接受答案的人都应该小心使用BlobBuilder,因为我发现支持受到限制(和命名空间):

    var bb;
        try {
            bb = new BlobBuilder();
        } catch(e) {
            try {
                bb = new WebKitBlobBuilder();
            } catch(e) {
                bb = new MozBlobBuilder();
            }
        }
    

    你在BlobBuilder上使用另一个库的polyfill吗?

  • 50

    toDataURL为您提供了一个字符串,您可以将该字符串放入隐藏的输入中 .

  • 5

    Firefox有canvas.toBlob()canvas.mozGetAsFile()方法 .

    但其他浏览器则没有 .

    我们可以从canvas获取dataurl,然后将dataurl转换为blob对象 .

    这是我的 dataURLtoBlob() 功能 . 它很短 .

    function dataURLtoBlob(dataurl) {
        var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
        while(n--){
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], {type:mime});
    }
    

    将此函数与FormData一起使用来处理画布或dataurl .

    例如:

    var dataurl = canvas.toDataURL('image/jpeg',0.8);
    var blob = dataURLtoBlob(dataurl);
    var fd = new FormData();
    fd.append("myFile", blob, "thumb.jpg");
    

    此外,您可以为非gecko引擎浏览器创建 HTMLCanvasElement.prototype.toBlob 方法 .

    if(!HTMLCanvasElement.prototype.toBlob){
        HTMLCanvasElement.prototype.toBlob = function(callback, type, encoderOptions){
            var dataurl = this.toDataURL(type, encoderOptions);
            var bstr = atob(dataurl.split(',')[1]), n = bstr.length, u8arr = new Uint8Array(n);
            while(n--){
                u8arr[n] = bstr.charCodeAt(n);
            }
            var blob = new Blob([u8arr], {type: type});
            callback.call(this, blob);
        };
    }
    

    现在 canvas.toBlob() 适用于所有现代浏览器,不仅适用于Firefox . 例如:

    canvas.toBlob(
        function(blob){
            var fd = new FormData();
            fd.append("myFile", blob, "thumb.jpg");
            //continue do something...
        },
        'image/jpeg',
        0.8
    );
    
  • 12

    谢谢! @steovi为此解决方案 .

    我已经添加了对ES6版本的支持,并从unescape更改为dataURI(不推荐使用unescape) .

    converterDataURItoBlob(dataURI) {
        let byteString;
        let mimeString;
        let ia;
    
        if (dataURI.split(',')[0].indexOf('base64') >= 0) {
          byteString = atob(dataURI.split(',')[1]);
        } else {
          byteString = encodeURI(dataURI.split(',')[1]);
        }
        // separate out the mime component
        mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    
        // write the bytes of the string to a typed array
        ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ia], {type:mimeString});
    }
    
  • 423

    这个适用于iOS和Safari .

    你需要使用Stoive的ArrayBuffer解决方案,但是你不能像vava720那样使用BlobBuilder,所以这里是两者的混搭 .

    function dataURItoBlob(dataURI) {
        var byteString = atob(dataURI.split(',')[1]);
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ab], { type: 'image/jpeg' });
    }
    
  • -1

    我有与Ravinder Payal完全相同的问题,我找到了答案 . 试试这个:

    var dataURL = canvas.toDataURL("image/jpeg");
    
    var name = "image.jpg";
    var parseFile = new Parse.File(name, {base64: dataURL.substring(23)});
    

相关问题