问题
I am trying to send an image to my Custom C++ code which I am planning to run using dart:ffi. I have successfully run the hello world problem where I send two integers and get the some of them as another intiger.
Now I want to send a whole image to it and process it on my C++ code. I am able to get Uint8List
from the CameraImage
using the below code
Future<ui.Image> convertCameraImageToUiImage(CameraImage image) async {
imglib.Image libImage = imglib.Image.fromBytes(
image.width,
image.height,
image.planes[0].bytes,
format: imglib.Format.bgra,
);
final c = Completer<ui.Image>();
ui.decodeImageFromPixels(
libImage.getBytes(),
image.width,
image.height,
ui.PixelFormat.rgba8888,
c.complete,
);
return c.future;
}
Then I converted it to Uint8List
ByteData data = await image.toByteData();
Uint8List bytes = data.buffer.asUint8List();
My problem is, how should I define lookup function to send a Uint8List
to the C++ code and get List<bool>
, my function over C++ expects cv::mat
(I can tweak it to receive array of integers) as a parameter and sends a Vector of boolean.
This is what I have tried
final List<bool> Function(Uint8List image) _imageToCode = nativeAddLib
.lookup<NativeFunction<List<bool> Function(List<Uint8List>)>>("imageToCode")
.asFunction();
The problem is, the bool and Uint8List are not a type supported by C++ so the function doesn't recognize them. How should I send it over the channel.
回答1:
You have to allocate, and then copy the data into, a Pointer<something>
. Your exported C function can then have a something*
argument. You will also need to pass the length of the data. As the goal is to construct a cv::Mat
you might want to pass the geometry instead, and infer the data length from that.
So, if your exported C function has a signature:
void process(int32_t width, int32_t height, uint8_t *bytes);
your two Dart typedefs would be:
typedef process_func = Void Function(Int32 width, Int32 height, Pointer<Uint8> bytes);
typedef ProcessFunc = void Function(int width, int height, Pointer<Uint8> bytes);
use those in the lookup
_process = nativeLib
.lookup<NativeFunction<process_func>>('process')
.asFunction();
To allocate the buffer, first import 'package:ffi/ffi.dart';
and use allocate
var outBuf = allocate<Uint8>(count: outSize);
then use a for loop to copy the data. Alternatively use asTypedData
on outBuf
to get a Uint8List
and use setAll
.
Remember to free
the buffer after using it.
(As your pixels are rgba8888, they fit in unsigned 32 bit ints. You might want to pass Uint32
s across in your pointer, and get them using data.buffer.asUint32List()
.)
You want to return a list of bool
. bool
isn't supported you you have to pass a list of, say, Int8
where you've set the values to 1 and 0 respectively. (If your list is bounded and reasonably sized, you could use a bitmap. For example, if you knew it was always 32 bits long, pack those bits into a Uint32 as 32 ones and zeroes.)
There are a couple of strategies for returning a list, where list in ffi
is going to mean Pointer<something>
of course.
If the list is bounded, you can allocate it on the Dart side, pass the pointer with the function and have the C function fill in the values, maybe returning an integer of the number it filled in.
If the list is unbounded you must allow C to malloc
it, as only the C function knows how much space it needs. You now need to return 2 values: the pointer and the length. Since you can only return one value you need to do something like pass in a Pointer<Int32>
and have the C function assign the length to that.
来源:https://stackoverflow.com/questions/62102889/how-to-convert-uint8list-to-c-equivalent-datatype-using-dartffi