【问题标题】:create data url from fetched image从获取的图像创建数据 url
【发布时间】:2019-10-25 12:12:22
【问题描述】:

TL;DR

我正在尝试fetch 和图像,将其转换为base64,并将数据url 放入imgsrc 属性中,但它不起作用:

async function ajax(id) {
  const tag = document.getElementById(id);
  const path = tag.getAttribute("data-src");
  const response = await fetch(path);
  const blob = await response.blob();
  const base64 = window.btoa(blob);
  const content = `data:image/jpeg;base64,${base64}`;
  tag.setAttribute("src", content);
}

工作的细节以及其他一些方法如下。


我一直在尝试不同的延迟加载方式:

$ mkdir lazy
$ cd lazy
$ wget https://upload.wikimedia.org/wikipedia/commons/7/7a/Lone_Ranger_and_Silver_1956.jpg # any other example image

现在创建一个名为 index.html 的文件,其中包含以下内容:

<script>
  // this works
  function setAttribute(id) {
    const tag = document.getElementById(id);
    const path = tag.getAttribute("data-src");
    tag.setAttribute("src", path);
  }

  // this doesn't work for some reason
  async function ajax(id) {
    const tag = document.getElementById(id);
    const path = tag.getAttribute("data-src");
    const response = await fetch(path);
    const blob = await response.blob();
    const base64 = window.btoa(blob);
    const content = `data:image/jpeg;base64,${base64}`;
    tag.setAttribute("src", content);
  }

  // this works too
  async function works(id) {
    const tag = document.getElementById(id);
    const path = tag.getAttribute("data-src");
    const response = await fetch(path);
    const blob = await response.blob();
    const content = URL.createObjectURL(blob);
    tag.setAttribute("src", content);
  }

</script>
<a href="javascript: setAttribute('example');">set attribute</a><br />
<a href="javascript: ajax('example');">data url</a><br />
<a href="javascript: works('example');">object url</a><br />
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg"></img><br />

并在该文件夹中启动服务器:

$ python -m SimpleHTTPServer # or whichever local webserver

然后当我在 chrome 中查看它时,我得到了这个:

第一个和第三个链接都有效:

但是,中间链接没有:

这三个链接分别对标签做了什么:

作品:

<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="Lone_Ranger_and_Silver_1956.jpg">

不起作用:

<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="data:image/jpeg;base64,W29iamVjdCBCbG9iXQ==">

作品:

<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="blob:http://localhost:8000/736a9e18-c30d-4e39-ac2e-b5246105c178">

非工作示例中的数据 url 看起来也太短了。那我做错了什么?

【问题讨论】:

    标签: javascript html image base64 data-uri


    【解决方案1】:

    感谢@dolpsdw 的建议。 window.btoa 并没有像我想的那样做。如果有人试图做同样的事情,将 blob 读入数据 url 的说明在这里:https://stackoverflow.com/a/18650249/5203563

    我创建了这个适合我的程序的包装器,如下所示:

    (它甚至为您添加了data:image/jpeg;base64, 部分并从blob 中计算出mime 类型)

    
      function readBlob(b) {
        return new Promise(function(resolve, reject) {
          const reader = new FileReader();
    
          reader.onloadend = function() {
            resolve(reader.result);
          };
    
          // TODO: hook up reject to reader.onerror somehow and try it
    
          reader.readAsDataURL(b);
        });
      }
    
      async function ajax(id) {
        const tag = document.getElementById(id);
        const path = tag.getAttribute("data-src");
        const response = await fetch(path);
        const blob = await response.blob();
        // const base64 = window.btoa(blob);
        // const content = `data:image/jpeg;base64,${base64}`;
        const content = await readBlob(blob);
        tag.setAttribute("src", content);
      }
    

    这给了我预期的更长的数据 url:

    【讨论】:

      【解决方案2】:

      当你有内存 blob 只需为该 blob 生成一个 url

      var url = urlCreator.createObjectURL(blob)

      然后用JavaScript新建一个IMG并调用decode方法

      const img = new Image();
      img.src = url;
      img.decode()
      .then(() => {
        document.body.appendChild(img);
      })
      .catch((encodingError) => {
        // Do something with the error.
      })

      也许您还想在加载后撤销 URL

      URL.revokeObjectURL(objectURL)


      关于为什么window.btoa 不起作用,因为它只适用于base64 的字符串。

      了解 blob 到 base64 的转换here。 但是 createObjectURL 是一个更优雅的解决方案。

      【讨论】:

      • 我认为这与我已经为我的第三个示例所做的相同,但我想知道如何使数据 url 工作(我的第二个示例)
      • 似乎btoa 仅将字符串编码为base64。将 blob 编码为 base64 结帐FileReader。但是我认为不处理img以提取base64然后让浏览器重新解码base64然后解码图像更合适。相反,只需使用 createUrl。
      猜你喜欢
      • 1970-01-01
      • 2015-01-29
      • 2021-11-21
      • 2011-06-12
      • 1970-01-01
      • 2012-05-04
      • 2011-08-22
      • 1970-01-01
      相关资源
      最近更新 更多