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相关推荐

  1. Flutter中的Provider(八)-多个Provider-MultiProvider

    在实际开发中,常常需要多个Provider一起使用,针对这种情况可以使用重复嵌套的方式,例如: Provider<Something>(create: (_) => Somethin ...

  2. Flutter中使用Provider

    前言.相当于全局变量,只要一改数据,引用到的地方就会自动刷新UI. 1.导入:provider: 5.0.0 2.写model类 class User extends ChangeNotifier{S ...

  3. Flutter Provider 异步通信、Provider状态管理

    题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精. Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日提醒 随时随记 每日积累 随心而过 [x2]各种系列的视频教程 ...

  4. Flutter主流状态管理框架provider、bloc、redux对比

    为什么需要状态管理 provider bloc redux 对比 总结 为什么需要状态管理 在了解和进行Flutter状态管理框架对比之前呢,我们先来问自己一个问题:为什么需要状态管理? 如果我们的应 ...

  5. Flutter基础笔记

    目录 List里面常用的属性和方法: Set Map forEach,map, where,any,every extends抽象类 和 implements Flutter环境搭建 入口文件.入口方 ...

  6. Flutter状态管理1-ChangeNotifierProvider的使用

    关于Flutter中的状态管理,可以参考官网的介绍:Simple app state management 中文网的介绍:简单的应用状态管理 Flutter 官方的两个sample: provider ...

  7. 编写第一个flutter的安卓app

    目录 1 创建flutter应用 2 使用vscode编写flutter应用 2.1 vscode连接夜神模拟器 2.2 运行flutter应用 2.3 flutter应用目录讲解 1 创建flutt ...

  8. 一纸读懂另类数据 | 未央研究

    一纸读懂另类数据 | 未央研究 未央研究 清华大学五道口金融学院 今天 什么是另类数据? 1.定义 另类数据(Alternative Data)是不同于传统的交易所披露.公司公告披露的新数据,是有利于 ...

  9. 策略死守“传统数据”招招落于人后?-也许您需要另类数据

    在大数据技术突飞猛进的时代,传统的数据公布和使用方式(比如坐等公司财报或静候研究员实地调研)已经愈发显得跟不上节奏,投资者们开始发掘新的"数据金矿"--另类数据. 那么,什么是&q ...

最新文章

  1. 这个新方法,竟然能检测 Python 代码的好坏!
  2. Linux内核探讨-- 第四章
  3. Python的global语句
  4. GVRP的应用—华为拓扑
  5. php 伪静态 500错误,Apache开启伪静态后报500错误.
  6. Anaconda日志
  7. “ 紫手环的力量 ” :我想,美好的生活应该是自已造就的...
  8. Swift @escaping @noescape
  9. [Email] 收发邮件的协议 : IMAP and SMTP , POP3 and SMTP
  10. ORA-01157、01110问题解决
  11. 服务器监控之 ping 监控
  12. 浅谈Java新手入门书籍选择
  13. php jmail实例,Jmail发邮件的例子
  14. mac怎么无线打印机连接到服务器,Mac如何连接打印机-Mac连接打印机教程 - 河东软件园...
  15. 【JavaScript】 基础知识
  16. 国家旅游局发布厕所大数据报告,上厕所最容易的城市你一定想不到
  17. 【HTML5】Web前端——第三课:HTML5 表单相关元素和属性
  18. 开源商城WSTMart支付开发研究[转]
  19. Java远程屏幕监控案例
  20. 使用python简单实现K核苷酸频率(KNF,k-nucleotide frequencies)或K-mer频率

热门文章

  1. pmp知识点详解-项目大牛整理_PMP核心知识点第六章:项目进度管理(3)
  2. signature=78718ebfda6f8d955fae3e9c9c284f5d,SKI SAFETY BINDING WITH SWIVELLING SOLE PLATE
  3. python怎么网络通信_深入Python中的网络通信
  4. Windows 全部调试符号包下载
  5. babylonjs 分部加载模型_如何使用BabylonJS加载OBJ或STL模型
  6. window环境编译在linux环境运行的golang程序
  7. 如何写一个能被手机打开的C语言小程序,如何用C语言中一些简单的语句做一个小程序,能够输入一个字符就会弹出一句话...
  8. b+tree数据结构可视化_数据结构: B+Tree及其应用
  9. 如何将浮点型准确地转换成字符串
  10. android 文件并发读写,Android下,rxJava+retrofit 并发上传文件和串行上传文件的效率为什么差不多?...