1

当我像这样嵌入时,我很难理解为什么来自谷歌驱动器(私人或共享给公共)的图像会毫无问题地显示在谷歌网站上:

<!DOCTYPE html>
<html>

<body>
    <img src="https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc" width="500">
</body>

</html>

在这里,谷歌驱动器上的图像存储在https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc并公开共享。图像的文件 ID 是0B6wwyazyzml-OGQ3VUo0Z2thdmc.

由于图像显示,这意味着从谷歌网站上的谷歌驱动器读取图像是可能的。

但是当我使用(Vega-lite)生成一个 html 时Altair,使用以下最少的代码:

import altair as alt
import pandas as pd
source = pd.DataFrame({"img": ["https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc",]})
chart=alt.Chart(source).mark_image(width=100,height=100,).encode(x=alt.value(0),y=alt.value(0),url='img')
chart.save('test/gdrive.html')

html的内容:

<!DOCTYPE html>
<html>
<head>
  <style>
    .error {
        color: red;
    }
  </style>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm//vega@5"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm//vega-lite@4.8.1"></script>
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm//vega-embed@6"></script>
</head>
<body>
  <div id="vis"></div>
  <script>
    (function(vegaEmbed) {
      var spec = {"config": {"view": {"continuousWidth": 400, "continuousHeight": 300}}, "data": {"name": "data-f41fe47a6561a1d8f01ad1fd7b81dffd"}, "mark": {"type": "image", "height": 100, "width": 100}, "encoding": {"url": {"type": "nominal", "field": "img"}, "x": {"value": 0}, "y": {"value": 0}}, "$schema": "https://vega.github.io/schema/vega-lite/v4.8.1.json", "datasets": {"data-f41fe47a6561a1d8f01ad1fd7b81dffd": [{"img": "https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc"}]}};
      var embedOpt = {"mode": "vega-lite"};

      function showError(el, error){
          el.innerHTML = ('<div class="error" style="color:red;">'
                          + '<p>JavaScript Error: ' + error.message + '</p>'
                          + "<p>This usually means there's a typo in your chart specification. "
                          + "See the javascript console for the full traceback.</p>"
                          + '</div>');
          throw error;
      }
      const el = document.getElementById('vis');
      vegaEmbed("#vis", spec, embedOpt)
        .catch(error => showError(el, error));
    })(vegaEmbed);

  </script>
</body>
</html>

图像未显示。

在此处输入图像描述

我想知道为什么会这样。

为了快速诊断,我查看了 vega-editor 的 LOGS 选项卡。在那里我看到了这个错误:[Error] Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.

4

1 回答 1

0

简短的回答:由于您的浏览器的跨域安全功能,这不起作用,唯一的解决方法是将图像托管在其他地方。

长版:如果您在查看图表时打开 Javascript 控制台日志,您会看到如下内容:

Access to image at 'https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

这表明在您的页面上运行的脚本正在尝试访问故意禁止自己从脚本访问的资源。如果不更改 Google Drive 内容上的 CORS 标头,就无法解决此问题,而且 Google 之所以无法做到这一点是有充分理由的:如果标头设置得更宽松,那么在您访问的任何网页上运行的恶意 javascript 都可能以编程方式从您的 Google 驱动器中抓取内容。

因此,您必须在其他地方托管您的图像。

一个简单的替代方法可能是下载图像并将其托管在您托管图表代码的同一服务器上;例如

from urllib.request import urlretrieve
urlretrieve("https://drive.google.com/uc?export=view&id=0B6wwyazyzml-OGQ3VUo0Z2thdmc", "test/img.jpg")

import altair as alt
import pandas as pd
source = pd.DataFrame({"img": ["img.jpg"]})
chart=alt.Chart(source).mark_image(width=100,height=100,).encode(x=alt.value(0),y=alt.value(0),url='img')
chart.save('test/chart.html')
于 2021-12-13T14:14:39.750 回答