Flutter Raw Image Provider

一般情况下,考虑网络传输效率,会采用算法来压缩这个数据,故而你会看到有各种各样的图像压缩算法和文件格式。

你可能会问什么情况下会有需要直接去加载一张图的原始rgba数据?

这里举个简单例子:分块加载图片。将图片解码后,分割成一个个矩形区域,每个矩形就有一个 raw rgba 数据,将其交给Image渲染,这样做可以降低一定的GPU 内存压力,减少出现GPU OOM 或黑屏的概率。

要支持 raw rgba ,其实很简单,在 dart:ui包下有个方法decodeImageFromPixels可以直接使用,前提是需要有原始的二进制数据、宽、高。

import 'dart:ui';

Future decodeRawRgba(ByteData bytes, int width, int height) {

final Completer completer = Completer();

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 {

@override

ImageStreamCompleter 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了。

如:

相关推荐
心中有国也有家18 小时前
使用 DevEco Studio 配置 Flutter 鸿蒙签名
学习·flutter·华为·harmonyos
nice先生的狂想曲20 小时前
Stream与StreamController以及对应的使用场景
flutter·客户端
心中有国也有家20 小时前
鸿蒙Flutter开发环境从零搭建教程(Windows/macOS双平台·避坑版)
学习·flutter·华为·harmonyos
心中有国也有家1 天前
Flutter 鸿蒙适配第一步:从 hive 迁移到 hive\_ce
hive·学习·flutter·华为·harmonyos
心中有国也有家1 天前
AtomGit Flutter 鸿蒙客户端:E-Brufen 架构设计
学习·flutter·华为·harmonyos
心中有国也有家1 天前
鸿蒙 Flutter 本地存储实战:Hive CE 从入门到精讲
人工智能·hive·flutter·华为·harmonyos
程序员老刘2 天前
老刘给大家道个歉
flutter·ai编程
binbin_522 天前
Flutter 开发鸿蒙实战:Windows 环境下从 HAP 构建到四 Tab 页面运行
windows·flutter·harmonyos
阳光予你2 天前
Flutter 字体渲染与字重
flutter
恋猫de小郭2 天前
Flutter 开发怎么做 Agent ?从工程实战详细给你解读下
android·前端·flutter