Flutter - 将 BlendMode 保存到图像

Flutter - Save BlendMode to Image

我正在尝试实现一个 UI,用户可以在其中编辑和应用效果到上传的图像,并想保存 BlendMode merged to the image. It's possible to save the result of the blended image or apply it using the Canvas

有一些包应用了一些特定的过滤器,但我想要为最终用户定制更多的东西。

我已经看过一些关于如何实现 Canvas 来绘制图像的示例,但无法弄清楚如何使用文档加载图像并应用相关的混合。谁能举个例子?

更新:

对于有相同问题的人,下面的代码说明了如何将图像从 canvas 保存到应用了 blendMode 的文件中。 但我仍然没有预期的结果。生成的图像质量与原始图像不同,混合似乎也不是我应用的混合。而且我不能保存为jpg,只能保存为png文件。

那么,我怎样才能载入图像,应用 canvas 混合并保存为 jpg 文件,而不损失质量?

代码:

const kCanvasSize = 200.0;

class CanvasImageToFile {
  CanvasImageToFile._();
  static final instance = CanvasImageToFile._();

  ByteData _readFromFile(File file) {
    // File file = getSomeCorrectFile();
    Uint8List bytes = file.readAsBytesSync();
    return ByteData.view(bytes.buffer);
  }

  Future<File> _writeToFile(ByteData data) async {
    String dir = (await getTemporaryDirectory()).path;
    String filePath = '$dir/tempImage.jpg';
    final buffer = data.buffer;
    return new File(filePath).writeAsBytes(
        buffer.asUint8List(data.offsetInBytes, data.lengthInBytes));
  }

  Future<ui.Image> _loadImageSource(File imageSource) async {
    // ByteData data = await rootBundle.load(asset);
    ByteData data = _readFromFile(imageSource);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }

  Future<File> generateImage(File imageSource) async {
    File imageResult;
    ui.Image image;
    await _loadImageSource(imageSource).then((value) {
      image = value;
    });
    if (image != null) {
      final recorder = ui.PictureRecorder();
      var rect =
          Rect.fromPoints(Offset(0.0, 0.0), Offset(kCanvasSize, kCanvasSize));
      final canvas = Canvas(recorder, rect);

      Size outputSize = rect.size;
      Paint paint = new Paint();

      //OVERLAY - BlendMode uses the previously drawn content as a mask
      paint.blendMode = BlendMode.colorBurn;
      paint.color = Colors.red;
      // paint.colorFilter = ColorFilter.mode(Colors.blue, BlendMode.colorDodge);
      // paint = Paint()..color = Colors.red;
      // paint = Paint()..blendMode = BlendMode.multiply;

      //Image
      Size inputSize = Size(image.width.toDouble(), image.height.toDouble());
      final FittedSizes fittedSizes =
          applyBoxFit(BoxFit.cover, inputSize, outputSize);
      final Size sourceSize = fittedSizes.source;
      final Rect sourceRect =
          Alignment.center.inscribe(sourceSize, Offset.zero & inputSize);

      canvas.saveLayer(rect, paint);
      canvas.drawImageRect(
          image, sourceRect, rect, paint);
      canvas.restore();

      final picture = recorder.endRecording();
      final img = await picture.toImage(200, 200);
      final byteData = await img.toByteData(format: ImageByteFormat.png);

      await _writeToFile(byteData).then((value) {
        imageResult = value;
      });
      return imageResult;
    }

经过一些研究和一些调整,在我以前的代码中使用(Bitmap 包)将图像从 png 解码为 rawUnmodified,我可以用原始格式 (jpg) 保存图像并实现我想要的。如果有人有同样的问题,请按照以下代码使用 canvas 加载图像,应用混合并写入具有相同质量的文件:

Future<File> generateImage(
      File imageSource, Color color, BlendMode blendMode) async {
    File imageResult;
    ui.Image image;
    await _loadImageSource(imageSource).then((value) {
      image = value;
    });
    if (image != null) {
      final recorder = ui.PictureRecorder();
      var rect = Rect.fromPoints(Offset(0.0, 0.0),
          Offset(image.width.toDouble(), image.height.toDouble()));
      final canvas = Canvas(recorder, rect);

      Size outputSize = rect.size;
      Paint paint = new Paint();

      //OVERLAY - BlendMode uses the previously drawn content as a mask
      // paint.blendMode = blendMode;
      // paint.color = color;
      paint.colorFilter = ColorFilter.mode(color, blendMode);

      //Image
      Size inputSize = Size(image.width.toDouble(), image.height.toDouble());
      final FittedSizes fittedSizes =
          applyBoxFit(BoxFit.contain, inputSize, outputSize);
      final Size sourceSize = fittedSizes.source;
      final Rect sourceRect =
          Alignment.center.inscribe(sourceSize, Offset.zero & inputSize);

      canvas.drawImageRect(image, sourceRect, rect, paint);

      final picture = recorder.endRecording();
      final img = await picture.toImage(image.width, image.height);

      ByteData byteData =
          await img.toByteData(format: ui.ImageByteFormat.rawUnmodified);
      Bitmap bitmap = Bitmap.fromHeadless(
          image.width, image.height, byteData.buffer.asUint8List());
      Uint8List headedIntList = bitmap.buildHeaded();

      await _writeToFile(headedIntList.buffer.asByteData()).then((value) {
        imageResult = value;
      });
      return imageResult;
    }
  }