在网络上显示图像
网络支持标准 Image
小组件以显示图片。但是,由于网络浏览器旨在安全地运行不受信任的代码,因此与移动和桌面平台相比,在图片处理方面存在一定的限制。此页面解释了这些限制并提供了解决方法。
背景
本节总结了 Flutter 和网络中可用的技术,以下解决方案基于这些技术。
Flutter 中的图片
Flutter 提供了 Image
小组件以及低级别的 dart:ui/Image
类来渲染图片。Image
小组件具有足够的功能来满足大多数用例。在需要对图片进行精细控制的高级情况下,可以使用 dart:ui/Image
类。
网络上的图片
网络提供了多种显示图片的方法。以下是其中一些常见方法
每个选项都有其优点和缺点。例如,内置元素很好地融入其他 HTML 元素中,并且它们自动利用浏览器缓存以及内置图像优化和内存管理。它们允许您从任意来源安全地显示图像(有关更多信息,请参阅下面的 CORS 部分)。当图像必须适应使用 <canvas>
元素渲染的其他内容时,drawImage
非常棒。您还可以控制图像大小,并且当 CORS 策略允许时,可以读取图像的像素以进行进一步处理。最后,WebGL 为您提供了对图像的最大程度控制。您不仅可以读取像素并应用自定义图像算法,还可以使用 GLSL 进行硬件加速。
跨源资源共享 (CORS)
CORS 是浏览器用来控制一个站点如何访问另一个站点资源的机制。其设计使得默认情况下,一个网站不允许使用 XHR 或 fetch
向另一个站点发出 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.toImage
和Scene.toImage
。 - 无法访问动画图像中的帧数据(
Codec.getNextFrame
,frameCount
始终为 1,repetitionCount
始终为 0)。 - 不支持
ImageShader
。 - 对可以应用于图像的着色器效果的支持有限。
- 无法控制图像内存(
Image.dispose
无效)。内存由浏览器在后台管理。
CanvasKit 渲染器完全实现了 Flutter 的图像 API。但是,它需要访问图像像素才能执行此操作,因此受 CORS 策略约束。
解决方案
内存中、资产和同源网络图像
如果应用程序在内存中具有编码图像的字节,作为 资产 提供,或存储在提供应用程序的同一服务器上(也称为同源),则无需额外的工作。可以在 HTML 和 CanvasKit 模式下使用 Image.memory
、Image.asset
和 Image.network
显示图像。
跨源图像
HTML 渲染器无需额外配置即可加载跨域图片。
CanvasKit 要求应用获取编码图片的字节。有几种方法可以做到,如下所述。
将图片托管在支持 CORS 的 CDN 中。
通常,内容分发网络 (CDN) 可以配置为自定义允许访问您内容的域。例如,Firebase 网站托管允许在 firebase.json
文件中 指定自定义 Access-Control-Allow-Origin
标头。
无法控制图片服务器?使用 CORS 代理。
如果无法将图片服务器配置为允许来自您应用的 CORS 请求,您仍然可以通过代理请求来加载图片。这要求中间服务器有足够的访问权限来加载图片。
当原始图片服务器公开提供图片,但未配置正确的 CORS 标头时,可以使用此方法。
示例
- 使用 CloudFlare Workers。
- 使用 Firebase Functions。
在平台视图中使用 <img>
。
Flutter 支持使用 HtmlElementView
在应用中嵌入 HTML。使用它创建 <img>
元素以从其他域渲染图片。但是,请记住,这会带来 Flutter 渲染器在网络上中说明的限制。