applyImageBackground method
Apply image background replacement.
Mirrors React's image compositing:
ctx.drawImage(results.segmentationMask, 0, 0, width, height);
ctx.globalCompositeOperation = "source-out";
ctx.fillStyle = ctx.createPattern(virtualImage, 'no-repeat');
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = "destination-atop";
ctx.drawImage(results.image, 0, 0, width, height);
Implementation
Future<Uint8List?> applyImageBackground(
Uint8List frameData, {
required ui.Image backgroundImage,
required int width,
required int height,
required Uint8List mask,
}) async {
try {
// Decode the frame
final codec = await ui.instantiateImageCodec(
frameData,
targetWidth: width,
targetHeight: height,
);
final frameImage = (await codec.getNextFrame()).image;
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final size = Size(width.toDouble(), height.toDouble());
// Create mask image
final maskImage =
await _bytesToImage(mask, width, height, isGrayscale: true);
if (maskImage == null) {
frameImage.dispose();
return frameData;
}
// Step 1: Draw background image (scaled to fill)
final bgRect = Rect.fromLTWH(0, 0, size.width, size.height);
final srcRect = Rect.fromLTWH(
0,
0,
backgroundImage.width.toDouble(),
backgroundImage.height.toDouble(),
);
canvas.drawImageRect(backgroundImage, srcRect, bgRect, Paint());
// Step 2: Draw person over background using mask
canvas.saveLayer(bgRect, Paint());
canvas.drawImage(frameImage, Offset.zero, Paint());
canvas.drawImage(
maskImage, Offset.zero, Paint()..blendMode = BlendMode.dstIn);
canvas.restore();
// Finalize
final picture = recorder.endRecording();
final resultImage = await picture.toImage(width, height);
final byteData =
await resultImage.toByteData(format: ui.ImageByteFormat.rawRgba);
frameImage.dispose();
maskImage.dispose();
resultImage.dispose();
return byteData?.buffer.asUint8List();
} catch (e) {
debugPrint('applyImageBackground error: $e');
return frameData;
}
}