imageMergeTransform function
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;
}());
}