Flutter / Dart:将图像转换为 1 位黑白

Flutter / Dart : convert image to 1 bit black and white

我正在编写代码以使用 ESC * 命令打印图像(使用 ESC POS 热敏收据打印机)。

基本上,我正在尝试为 Dart/Flutter 调整 Python 算法。这听起来很简单:打开图像 -> 灰度 -> 反转颜色 -> 转换为黑白 1 位:

im = Image.open(filename)
im = im.convert("L")  # Invert: Only works on 'L' images
im = ImageOps.invert(im)  # Bits are sent with 0 = white, 1 = black in ESC/POS

print(len(im.tobytes())) # len = 576 (image size: 24*24)
im = im.convert("1")  # Pure black and white
print(len(im.tobytes())) # leng = 72 (image size: 24*24)
...

我只有最后一步(1 位转换)有问题。

如您所见,Python 代码(Pillow 库)将减少 im.convert("1") 命令后的字节数,这正是我正确生成 ESC/POS 命令。每个值都在 0 到 255 之间。

如何使用Dart实现?

这是我的代码:

import 'package:image/image.dart';

const String filename = './test_24x24.png';
final Image image = decodeImage(File(filename).readAsBytesSync());

grayscale(image);
invert(image);

源图片:24px * 24px

最后我有一个 grey/inverted 图像,在 RGB 模式下包含 (24 * 24 * 3) 个字节。由于灰度化,所有 r/g/b 值都相等,所以我只能保留一个通道,它给我 (24 * 24) 个字节。

如何实现最后一步im.convert("1")并只保留24 * 3字节?

遍历 576 个灰度字节,将每个字节与阈值进行比较,并将这些位打包成字节(或者更方便的是整数)。

这是一个使用 package:raw 中的辅助函数的示例,但您可以直接内联它,因为它相对简单。

  Uint8List img24x24 = Uint8List(24 * 24); // input 24x24 greyscale bytes [0-255]
  Uint32List img24 = Uint32List(24); // output 24 packed int with 24 b/w bits each
  final threshold = 127; // set the greyscale -> b/w threshold here
  for (var i = 0; i < 24; i++) {
    for (var j = 0; j < 24; j++) {
      img24[i] = transformUint32Bool(
        img24[i],
        24 - j,
        img24x24[i * 24 + j] > threshold, // or < threshold to do the invert in one step
      );
    }
  }