Convert Data URI to File then append to FormData

2018-12-31 01:20发布

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

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

The Mozilla solution used the following Firefox-only function on 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.

Is it possible? If not, any alternatives?

Thanks.

14条回答
深知你不懂我心
2楼-- · 2018-12-31 02:01

This one works in iOS and 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.

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' });
}
查看更多
琉璃瓶的回忆
3楼-- · 2018-12-31 02:01

Thanks to @Stoive and @vava720 I combined the two in this way, avoiding to use the deprecated BlobBuilder and 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楼-- · 2018-12-31 02:02

My preferred way is canvas.toBlob()

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

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

查看更多
不再属于我。
5楼-- · 2018-12-31 02:02

Thanks! @steovi for this solution.

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

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});
}
查看更多
妖精总统
6楼-- · 2018-12-31 02:05

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

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'});
}
查看更多
闭嘴吧你
7楼-- · 2018-12-31 02:08
var BlobBuilder = (window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder);

can be used without the try catch.

Thankx to check_ca. Great work.

查看更多
登录 后发表回答