日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Flutter Raw Image Provider

發布時間:2025/3/19 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Flutter Raw Image Provider 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Flutter 中的 Image Widget 內置支持 file、network、memory三種形式的文件。
但這幾種都只支持常規的經過壓縮后的圖片文件或二進制數據,如jpg、png、webp文件等。并沒有支持原始的rgba 二進制數據。
這里說的原始二進制數據是指圖像的每個像素的色彩值所組成的字節數組。一張圖有寬x高個像素點,一個像素點的色彩值用32bit來存儲,分為4個通道,每個通道各占用8bit,分別為紅、綠、藍、透明度(RGBA),這個數組就是每個像素點色彩值的集合,dart 中一般用Uint8List。

一般情況下,考慮網絡傳輸效率,會采用算法來壓縮這個數據,故而你會看到有各種各樣的圖像壓縮算法和文件格式。

你可能會問什么情況下會有需要直接去加載一張圖的原始rgba數據?

這里舉個簡單例子:分塊加載圖片。將圖片解碼后,分割成一個個矩形區域,每個矩形就有一個 raw rgba 數據,將其交給Image渲染,這樣做可以降低一定的GPU 內存壓力,減少出現GPU OOM 或黑屏的概率。

要支持 raw rgba ,其實很簡單,在 dart:ui包下有個方法decodeImageFromPixels可以直接使用,前提是需要有原始的二進制數據、寬、高。

import 'dart:ui';Future<Image> decodeRawRgba(ByteData bytes, int width, int height) {final Completer<Image> completer = Completer<Image>();decodeImageFromPixels(bytes.buffer.asUint8List(),width,height,PixelFormat.rgba8888,completer.complete,);return completer.future; }

有了這個 Image(dart:ui)對象就可以交給 RawImage Widget 來加載了。但RawImage太過于底層了,能不能只用 Image Widget呢?因為需要復用 LoadingBuilder這些邏輯。

當然可以。查看一下 Image Widget 的構造函數就知道,我們需要一個 ImageProvider,那么問題進一步簡化到如何寫一個ImageProvider 支持 raw rgba 數據。

實現一個 ImageProvider,我們需要實現 load這個關鍵方法。以MemoryImage為例:

class MemoryImage extends ImageProvider<MemoryImage> {@overrideImageStreamCompleter load(MemoryImage key, DecoderCallback decode) {return MultiFrameImageStreamCompleter(codec: _loadAsync(key, decode),scale: key.scale,debugLabel: 'MemoryImage(${describeIdentity(key.bytes)})',);}Future<ui.Codec> _loadAsync(MemoryImage key, DecoderCallback decode) {return decode(bytes);} }

很顯然,我們需要想一個方法構造出raw rgba 數據的 Codec。

其實秘密就在 decodeImageFromPixels這個方法實現里:

void decodeImageFromPixels(Uint8List pixels,int width,int height,PixelFormat format,ImageDecoderCallback callback, {int? rowBytes,int? targetWidth,int? targetHeight,bool allowUpscaling = true, }) {if (targetWidth != null) {assert(allowUpscaling || targetWidth <= width);}if (targetHeight != null) {assert(allowUpscaling || targetHeight <= height);}ImmutableBuffer.fromUint8List(pixels).then((ImmutableBuffer buffer) {final ImageDescriptor descriptor = ImageDescriptor.raw(buffer,width: width,height: height,rowBytes: rowBytes,pixelFormat: format,);if (!allowUpscaling) {if (targetWidth != null && targetWidth! > descriptor.width) {targetWidth = descriptor.width;}if (targetHeight != null && targetHeight! > descriptor.height) {targetHeight = descriptor.height;}}descriptor.instantiateCodec(targetWidth: targetWidth,targetHeight: targetHeight,).then((Codec codec) => codec.getNextFrame()).then((FrameInfo frameInfo) => callback(frameInfo.image));}); }

先從數據構造出ImageDescriptor,再把descriptor.instantiateCodec()這一步抽出來就可以獲取 raw rgba 數據的 Codec,進而實現一個自己的RawImageProvider了。

如:

class RawImageProvider extends ImageProvider<_RawImageKey> {final RawImageData image;/// see [ui.decodeImageFromPixels]Future<ui.Codec> _loadAsync(_RawImageKey key) async {var buffer = await ui.ImmutableBuffer.fromUint8List(image.pixels);final descriptor = ui.ImageDescriptor.raw(buffer,width: image.width,height: image.height,pixelFormat: image.pixelFormat,);return descriptor.instantiateCodec(targetWidth: targetWidth, targetHeight: targetHeight);}

如果你恰好也有這個需要,可以直接添加 pub 依賴

dependencies:raw_image_provider: ^0.1.0

完。

總結

以上是生活随笔為你收集整理的Flutter Raw Image Provider的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。