在 Web 中展示圖片
Web 支援使用標準的 Image
元件來展示圖片。然而,Web 瀏覽器和手機以及桌面平台相比,在處理圖片上會有一定的侷限性,因為它需要以安全的方式執行未信任的程式碼。本頁面內容解釋了這些限制,並提供一些解決方法。
背景
本節概括了 Flutter Web 中可用的技術,下述的解決方案都基於此。
Images in Flutter
Flutter 提供了 Image
元件以及底層的 dart:ui/Image
類來渲染圖片。
Image
元件的功能足夠滿足大部分使用場景。
dart:ui/Image
類可用於需要精細控制圖片的場景。
Web 中的圖片
Web 提供了多種展示圖片的方式,下面是幾種常見的:
每種方式都有各自的優缺點。例如:內建的元素和其他 HTML 元素完美契合,並且自帶瀏覽器快取、內建圖片最佳化和記憶體管理的優勢。這使得你可以安全地展示任意來源的圖片(超越了下節中的 CORS)。當圖片必須和 <canvas>
元素中渲染的其他內容適配時,drawImage
更合適。當 CORS 政策允許時,你也可以獲取圖片尺寸的控制權,讀取畫素資訊用於進一步處理。最後,WebGL 給予了你最大限度的圖片控制權。你不僅可以讀取畫素資訊、應用自訂的圖片演算法,還可以使用 GLSL 實現硬體加速。
跨域資源共享 (CORS)
CORS 是一種瀏覽器用來控制一個站點如何獲取另一個站點的資源的機制。預設情況下,一個網站不允許使用 XHR 或者 fetch
的方式向另一個站點發送 HTTP 請求。這樣可以阻止另一個站點代表使用者執行指令碼,以及無需許可權就可以獲取另一個站點的資源。
當使用 <img>
、<picture>
或者 <canvas>
時,如果瀏覽器發現圖片來源於另一個站點,且 CORS 政策不允許存取資料時,瀏覽器會自動阻止資訊的存取許可權。
WebGL 需要存取圖片資訊以用於渲染圖片。因此要想使用 WebGL 渲染圖片,該圖片的來源服務所在的域名必須配置有效且可用的 CORS 策略。
Web 中的 Flutter 渲染器
Flutter 在 Web 中提供了兩種可供選擇的渲染器:
-
HTML:該渲染器使用了 HTML、CSS、Canvas 2D 和 SVG 組合的方式渲染 UI。使用
<img>
元素渲染圖片。 -
CanvasKit:該渲染器使用了 WebGL 渲染 UI,因此需要存取圖片的畫素資訊。
因為 HTML 渲染器使用了 <img>
元素,所以可以展示任意來源的圖片。但是,這也給你帶來了以下限制:
-
對
Image.toByteData
的支援有限。 -
不支援
OffsetLayer.toImage
和Scene.toImage
。 -
無法獲取動畫中的幀資訊(
Codec.getNextFrame
,frameCount
永遠為 1,repetitionCount
永遠為 0)。 -
不支援
ImageShader
。 -
應用於圖片的著色器效果的支援有限。
-
不可控制圖片記憶體(
Image.dispose
無效)。記憶體由瀏覽器自行控制。
CanvasKit 完全實現了 Flutter 中的圖片 API。但它需要存取圖片的畫素資訊,因此受制於 CORS 政策。
解決方案
記憶體、asset 和同源網路圖片
如果圖片在應用記憶體中有編碼後的位元組資訊、或者以 asset 的方式提供、或者和應用儲存在同一伺服器上(也就是同源),則不需要做額外工作。圖片既可以在 HTML 也可以在 CanvasKit 模式下,使用 Image.memory
、
Image.asset
和 Image.network
來展示。
跨域圖片
HTML 渲染器可以載入跨域圖片,無需額外配置。
CanvasKit 需要應用獲取編碼後的圖片的位元組資訊。有多種獲取方式,如下文所述。
在支援 CORS 的 CDN 中部署你的圖片
通常,可以配置內容分發網路 (CDN) 來自訂哪些域名可以存取你的內容。例如:Firebase 站點託管允許在 firebase.json
檔案中,
指定一個自訂的 Access-Control-Allow-Origin
頭。
沒有圖片伺服器控制權?使用一個 CORS 代理
如果無法從你的應用層面去配置圖片伺服器的 CORS,你依然可以透過另一個伺服器代理請求,從而載入圖片。這要求中轉伺服器對圖片載入有充分的存取權。
此方法適用於源圖片伺服器公開提供了圖片,卻沒有正確配置 CORS 頭的情況。
例子:
<img>
在平臺視圖中使用 Flutter 支援在應用中使用 HtmlElementView
嵌入 HTML。透過它可以建立一個 <img>
元素來渲染另一個域名的圖片。但是,一定要記住,此方法也附帶了「Web 中的 Flutter 渲染器」一節中提到的限制。
就目前而言,在 CanvasKit 渲染器中過多地使用 HTML 元素,可能較為影響效能。如果圖片和非圖片內容交替出現,
Flutter 需要在 <img>
元素之間建立額外的 WebGL 上下文。如果你的應用需要一次性在同一螢幕中展示大量的圖片,請考慮使用 HTML 渲染器替代 CanvasKit。