在 Flutter 中,如何在不使用 Image 包的情况下逐个像素地操作 ui.Image?

In Flutter, how to manipulate pixel by pixel of an ui.Image without using the Image package?

在 Flutter 中,在不使用 Image 包的情况下更改具有 ui.Image 类型的图像像素数据的正确方法是什么?我可以使用 Image 包更新像素,但我不想多次转换图像。所以我试图探索更新 Uint8List 数据的可能性。下面是代码片段。但是,当我尝试使用操纵的 Uint8List 更新图像时,出现“异常:图像数据无效”。想知道我做错了什么吗?感谢任何反馈。

int clamp(int x, int a, int b) {
    return (x < a)
        ? a
        : (x > b)
            ? b
            : x;
  }

int getColorY(int a, int r, int g, int b ) =>
      (clamp(a, 0, 255) << 24) |
      (clamp(r, 0, 255) << 16) |
      (clamp(g, 0, 255) << 8) |
      (clamp(b, 0, 255));

 Future<ui.Image> setImageData(ui.Image uiX) async 

    int w = uiX.width;
    int h = uiX.height;

    //get byteData

    final rgbaImageData =
           await uiX.toByteData(format: ui.ImageByteFormat.png);

    // convert to Uint32

    Uint32List words = Uint32List.view(
        rgbaImageData.buffer,
        rgbaImageData.offsetInBytes,
        rgbaImageData.lengthInBytes ~/ Uint32List.bytesPerElement);
   
    int a = 0;
    int r = 0;
    int g = 0;
    int b = 0;

    for (int idx = 0; idx < words.length; idx++) {
      Color color = Color(words[idx]);

      if (color.red > 128) {
         a = 0;
      } else {
        r = 128;
        g = 135;
        b = 110;
   
      }
      words[idx] = getColorY(a, r, g, b);
    }
    //convert Uint32List to Uint8List 

    Uint8List bytes = words.buffer.asUint8List();
   
    final Completer<ui.Image> imageCompleter = new Completer();
    ui.decodeImageFromList(bytes, (ui.Image img) {
      imageCompleter.complete(img);
    });
    return imageCompleter.future;
  }

您可以将 ui.Image 转换为原始字节数据,对其进行操作,然后使用 ui.imageFromBytes.

将其转换回 ui.Image
final ui.Image image = ...;

// Convert to raw rgba
final ByteData bytes = image.toByteData(format: 
  ImageByteFormat.rawRgba,
);

// Set the first pixel of the image to red.
bytes.setUint32(0, 0xFF0000FF);

// Set pixel at (x, y) to green.
final x = 10;
final y = 10;
bytes.setUint32((y * image.width + x) * 4, 0x00FF00FF);

ui.decodeImageFromPixels(
  bytes.buffer.asUint8List(),
  image.width,
  image.height,
  ui.PixelFormat.rgba8888,
  (ui.Image result) {
    // use your result image
  },
);

您的代码中错误的部分是:

final rgbaImageData = await uiX.toByteData(format: ui.ImageByteFormat.png);

As format: 指定返回字节的格式。所以,你必须通过 ui.ImageByteFormat.rawRgba.

此外,Color(int) 需要 ARGB 格式而不是 RGBA。