imageMergeTransform function

Stream imageMergeTransform(
  1. Stream<Map> inputStream
)

Implementation

@pragma('vm:entry-point')
Stream<dynamic> imageMergeTransform(Stream<Map> inputStream) async* {
  var index = 0;
  final List<(Image, int, int)> list = [];
  var maxWidth = 0;
  var maxHeight = 0;
  ScreenshotEncoder? encoder;
  int startTime = DateTime.now().millisecondsSinceEpoch;
  await for (var map in inputStream) {
    if (ScreenshotEncoder.isValidMap(map)) {
      encoder = ScreenshotEncoder.fromMap(map);
      continue;
    }
    final int dx = map['dx'];
    final int dy = map['dy'];
    final int? color = map['color'];
    final Color? backgroundColor;
    if (color != null) {
      final argb = (ByteData(4)..setUint32(0, color)).buffer.asUint8List();
      backgroundColor = ColorUint8.rgba(argb[1], argb[2], argb[3], argb[0]);
    } else {
      backgroundColor = null;
    }
    final currentImage = decodeRgba(map['width'], map['height'], map['bytes']);
    for (var y = 0; y < currentImage.height; y++) {
      for (var x = 0; x < currentImage.width; x++) {
        final newPixel =
            blendColors(backgroundColor, currentImage.getPixel(x, y));
        currentImage.setPixel(x, y, newPixel);
      }
    }
    list.add((currentImage, dx, dy));
    final right = dx + currentImage.width;
    final bottom = dy + currentImage.height;
    if (right > maxWidth) {
      maxWidth = right;
    }
    if (bottom > maxHeight) {
      maxHeight = bottom;
    }
    yield index++;
    assert(() {
      log('input: ${currentImage.width}, ${currentImage.height}');
      return true;
    }());
  }
  int inputTime = DateTime.now().millisecondsSinceEpoch;
  assert(() {
    log('inputTime: ${inputTime - startTime}');
    return true;
  }());
  Image? image;
  for (var param in list) {
    final (currentImage, dx, dy) = param;
    image ??=
        Image.fromResized(currentImage, width: maxWidth, height: maxHeight);
    final bottom = dy + currentImage.height;
    final imageBuffer = image.buffer.asUint32List();
    final currentImageBuffer = currentImage.buffer.asUint32List();
    if (dx == 0 && currentImage.width == image.width) {
      // 整个图片合并,
      final start = image.width * dy;
      final end = start + image.width * currentImage.height;
      imageBuffer.setRange(start, end, currentImageBuffer);
    } else {
      // 一行一行合并,
      for (var y = dy; y < bottom; y++) {
        final start = image.width * y + dx;
        final end = start + currentImage.width;
        imageBuffer.setRange(start, end,
            currentImageBuffer.sublist((y - dy) * currentImage.width));
      }
    }
  }
  int mergeTime = DateTime.now().millisecondsSinceEpoch;
  assert(() {
    log('mergeTime: ${mergeTime - inputTime}');
    return true;
  }());
  final result = image ?? Image.empty();
  assert(() {
    log('output: ${result.width}, ${result.height}');
    return true;
  }());
  if (encoder == null) {
    yield result.toMap();
    return;
  }
  yield encoder.encode(result);
  int encodeTime = DateTime.now().millisecondsSinceEpoch;
  assert(() {
    log('encodeTime: ${encodeTime - mergeTime}');
    return true;
  }());
}