【问题标题】:Blob from DataURL?来自 DataURL 的 Blob?
【发布时间】:2012-08-23 12:44:04
【问题描述】:

使用FileReaderreadAsDataURL() 我可以将任意数据转换为数据URL。有没有办法使用内置浏览器 API 将数据 URL 转换回 Blob 实例?

【问题讨论】:

    标签: javascript fileapi


    【解决方案1】:

    使用

    FileReader.readAsArrayBuffer(Blob|File)
    

    而不是

    FileReader.readAsDataURL(Blob|File)
    

    【讨论】:

    • 我必须将它作为 DataURL 无限期地存储在 localStorage 中,因此使用替代 ArrayBuffer 路径将不起作用。
    【解决方案2】:

    用户 Matt 在一年前提出了以下代码 (How to convert dataURL to file object in javascript?),可能会对您有所帮助

    编辑:正如一些评论者所报告的,BlobBuilder 已在一段时间前被弃用。这是更新后的代码:

    function dataURItoBlob(dataURI) {
      // convert base64 to raw binary data held in a string
      // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
      var byteString = atob(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);
    
      // create a view into the buffer
      var ia = new Uint8Array(ab);
    
      // set the bytes of the buffer to the correct values
      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([ab], {type: mimeString});
      return blob;
    
    }
    

    【讨论】:

    • 重复的拆分似乎有点浪费,因为这可能是一个非常大的字符串。
    • 变量“ia”的作用是什么 - 它分配了一个值,但从未用于形成 blob。为什么?
    • Blaze,Ward:ia 是缓冲区的视图。因此,当您在 ia 中设置每个字节时,它正在写入缓冲区。如果没有 ia 循环,缓冲区将完全为空。
    • 如何找到 SO answer #6850276 ?
    • @BT :我猜stackoverflow.com/a/30407840/271577 是有意的(注意重定向的 URL 包括“#6850276”)。
    【解决方案3】:
    dataURItoBlob : function(dataURI, dataTYPE) {
            var binary = atob(dataURI.split(',')[1]), array = [];
            for(var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i));
            return new Blob([new Uint8Array(array)], {type: dataTYPE});
        }
    

    输入dataURI为Data URL,dataTYPE为文件类型,然后输出blob对象

    【讨论】:

    【解决方案4】:

    尝试:

    function dataURItoBlob(dataURI) {
        if(typeof dataURI !== 'string'){
            throw new Error('Invalid argument: dataURI must be a string');
        }
        dataURI = dataURI.split(',');
        var type = dataURI[0].split(':')[1].split(';')[0],
            byteString = atob(dataURI[1]),
            byteStringLength = byteString.length,
            arrayBuffer = new ArrayBuffer(byteStringLength),
            intArray = new Uint8Array(arrayBuffer);
        for (var i = 0; i < byteStringLength; i++) {
            intArray[i] = byteString.charCodeAt(i);
        }
        return new Blob([intArray], {
            type: type
        });
    }
    

    【讨论】:

      【解决方案5】:

      使用我的代码将 dataURI 转换为 blob。 它比其他的更简单、更干净。

      function dataURItoBlob(dataURI) {
          var arr = dataURI.split(','), mime = arr[0].match(/:(.*?);/)[1];
          return new Blob([atob(arr[1])], {type:mime});
      }
      

      【讨论】:

      • 您能解释一下为什么您的代码不需要转换为 int 数组,而其他人都在这样做吗?
      • 参见 MDN 上的Blob() constructor
      • @Rikard 你是什么意思?它不会影响任何图像
      • 这只适用于一些基本的东西。您需要首先对其进行转义 + decodeURIComponent 以支持大多数内容编码read this。这就是为什么其他人将字符串转换为 int 数组以避免缓慢/饥饿的 decodeURIComponent/atob 函数调用并直接转换为字节
      【解决方案6】:

      基于 XHR 的方法。

      function dataURLtoBlob( dataUrl, callback )
      {
          var req = new XMLHttpRequest;
      
          req.open( 'GET', dataUrl );
          req.responseType = 'arraybuffer'; // Can't use blob directly because of https://crbug.com/412752
      
          req.onload = function fileLoaded(e)
          {
              // If you require the blob to have correct mime type
              var mime = this.getResponseHeader('content-type');
      
              callback( new Blob([this.response], {type:mime}) );
          };
      
          req.send();
      }
      
      dataURLtoBlob( 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==', function( blob )
      {
          console.log( blob );
      });
      

      【讨论】:

      • 看来,这是目前最好的办法。谢谢!
      • 无法在 Safari 中工作 - 如果页面从 HTTPS 加载,它将引发跨域错误。
      • 问题是来自DataURL的Blob?
      【解决方案7】:

      类似于@Adria 方法,但使用 Fetch api 并且更小 [caniuse?]
      不必考虑 mimetype,因为 blob 响应类型开箱即用

      警告:可能违反内容安全政策 (CSP)
      ...如果你使用那些东西

      var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
      
      fetch(url)
      .then(res => res.blob())
      .then(blob => console.log(blob))

      不要认为你可以在不使用 lib 的情况下做得比这更小

      【讨论】:

      • 非常优雅。不幸的是,edge 13 和 safari 不支持“获取”。
      • edge 14 和 safari 10.1 支持
      • 异步版本:const blob = await (await fetch(url)).blob();
      • 效果很好,但是从服务器读取文件时没有扩展名。有什么想法吗?
      • fetch 的更大问题是它强制使用异步 API。
      【解决方案8】:

      由于这些答案都不支持 base64 和非 base64 数据 URL,因此这是基于 vuamitom 已删除答案的答案:

      // from https://stackoverflow.com/questions/37135417/download-canvas-as-png-in-fabric-js-giving-network-error/
      var dataURLtoBlob = exports.dataURLtoBlob = function(dataurl) {
          var parts = dataurl.split(','), mime = parts[0].match(/:(.*?);/)[1]
          if(parts[0].indexOf('base64') !== -1) {
              var bstr = atob(parts[1]), n = bstr.length, u8arr = new Uint8Array(n)
              while(n--){
                  u8arr[n] = bstr.charCodeAt(n)
              }
      
              return new Blob([u8arr], {type:mime})
          } else {
              var raw = decodeURIComponent(parts[1])
              return new Blob([raw], {type: mime})
          }
      }
      

      注意:我不确定是否有可能需要以不同方式处理的 other dataURL mime 类型。但是,如果你发现了,请告诉我!可能 dataURL 可以简单地具有他们想要的任何格式,在这种情况下,您可以为您的特定用例找到正确的代码。

      【讨论】:

        【解决方案9】:

        使用XHR API 创建一个blob:

        function dataURLtoBlob( dataUrl, callback )
        {
            var req = new XMLHttpRequest;
        
            req.open( 'GET', dataUrl );
            req.responseType = 'blob';
        
            req.onload = function fileLoaded(e)
            {
                callback(this.response);
            };
        
            req.send();
        }
        
        var dataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
        
        dataURLtoBlob(dataURI , function( blob )
        {
            console.log( blob );
        });

        【讨论】:

        • Chrome 抛出 net::ERR_INVALID_URL
        【解决方案10】:

        modern browsers 中,可以使用 Christian d'Heureuse 在评论中建议的 one liner:

        const blob = await (await fetch(dataURI)).blob(); 
        

        【讨论】:

        • 使用此方法的一个警告是,如果您的应用程序有任何内容安全策略 (CSP),这可能会违反您的内容安全策略 (CSP)。
        【解决方案11】:

        如果您需要在 Google Apps 脚本的服务器端工作,请尝试:

        function dataURItoBlob(dataURI) {
          // convert base64 to Byte[]
          // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
          var data = Utilities.base64Decode(dataURI.split(',')[1]);
        
          // separate out the mime component
          var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
        
          var blob = Utilities.newBlob(data);
          blob.setContentType(mimeString);
          return blob;
        }
        

        【讨论】:

          猜你喜欢
          • 2014-06-02
          • 2021-05-04
          • 2013-02-28
          • 2021-04-12
          • 2020-01-23
          • 1970-01-01
          • 1970-01-01
          • 2014-11-02
          • 1970-01-01
          相关资源
          最近更新 更多