这是一个代码片段,我想做Blob到Base64字符串:

这个注释部分可以工作,当它生成的URL被设置为img src时,它会显示图像:

var blob = items[i].getAsFile();
//var URLObj = window.URL || window.webkitURL;
//var source = URLObj.createObjectURL(blob);
//console.log("image source=" + source);

var reader = new FileReader();
reader.onload = function(event){
console.log(event.target.result)
}; // data url!
var source = reader.readAsBinaryString(blob);

问题在于较低的代码,生成的源变量为空

更新:

有一个更简单的方法来做到这一点与JQuery能够创建Base64字符串从Blob文件如在上面的代码?


当前回答

有一种纯JavaScript方式不依赖于任何堆栈:

const blobToBase64 = blob => {
  const reader = new FileReader();
  reader.readAsDataURL(blob);
  return new Promise(resolve => {
    reader.onloadend = () => {
      resolve(reader.result);
    };
  });
};

为了使用这个helper函数,你应该设置一个回调函数,例如:

blobToBase64(blobData).then(res => {
  // do what you wanna do
  console.log(res); // res is base64 now
});

我在React Native项目上为我的问题写了这个helper函数,我想下载一张图像,然后将它存储为缓存图像:

fetch(imageAddressAsStringValue)
  .then(res => res.blob())
  .then(blobToBase64)
  .then(finalResult => { 
    storeOnMyLocalDatabase(finalResult);
  });

其他回答

这招对我很管用:

var blobToBase64 = function(blob, callback) {
    var reader = new FileReader();
    reader.onload = function() {
        var dataUrl = reader.result;
        var base64 = dataUrl.split(',')[1];
        callback(base64);
    };
    reader.readAsDataURL(blob);
};

async TypeScript变体:

async function blobToBase64Async(blob: Blob): Promise<string> {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onerror = (e) => reject(fileReader.error);
    fileReader.onloadend = (e) => {
      const dataUrl = fileReader.result as string;
      // remove "data:mime/type;base64," prefix from data url
      const base64 = dataUrl.substring(dataUrl.indexOf(',') + 1);
      resolve(base64);
    };
    fileReader.readAsDataURL(blob);
  });
}

示例用法:

async function fetchToBase64Async(url: string, init?: RequestInit): Promise<string> {
  try {
    const response = await fetch(url, init);
    if (!response.ok) {
      const responseText = await response.text();
      throw new Error("server status: " + response.status + "\n" + "server response:" + "\n" + responseText);
    }
    const blob = await response.blob();
    const base64 = await blobToBase64Async(blob);
    return base64;
  } catch (e) {
    throw new Error("failed to fetch: " + url + "\n" + "caused by: " + e);
  }
}

async function demoUsage() {
  const base64 = await fetchToBase64Async("https://httpstat.us/200", {
    method: "POST",
    headers: {
      "Accept": "*/*",
      "Authorization": "Bearer ...",
    }
  });
  console.log(base64);
}

注:

我不明白为什么有些答案使用load而不是loadend事件 我不明白为什么有些答案在设置事件处理程序之前调用readAsDataURL

另一种方法是使用一个简单的包装器来包装返回Observable的FileReader(代码片段在TypeScript中):

  function toBase64(blob: Blob): Observable<string> {
    const reader = new FileReader();
    reader.readAsDataURL(blob);
    return fromEvent(reader, 'load')
      .pipe(map(() => (reader.result as string).split(',')[1]));
  }

用法:

toBase64(blob).subscribe(base64 => console.log(base64));

也许我遗漏了什么,但是

let encoded = btoa(await myblob.text());

... 是所有你需要做的编码一个Blob的数据到base64。参见Blob.text()和btoa()。

或者如果你想把所有事情都当做承诺

let encode = myblob.text().then(btoa);

PS:解码回一个Blob: new Blob([atob(encoded)])

function bufferToBinaryString(arrayBuffer){
    return String.fromCharCode(...new Uint8Array(arrayBuffer));
}
(async () => console.log(btoa(bufferToBinaryString(await new Response(blob).arrayBuffer()))))();

or

function bufferToBinaryString(arrayBuffer){
    return String.fromCharCode(...new Uint8Array(arrayBuffer));
}
new Response(blob).arrayBuffer().then(arr_buf => console.log(btoa(bufferToBinaryString(arr_buf)))))

查看Response的构造函数,你可以将[blob,缓冲区源表单数据,可读流等]转换为Response,然后可以通过async方法/回调转换为[json,文本,数组缓冲区,blob]。

编辑:正如@Ralph所提到的,将所有内容转换为utf-8字符串会导致问题(不幸的是响应API没有提供转换为二进制字符串的方法),因此使用数组缓冲区作为中间,这需要更多的两个步骤(将其转换为字节数组,然后转换为二进制字符串),如果你坚持使用本机btoa方法。