processing_camera_image.dart
5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:ffi/ffi.dart' as ffi;
import 'package:image/image.dart' as imglib;
/*
'C' Header definition
uint32_t *convertImage(uint8_t *plane0, uint8_t *plane1, uint8_t *plane2, int bytesPerRow, int bytesPerPixel, int width, int height);
*/
typedef convert_image_rgb_c = Pointer<Uint32> Function(Pointer<Uint8>,
Pointer<Uint8>, Pointer<Uint8>, Int32, Int32, Int32, Int32, Double);
typedef ConvertImageRGBFlutter = Pointer<Uint32> Function(
Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, int, int, int, int, double);
typedef convert_image_gray_c = Pointer<Uint32> Function(
Pointer<Uint8>, Int32, Int32, Double);
typedef ConvertImageGrayFlutter = Pointer<Uint32> Function(
Pointer<Uint8>, int, int, double);
class ProcessingCameraImage {
static ProcessingCameraImage? _instance;
late final ConvertImageRGBFlutter _convertImageRGB;
late final ConvertImageGrayFlutter _convertImageGrayFlutter;
factory ProcessingCameraImage() {
_instance ??= ProcessingCameraImage._();
return _instance!;
}
ProcessingCameraImage._() {
final DynamicLibrary convertImageLib = Platform.isAndroid
? DynamicLibrary.open("libconvertImage.so")
: DynamicLibrary.process();
_convertImageRGB = convertImageLib
.lookup<NativeFunction<convert_image_rgb_c>>('convertImageRGB')
.asFunction<ConvertImageRGBFlutter>();
_convertImageGrayFlutter = convertImageLib
.lookup<NativeFunction<convert_image_gray_c>>('convertImageGrayScale')
.asFunction<ConvertImageGrayFlutter>();
}
/// [ProcessCameraImageToRGB].
imglib.Image? processCameraImageToRGB({
int? width,
int? height,
Uint8List? plane0,
Uint8List? plane1,
Uint8List? plane2,
double? rotationAngle,
int? bytesPerRowPlane0,
int? bytesPerRowPlane1,
int? bytesPerPixelPlan1,
}) {
if (width == null ||
height == null ||
plane0?.isEmpty == null ||
plane1?.isEmpty == null ||
plane2?.isEmpty == null ||
bytesPerRowPlane0 == null ||
bytesPerRowPlane1 == null ||
bytesPerPixelPlan1 == null) {
return null;
}
if (Platform.isAndroid) {
// Allocate memory for the 3 planes of the image
Pointer<Uint8> p = ffi.malloc.allocate(plane0?.length ?? 0);
Pointer<Uint8> p1 = ffi.malloc.allocate(plane1?.length ?? 0);
Pointer<Uint8> p2 = ffi.malloc.allocate(plane2?.length ?? 0);
// Assign the planes data to the pointers of the image
Uint8List pointerList = p.asTypedList(plane0?.length ?? 0);
Uint8List pointerList1 = p1.asTypedList(plane1?.length ?? 0);
Uint8List pointerList2 = p2.asTypedList(plane2?.length ?? 0);
pointerList.setRange(0, plane0?.length ?? 0, plane0 ?? Uint8List(0));
pointerList1.setRange(0, plane1?.length ?? 0, plane1 ?? Uint8List(0));
pointerList2.setRange(0, plane2?.length ?? 0, plane2 ?? Uint8List(0));
// Call the convertImage function and convert the YUV to RGB
Pointer<Uint32> imgP = _convertImageRGB(p, p1, p2, bytesPerRowPlane1,
bytesPerPixelPlan1, bytesPerRowPlane0, height, rotationAngle ?? 0.0);
// Get the pointer of the data returned from the function to a List
List<int> imgData = imgP.asTypedList(((bytesPerRowPlane0) * (height)));
// Generate image from the converted data
imglib.Image img =
imglib.Image.fromBytes(height, bytesPerRowPlane0, imgData);
// Free the memory space allocated
// from the planes and the converted data
ffi.malloc.free(p);
ffi.malloc.free(p1);
ffi.malloc.free(p2);
ffi.malloc.free(imgP);
if (rotationAngle != null) {
// imglib.Image imgRot = imglib.copyRotate(img, rotationAngle);
return img;
} else {
return img;
}
} else if (Platform.isIOS) {
imglib.Image img = imglib.Image.fromBytes(
bytesPerRowPlane0,
height,
plane0 ?? Uint8List(0),
format: imglib.Format.bgra,
);
if (rotationAngle != null) {
imglib.Image imgRot = imglib.copyRotate(img, rotationAngle);
return imgRot;
} else {
return img;
}
}
return null;
}
/// [processCameraImageToGray].
imglib.Image? processCameraImageToGray({
int? width,
int? height,
Uint8List? plane0,
double? rotationAngle,
}) {
if (width == null || height == null || plane0?.isEmpty == null) {
return null;
}
if (Platform.isAndroid) {
Pointer<Uint8> p = ffi.malloc.allocate(plane0?.length ?? 0);
Uint8List pointerList = p.asTypedList(plane0?.length ?? 0);
pointerList.setRange(0, plane0?.length ?? 0, plane0 ?? Uint8List(0));
Pointer<Uint32> imgP =
_convertImageGrayFlutter(p, width, height, rotationAngle ?? 0.0);
List<int> imgData = imgP.asTypedList(width * height);
imglib.Image img = imglib.Image.fromBytes(height, width, imgData);
ffi.malloc.free(p);
ffi.malloc.free(imgP);
if (rotationAngle != null) {
imglib.Image imgRot = imglib.copyRotate(img, rotationAngle);
return imgRot;
} else {
return img;
}
} else if (Platform.isIOS) {
imglib.Image img = imglib.Image.fromBytes(
width,
height,
plane0 ?? Uint8List(0),
format: imglib.Format.bgra,
);
if (rotationAngle != null) {
imglib.Image imgRot = imglib.copyRotate(img, rotationAngle);
return imgRot;
} else {
return img;
}
}
return null;
}
}