cropFromRoi function

Future<Image> cropFromRoi(
  1. Image src,
  2. RectF roi
)

Implementation

Future<img.Image> cropFromRoi(img.Image src, RectF roi) async {
  if (roi.xmin < 0 || roi.ymin < 0 || roi.xmax > 1 || roi.ymax > 1) {
    throw ArgumentError('ROI coordinates must be normalized [0,1], got: (${roi.xmin}, ${roi.ymin}, ${roi.xmax}, ${roi.ymax})');
  }
  if (roi.xmin >= roi.xmax || roi.ymin >= roi.ymax) {
    throw ArgumentError('Invalid ROI: min coordinates must be less than max');
  }
  final rgb = src.getBytes(order: img.ChannelOrder.rgb);
  final rp = ReceivePort();
  final params = {
    'sendPort': rp.sendPort,
    'op': 'crop',
    'w': src.width,
    'h': src.height,
    'rgb': TransferableTypedData.fromList([rgb]),
    'roi': {
      'xmin': roi.xmin,
      'ymin': roi.ymin,
      'xmax': roi.xmax,
      'ymax': roi.ymax,
    },
  };
  await Isolate.spawn(_imageTransformIsolate, params);
  final Map msg = await rp.first as Map;
  rp.close();
  if (msg['ok'] != true) {
    final error = msg['error'];
    throw StateError('Image crop failed: ${error ?? "unknown error"}');
  }
  final ByteBuffer outBB = (msg['rgb'] as TransferableTypedData).materialize();
  final Uint8List outRgb = outBB.asUint8List();
  final int ow = msg['w'] as int;
  final int oh = msg['h'] as int;
  return img.Image.fromBytes(width: ow, height: oh, bytes: outRgb.buffer, order: img.ChannelOrder.rgb);
}