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

如:

相关推荐
小白学鸿蒙8 小时前
使用Flutter从0到1构建OpenHarmony/HarmonyOS应用
flutter·华为·harmonyos
不爱吃糖的程序媛10 小时前
Flutter OH 框架介绍
flutter
ljt272496066111 小时前
Flutter笔记--加水印
笔记·flutter
恋猫de小郭13 小时前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
ljt27249606611 天前
Flutter笔记--事件处理
笔记·flutter
Feng-licong1 天前
告别手写 UI:当 Google Stitch 遇上 Flutter,2026 年的“Vibe Coding”开发流
flutter·ui
不爱吃糖的程序媛2 天前
Flutter OH Engine构建指导
flutter
小蜜蜂嗡嗡2 天前
flutter实现付费解锁内容的遮挡
android·flutter
tangweiguo030519872 天前
Flutter iOS 调试利器:idevicesyslog 从入门到精通
flutter
tangweiguo030519872 天前
Flutter 异常捕获与处理:从入门到生产实践
flutter