How could I blend two png images and mix the content outline of one of the png images?

88 views Asked by At

I have tried to implement a BlendModeWidget component to mix two PNG images with BlendMode, but the effect was not as good as expected.

Here is my code:

// main screen
class BlendModeDemo extends StatelessWidget {
  const BlendModeDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: BlendModeWidget(
        blendMode: BlendMode.multiply,
        src: "assets/radio_mix.png",
        dst: Align(
          alignment: const Alignment(-0.4, 0.8),
          child: Image.asset(
            "assets/radio.png",
            fit: BoxFit.fitHeight,
            height: 330,
          ),
        ),
      ),
    );
  }
}

class BlendModeWidget extends StatefulWidget {
  final String src;
  final Widget? dst;
  final BlendMode blendMode;
  const BlendModeWidget({
    super.key,
    this.dst,
    required this.src,
    required this.blendMode,
  });

  @override
  State<BlendModeWidget> createState() => _BlendModeWidgetState();
}

class _BlendModeWidgetState extends State<BlendModeWidget> {
  late Future<ui.Image> _future;

  Future<ui.Image> loadImage(String imagePath) async {
    final completer = Completer<ui.Image>();
    final bytes = await rootBundle.load(imagePath);
    ui.decodeImageFromList(bytes.buffer.asUint8List(), completer.complete);
    return completer.future;
  }

  @override
  void initState() {
    _future = loadImage(widget.src);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: _future,
      builder: (context, snapshot) {
        return snapshot.hasData && snapshot.data != null
            ? CustomPaint(
                foregroundPainter: BlendModePainter(
                  image: snapshot.data as ui.Image,
                  blendMode: widget.blendMode,
                ),
                child: widget.dst,
              )
            : Container(child: null);
      },
    );
  }
}

class BlendModePainter extends CustomPainter {
  final ui.Image image;
  final BlendMode blendMode;

  BlendModePainter({
    required this.image,
    required this.blendMode,
  });

  @override
  void paint(Canvas canvas, Size size) {
    ui.Image img = image;

    // 计算图像的宽高比
    double imageWidth = img.width.toDouble();
    double imageHeight = img.height.toDouble();

    // 计算绘制区域的宽度和高度,以适应CustomPaint的宽度
    double paintWidth = size.width;
    double paintHeight = size.height;

    // 容器宽高比
    double ratio = paintHeight / paintWidth;
    double offset = imageHeight - imageWidth * ratio;

    // 创建绘制区域
    Rect srcRect =
        Rect.fromPoints(Offset(0, offset), Offset(imageWidth, imageHeight));
    Rect destRect =
        Rect.fromPoints(Offset.zero, Offset(paintWidth, paintHeight));

    // 绘制图片
    Paint paint = Paint()
      ..filterQuality = FilterQuality.high
      ..blendMode = blendMode;
    canvas.drawImageRect(img, srcRect, destRect, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

These are the pictures:

The effect of running the above code:

I have tried to modify the code:

class BlendModeDemo extends StatelessWidget {
  const BlendModeDemo({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      // Wrap it with a ColorFiltered,it`s working on ios, howerver not work on mac or android!
      child: ColorFiltered(
        colorFilter: ColorFilter.mode(
          Colors.white.withOpacity(0.01),
          BlendMode.srcATop,
        ),
        child: BlendModeWidget(
          blendMode: BlendMode.multiply,
          src: "assets/bg_mix.png",
          dst: Align(
            alignment: const Alignment(-0.4, 0.8),
            child: Image.asset(
              "assets/音响.png",
              fit: BoxFit.fitHeight,
              height: 330,
            ),
          ),
        ),
      ),
    );
  }
}

Wrap it with a ColorFiltered, it`s working on iOS, but it does not work on Mac or Android!

0

There are 0 answers