Javascript 将数据 URI 转换为文件,然后附加到 FormData

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4998908/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 15:09:24  来源:igfitidea点击:

Convert Data URI to File then append to FormData

javascripthtmlwebkit

提问by Stoive

I've been trying to re-implement an HTML5 image uploader like the one on the Mozilla Hackssite, but that works with WebKit browsers. Part of the task is to extract an image file from the canvasobject and append it to a FormDataobject for upload.

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

The issue is that while canvashas the toDataURLfunction to return a representation of the image file, the FormData object only accepts File or Blob objects from the File API.

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

The Mozilla solution used the following Firefox-only function on canvas:

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

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

...which isn't available on WebKit browsers. The best solution I could think of is to find some way to convert a Data URI into a File object, which I thought might be part of the File API, but I can't for the life of me find something to do that.

...在 WebKit 浏览器上不可用。我能想到的最佳解决方案是找到某种方法将 Data URI 转换为 File 对象,我认为这可能是 File API 的一部分,但我一生都找不到这样做的方法。

Is it possible? If not, any alternatives?

是否可以?如果没有,有什么替代方案吗?

Thanks.

谢谢。

回答by Stoive

After playing around with a few things, I managed to figure this out myself.

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

First of all, this will convert a dataURI to a Blob:

首先,这会将 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});
}

From there, appending the data to a form such that it will be uploaded as a file is easy:

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

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

回答by vava720

BlobBuilder and ArrayBuffer are now deprecated, here is the top comment's code updated with Blob constructor:

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

回答by William T.

This one works in iOS and Safari.

这个适用于 iOS 和 Safari。

You need to use Stoive's ArrayBuffer solution but you can't use BlobBuilder, as vava720 indicates, so here's the mashup of both.

您需要使用 Stoive 的 ArrayBuffer 解决方案,但不能使用 BlobBuilder,如 vava720 所示,因此这里是两者的混搭。

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

回答by cuixiping

Firefox has canvas.toBlob()and canvas.mozGetAsFile()methods.

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

But other browsers do not.

但其他浏览器没有。

We can get dataurl from canvas and then convert dataurl to blob object.

我们可以从画布中获取 dataurl,然后将 dataurl 转换为 blob 对象。

Here is my dataURLtoBlob()function. It's very short.

这是我的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});
}

Use this function with FormData to handle your canvas or dataurl.

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

For example:

例如:

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

Also, you can create a HTMLCanvasElement.prototype.toBlobmethod for non gecko engine browser.

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

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

Now canvas.toBlob()works for all modern browsers not only Firefox. For example:

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

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

回答by Endless

My preferred way is canvas.toBlob()

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

But anyhow here is yet another way to convert base64 to a blob using fetch ^^,

但无论如何,这是使用 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})
})

回答by Mimo

Thanks to @Stoive and @vava720 I combined the two in this way, avoiding to use the deprecated BlobBuilder and ArrayBuffer

感谢@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});
}

回答by Chris Bosco

The evolving standard looks to be canvas.toBlob()not canvas.getAsFile() as Mozilla hazarded to guess.

不断发展的标准看起来是canvas.toBlob()而不是 canvas.getAsFile(),因为 Mozilla 冒险猜测。

I don't see any browser yet supporting it :(

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

Thanks for this great thread!

感谢这个伟大的线程!

Also, anyone trying the accepted answer should be careful with BlobBuilder as I'm finding support to be limited (and namespaced):

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

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

Were you using another library's polyfill for BlobBuilder?

您是否为 BlobBuilder 使用了另一个库的 polyfill?

回答by Nafis Ahmad

var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);

can be used without the try catch.

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

Thankx to check_ca. Great work.

感谢check_ca。做得好。

回答by topkara

The original answer by Stoive is easily fixable by changing the last line to accommodate Blob:

通过更改最后一行以适应 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});
}

回答by wilfredonoyola

Thanks! @steovi for this solution.

谢谢!@steovi 用于此解决方案。

I have added support to ES6 version and changed from unescape to dataURI(unescape is deprecated).

我添加了对 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});
}