applyBlur method

Future<Uint8List?> applyBlur(
  1. Uint8List frameData, {
  2. required double intensity,
  3. required int width,
  4. required int height,
  5. Uint8List? mask,
})

Apply blur effect to the background (person stays sharp).

Mirrors React's blur background effect. Uses the segmentation mask to selectively blur only the background.

Implementation

Future<Uint8List?> applyBlur(
  Uint8List frameData, {
  required double intensity,
  required int width,
  required int height,
  Uint8List? mask,
}) async {
  if (mask == null) return frameData;

  try {
    // Decode the frame to an image
    final codec = await ui.instantiateImageCodec(
      frameData,
      targetWidth: width,
      targetHeight: height,
    );
    final frameImage = (await codec.getNextFrame()).image;

    // Create a picture recorder for compositing
    final recorder = ui.PictureRecorder();
    final canvas = Canvas(recorder);
    final size = Size(width.toDouble(), height.toDouble());

    // Calculate blur sigma from intensity (0.0-1.0 → 0-30 sigma)
    final sigma = intensity * 30.0;

    // Step 1: Draw blurred background
    final blurPaint = Paint()
      ..imageFilter = ui.ImageFilter.blur(
        sigmaX: sigma,
        sigmaY: sigma,
        tileMode: TileMode.clamp,
      );
    canvas.drawImage(frameImage, Offset.zero, blurPaint);

    // Step 2: Draw sharp foreground (person) using mask
    // Create mask image from bytes
    final maskImage =
        await _bytesToImage(mask, width, height, isGrayscale: true);
    if (maskImage != null) {
      // Use mask as alpha channel to composite original over blur
      final maskPaint = Paint()..blendMode = BlendMode.dstIn;

      // Draw original frame
      canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());
      canvas.drawImage(frameImage, Offset.zero, Paint());

      // Apply mask
      canvas.drawImage(maskImage, Offset.zero, maskPaint);
      canvas.restore();

      maskImage.dispose();
    }

    // Finalize
    final picture = recorder.endRecording();
    final resultImage = await picture.toImage(width, height);
    final byteData =
        await resultImage.toByteData(format: ui.ImageByteFormat.rawRgba);

    frameImage.dispose();
    resultImage.dispose();

    return byteData?.buffer.asUint8List();
  } catch (e) {
    debugPrint('applyBlur error: $e');
    return frameData;
  }
}