在网络上显示图像

网络支持标准 Image 小组件以显示图片。但是,由于网络浏览器旨在安全地运行不受信任的代码,因此与移动和桌面平台相比,在图片处理方面存在一定的限制。此页面解释了这些限制并提供了解决方法。

背景

本节总结了 Flutter 和网络中可用的技术,以下解决方案基于这些技术。

Flutter 中的图片

Flutter 提供了 Image 小组件以及低级别的 dart:ui/Image 类来渲染图片。Image 小组件具有足够的功能来满足大多数用例。在需要对图片进行精细控制的高级情况下,可以使用 dart:ui/Image 类。

网络上的图片

网络提供了多种显示图片的方法。以下是其中一些常见方法

每个选项都有其优点和缺点。例如,内置元素很好地融入其他 HTML 元素中,并且它们自动利用浏览器缓存以及内置图像优化和内存管理。它们允许您从任意来源安全地显示图像(有关更多信息,请参阅下面的 CORS 部分)。当图像必须适应使用 <canvas> 元素渲染的其他内容时,drawImage 非常棒。您还可以控制图像大小,并且当 CORS 策略允许时,可以读取图像的像素以进行进一步处理。最后,WebGL 为您提供了对图像的最大程度控制。您不仅可以读取像素并应用自定义图像算法,还可以使用 GLSL 进行硬件加速。

跨源资源共享 (CORS)

CORS 是浏览器用来控制一个站点如何访问另一个站点资源的机制。其设计使得默认情况下,一个网站不允许使用 XHRfetch 向另一个站点发出 HTTP 请求。这可以防止另一个站点上的脚本代表用户执行操作,并在未经许可的情况下访问另一个站点的资源。

使用 <img><picture><canvas> 时,浏览器在知道图像来自另一个网站且 CORS 策略不允许访问数据时,会自动阻止对像素的访问。

WebGL 需要访问图像数据才能渲染图像。因此,要使用 WebGL 渲染的图像只能来自已配置 CORS 策略以与提供应用程序的域配合使用的服务器。

Web 上的 Flutter 渲染器

Flutter 在 Web 上提供两种渲染器供选择

CanvasKit
使用 WebGL 渲染 UI,因此需要访问图像的像素。
HTML
使用 HTML、CSS、Canvas 2D 和 SVG 的组合来渲染 UI。它使用 <img> 元素来渲染图像。

由于 HTML 渲染器使用 <img> 元素,因此它可以显示来自任意来源的图像。但是,这会对你可以对它们执行的操作施加以下限制

  • Image.toByteData 的支持有限。
  • 不支持 OffsetLayer.toImageScene.toImage
  • 无法访问动画图像中的帧数据(Codec.getNextFrameframeCount 始终为 1,repetitionCount 始终为 0)。
  • 不支持 ImageShader
  • 对可以应用于图像的着色器效果的支持有限。
  • 无法控制图像内存(Image.dispose 无效)。内存由浏览器在后台管理。

CanvasKit 渲染器完全实现了 Flutter 的图像 API。但是,它需要访问图像像素才能执行此操作,因此受 CORS 策略约束。

解决方案

内存中、资产和同源网络图像

如果应用程序在内存中具有编码图像的字节,作为 资产 提供,或存储在提供应用程序的同一服务器上(也称为同源),则无需额外的工作。可以在 HTML 和 CanvasKit 模式下使用 Image.memoryImage.assetImage.network 显示图像。

跨源图像

HTML 渲染器无需额外配置即可加载跨域图片。

CanvasKit 要求应用获取编码图片的字节。有几种方法可以做到,如下所述。

将图片托管在支持 CORS 的 CDN 中。

通常,内容分发网络 (CDN) 可以配置为自定义允许访问您内容的域。例如,Firebase 网站托管允许在 firebase.json 文件中 指定自定义 Access-Control-Allow-Origin 标头。

无法控制图片服务器?使用 CORS 代理。

如果无法将图片服务器配置为允许来自您应用的 CORS 请求,您仍然可以通过代理请求来加载图片。这要求中间服务器有足够的访问权限来加载图片。

当原始图片服务器公开提供图片,但未配置正确的 CORS 标头时,可以使用此方法。

示例

在平台视图中使用 <img>

Flutter 支持使用 HtmlElementView 在应用中嵌入 HTML。使用它创建 <img> 元素以从其他域渲染图片。但是,请记住,这会带来 Flutter 渲染器在网络上中说明的限制。