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++),使其速度极快。
  • 使用此包,您可以轻松利用 computeIsolates)等功能,仅对您想要的那些操作进行处理,从而解放 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 库,您可以在其中将图像保存为多种格式。

如何使用 Flutter 保存文件?

性能改进和 Dart FFI

Dart FFI

从 dart 调用 c(或 c++)函数的能力在提高性能方面可以帮助我们很多。

Isolates

位图上的大多数操作都需要很长时间才能完成。这是因为它们必须遍历位图的每个项。
一个宽度和高度为 400 像素的图像将生成一个包含 640000 个整数的列表。这是一项繁重的计算。
这些可能会很昂贵。因此,您可以在此处使用 Isolates 将所有这些工作从 UI 线程中解放出来。

查看 示例应用程序,其中转换是通过 compute 函数应用的。

重要提示:据观察,在 Flutter 应用的发布模式下使用时,性能会大大提高。

正在使用它的应用程序(目前只有一个)

支持的操作

  • 垂直翻转
  • 水平翻转
  • 旋转
  • 调整大小(最近邻插值)
  • 对比度
  • Brightness
  • 饱和度
  • 曝光
  • 裁剪

待办事项

还有很多工作要做

  • [ ] 使用其他插值进行调整大小
  • [ ] 设置通道
  • [ ] 白平衡
  • [ ] 颜色混合
  • [ ] 噪点
  • [ ] 色调
  • [ ] ??? 前途无量

GitHub

https://github.com/renancaraujo/bitmap