Flutter Bitmap
一个极简的 Flutter 包,用于执行快速的位图操作。重点是提供一个酷炫的位图操作界面。
该包的标准格式是 RGBA32。
Bitmap 使用 Dart FFI 执行诸如对比度、亮度、饱和度和曝光等操作。
目前,格式编码、EXIF 和多帧图像等问题不在该包的考虑范围内。如果您需要这些功能,请查看 image。此处的一些算法深受这个了不起的库的启发。
为什么会有这个包?
我开始使用 dart image 来创建 LetsPicture(一个很棒的应用程序,快来看看吧),但从一开始,我就注意到性能非常糟糕。
Dart image 有自己的 Image 格式,因此在解码、进行一些转换然后显示应用程序中的结果之间,您需要转换图像两次(至少)。
所以这个包就是这样:我们处理 位图(当然),并且我们只关注 Flutter 的用例。
bitmap 从 Flutter 中获得了一些优势
- 通过 ImageStreamListener,框架将所有图像解码为 RGBA32,因此我们可以依赖 Flutter 来完成解码工作;
- Dart FFI:我们将一些函数移植到 C(或 C++),使其速度极快。
- 使用此包,您可以轻松利用 compute(Isolates)等功能,仅对您想要的那些操作进行处理,从而解放 UI 线程,避免繁重的计算。
- Niks 想要创建自己的图像编辑器吗?Niks 和 bitmap 是完成这项工作的绝佳选择。
替代方案
Dart image
如前所述,在 pub 上查看。
Flutter 内置 ColorFilter 类
Flutter 有一个强大的 ColorFilter 类(来自 skia),可用于在画布上绘制内容时进行一些颜色校正。您可以使用矩阵来校正颜色(一些矩阵示例 在此处)。
然而,并非所有颜色变换都可以通过矩阵完成。
基本用法
1. Image 到 Bitmap
一切都围绕着 Bitmap 类。您可以从任何 ImageProvider 获取一个实例。
import 'package:bitmap/bitmap.dart';
Bitmap bitmap = await Bitmap.fromProvider(NetworkImage("http://pudim.com.br/pudim.jpg")); // Notice this is an async operation
您可以从带头部的 Uint8List 创建
import 'package:bitmap/bitmap.dart';
Bitmap bitmap = Bitmap.fromHeadful(imageWidth, imageHeight, theListOfInts); // Not async
或无头
Bitmap bitmap = Bitmap.fromHeadless(imageWidth, imageHeight, theListOfInts); // Not async
这在使用 ByteData 生成的 Uint8List 时很有用。
您甚至可以创建一个空白的
Bitmap bitmap = Bitmap.blank(imageWidth, imageHeight);
这会创建一个黑色、完全透明的位图。
2. 应用一些操作
让我们增加一些对比度
import 'package:bitmap/bitmap.dart';
Bitmap contrastedBitmap = bitmap.apply(BitmapContrast(0.2));;
可以一次添加多个操作
import 'package:bitmap/bitmap.dart';
Bitmap brightBitmap = bitmap.applyBatch([
BitmapBrightness(0.2),
BitmapAdjustColor(
saturation: 1.0
),
]);
3. 显示/绘制/保存输出
您可以从 Bitmap 实例创建两个输出
- 一个没有头部的
Uint8List,只有文件内容(.content属性)。 - 一个带有位图头部的
Uint8List,Flutter 可以解析(.buildHeaded()方法)。
显示
显示图像的最简单方法是获取带头部的位图,然后将其传递给 Image.memory 小部件
// ..
Uint8List headedBitmap = bitmap.buildHeaded();
// ..
child: Image.memory(headedBitmap)
// ..
绘制
Bitmap 类还有一个帮助函数 buildImage,它使用 Flutter 的 decodeImageFromList 来构建一个 dart:ui Image。
使用 Image,您可以 在画布上绘制它(例如,在 CustomPainter 中)。
import 'dart:ui' as ui;
// ..
ui.Image outputImage = await bitmap.buildImage();
canvas.drawImage(outputImage, Offset.zero, ui.Paint());
保存
您还可以将图像保存为 .bmp 文件(使用 .buildHeaded() 方法获取文件内容)。
您还可以查看 image 库,您可以在其中将图像保存为多种格式。
性能改进和 Dart FFI
Dart FFI
从 dart 调用 c(或 c++)函数的能力在提高性能方面可以帮助我们很多。
Isolates
位图上的大多数操作都需要很长时间才能完成。这是因为它们必须遍历位图的每个项。
一个宽度和高度为 400 像素的图像将生成一个包含 640000 个整数的列表。这是一项繁重的计算。
这些可能会很昂贵。因此,您可以在此处使用 Isolates 将所有这些工作从 UI 线程中解放出来。
查看 示例应用程序,其中转换是通过 compute 函数应用的。
重要提示:据观察,在 Flutter 应用的发布模式下使用时,性能会大大提高。
正在使用它的应用程序(目前只有一个)
- Lets Picture - Play 商店 和 源代码。
支持的操作
- 垂直翻转
- 水平翻转
- 旋转
- 调整大小(最近邻插值)
- 对比度
- Brightness
- 饱和度
- 曝光
- 裁剪
待办事项
还有很多工作要做
- [ ] 使用其他插值进行调整大小
- [ ] 设置通道
- [ ] 白平衡
- [ ] 颜色混合
- [ ] 噪点
- [ ] 色调
- [ ] ??? 前途无量