[mob][photos] Mix of flutter and rust decoding

This commit is contained in:
laurenspriem
2024-11-08 08:41:14 +05:30
parent ffa50df43e
commit 1bad2b3555
9 changed files with 377 additions and 305 deletions

View File

@@ -8,6 +8,8 @@
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
import 'package:photos/src/rust/frb_generated.dart';
// These functions are ignored because they are not marked as `pub`: `process_image_ml`
Future<
(
Uint8List,
@@ -24,6 +26,24 @@ Future<
RustLib.instance.api
.crateApiImageProcessingProcessImageMlFromPath(imagePath: imagePath);
Future<
(
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt
)> processImageMlFromData(
{required List<int> rgbaData,
required int width,
required int height}) =>
RustLib.instance.api.crateApiImageProcessingProcessImageMlFromData(
rgbaData: rgbaData, width: width, height: height);
Future<(Uint8List, String, BigInt, BigInt)> processYoloFace(
{required String imagePath}) =>
RustLib.instance.api

View File

@@ -72,7 +72,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.5.1';
@override
int get rustContentHash => -1741400115;
int get rustContentHash => -804230794;
static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig(
@@ -86,6 +86,23 @@ abstract class RustLibApi extends BaseApi {
Future<(Uint8List, String, BigInt, BigInt)>
crateApiImageProcessingProcessClip({required String imagePath});
Future<
(
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt
)>
crateApiImageProcessingProcessImageMlFromData(
{required List<int> rgbaData,
required int width,
required int height});
Future<
(
Uint8List,
@@ -143,6 +160,49 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
argNames: ["imagePath"],
);
@override
Future<
(
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt
)>
crateApiImageProcessingProcessImageMlFromData(
{required List<int> rgbaData,
required int width,
required int height}) {
return handler.executeNormal(NormalTask(
callFfi: (port_) {
final arg0 = cst_encode_list_prim_u_8_loose(rgbaData);
final arg1 = cst_encode_u_32(width);
final arg2 = cst_encode_u_32(height);
return wire
.wire__crate__api__image_processing__process_image_ml_from_data(
port_, arg0, arg1, arg2);
},
codec: DcoCodec(
decodeSuccessData:
dco_decode_record_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize,
decodeErrorData: null,
),
constMeta: kCrateApiImageProcessingProcessImageMlFromDataConstMeta,
argValues: [rgbaData, width, height],
apiImpl: this,
));
}
TaskConstMeta get kCrateApiImageProcessingProcessImageMlFromDataConstMeta =>
const TaskConstMeta(
debugName: "process_image_ml_from_data",
argNames: ["rgbaData", "width", "height"],
);
@override
Future<
(
@@ -257,6 +317,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as String;
}
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return raw as List<int>;
}
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -310,6 +376,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
}
@protected
int dco_decode_u_32(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return raw as int;
}
@protected
int dco_decode_u_8(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
@@ -335,6 +407,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return utf8.decoder.convert(inner);
}
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
final len_ = sse_decode_i_32(deserializer);
return deserializer.buffer.getUint8List(len_);
}
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -390,6 +469,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
);
}
@protected
int sse_decode_u_32(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
return deserializer.buffer.getUint32();
}
@protected
int sse_decode_u_8(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
@@ -419,6 +504,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0;
}
@protected
int cst_encode_u_32(int raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
return raw;
}
@protected
int cst_encode_u_8(int raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
@@ -437,6 +528,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_list_prim_u_8_strict(utf8.encoder.convert(self), serializer);
}
@protected
void sse_encode_list_prim_u_8_loose(
List<int> self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_i_32(self.length, serializer);
serializer.buffer
.putUint8List(self is Uint8List ? self : Uint8List.fromList(self));
}
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer) {
@@ -482,6 +582,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
sse_encode_usize(self.$9, serializer);
}
@protected
void sse_encode_u_32(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs
serializer.buffer.putUint32(self);
}
@protected
void sse_encode_u_8(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs

View File

@@ -24,6 +24,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
String dco_decode_String(dynamic raw);
@protected
List<int> dco_decode_list_prim_u_8_loose(dynamic raw);
@protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@@ -45,6 +48,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) dco_decode_record_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize(
dynamic raw);
@protected
int dco_decode_u_32(dynamic raw);
@protected
int dco_decode_u_8(dynamic raw);
@@ -57,6 +63,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
String sse_decode_String(SseDeserializer deserializer);
@protected
List<int> sse_decode_list_prim_u_8_loose(SseDeserializer deserializer);
@protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@@ -79,6 +88,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) sse_decode_record_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize_list_prim_u_8_strict_usize_usize(
SseDeserializer deserializer);
@protected
int sse_decode_u_32(SseDeserializer deserializer);
@protected
int sse_decode_u_8(SseDeserializer deserializer);
@@ -100,6 +112,15 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
return cst_encode_list_prim_u_8_strict(utf8.encoder.convert(raw));
}
@protected
ffi.Pointer<wire_cst_list_prim_u_8_loose> cst_encode_list_prim_u_8_loose(
List<int> raw) {
// Codec=Cst (C-struct based), see doc to use other codecs
final ans = wire.cst_new_list_prim_u_8_loose(raw.length);
ans.ref.ptr.asTypedList(raw.length).setAll(0, raw);
return ans;
}
@protected
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_encode_list_prim_u_8_strict(
Uint8List raw) {
@@ -151,6 +172,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
wireObj.field8 = cst_encode_usize(apiObj.$9);
}
@protected
int cst_encode_u_32(int raw);
@protected
int cst_encode_u_8(int raw);
@@ -160,6 +184,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected
void sse_encode_String(String self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_loose(List<int> self, SseSerializer serializer);
@protected
void sse_encode_list_prim_u_8_strict(
Uint8List self, SseSerializer serializer);
@@ -184,6 +211,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
) self,
SseSerializer serializer);
@protected
void sse_encode_u_32(int self, SseSerializer serializer);
@protected
void sse_encode_u_8(int self, SseSerializer serializer);
@@ -260,6 +290,35 @@ class RustLibWire implements BaseWire {
_wire__crate__api__image_processing__process_clipPtr.asFunction<
void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
void wire__crate__api__image_processing__process_image_ml_from_data(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_loose> rgba_data,
int width,
int height,
) {
return _wire__crate__api__image_processing__process_image_ml_from_data(
port_,
rgba_data,
width,
height,
);
}
late final _wire__crate__api__image_processing__process_image_ml_from_dataPtr =
_lookup<
ffi.NativeFunction<
ffi.Void Function(
ffi.Int64,
ffi.Pointer<wire_cst_list_prim_u_8_loose>,
ffi.Uint32,
ffi.Uint32)>>(
'frbgen_photos_wire__crate__api__image_processing__process_image_ml_from_data');
late final _wire__crate__api__image_processing__process_image_ml_from_data =
_wire__crate__api__image_processing__process_image_ml_from_dataPtr
.asFunction<
void Function(
int, ffi.Pointer<wire_cst_list_prim_u_8_loose>, int, int)>();
void wire__crate__api__image_processing__process_image_ml_from_path(
int port_,
ffi.Pointer<wire_cst_list_prim_u_8_strict> image_path,
@@ -332,6 +391,21 @@ class RustLibWire implements BaseWire {
late final _wire__crate__api__simple__init_app =
_wire__crate__api__simple__init_appPtr.asFunction<void Function(int)>();
ffi.Pointer<wire_cst_list_prim_u_8_loose> cst_new_list_prim_u_8_loose(
int len,
) {
return _cst_new_list_prim_u_8_loose(
len,
);
}
late final _cst_new_list_prim_u_8_loosePtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<wire_cst_list_prim_u_8_loose> Function(
ffi.Int32)>>('frbgen_photos_cst_new_list_prim_u_8_loose');
late final _cst_new_list_prim_u_8_loose = _cst_new_list_prim_u_8_loosePtr
.asFunction<ffi.Pointer<wire_cst_list_prim_u_8_loose> Function(int)>();
ffi.Pointer<wire_cst_list_prim_u_8_strict> cst_new_list_prim_u_8_strict(
int len,
) {
@@ -374,6 +448,13 @@ final class wire_cst_list_prim_u_8_strict extends ffi.Struct {
external int len;
}
final class wire_cst_list_prim_u_8_loose extends ffi.Struct {
external ffi.Pointer<ffi.Uint8> ptr;
@ffi.Int32()
external int len;
}
final class wire_cst_record_list_prim_u_8_strict_string_usize_usize
extends ffi.Struct {
external ffi.Pointer<wire_cst_list_prim_u_8_strict> field0;

View File

@@ -32,7 +32,7 @@ final List<List<double>> gaussianKernel =
const maxKernelSize = gaussianKernelSize;
const maxKernelRadius = maxKernelSize ~/ 2;
const List<String> supportedImageFormats = [
const List<String> supportedRustImageFormats = [
'bmp',
'dds',
'farbfeld',
@@ -48,8 +48,6 @@ const List<String> supportedImageFormats = [
'tga',
'tiff',
'webp',
'heic',
'heif',
];
Future<(Image, Uint8List)> decodeImageFromPath(String imagePath) async {
@@ -86,35 +84,9 @@ Future<(Image, Uint8List)> decodeImageFromPath(String imagePath) async {
}
}
Future<String> safePathFromImagepath(String imagePath) async {
bool canRustDecodeImage(String imagePath) {
final format = imagePath.split('.').last;
if (supportedImageFormats.contains(format)) {
return imagePath;
}
try {
final newPath = imagePath.replaceAll(format, 'jpeg');
final time = DateTime.now();
final File? convertedFile = await FlutterImageCompress.compressAndGetFile(
imagePath,
newPath,
format: CompressFormat.jpeg,
);
_logger.info(
'Conversion successful, heic converted in ${DateTime.now().difference(time).inMilliseconds} ms',
);
if (convertedFile == null) {
throw Exception('Error converting image to jpeg');
}
return newPath;
} catch (e) {
_logger.severe(
'Error decoding image of format $format on ${Platform.isAndroid ? "Android" : "iOS"}',
e,
);
throw Exception(
'InvalidImageFormatException: Error decoding image of format $format',
);
}
return supportedRustImageFormats.contains(format);
}
/// Decodes [Uint8List] image data to an ui.[Image] object.

View File

@@ -1,5 +1,6 @@
import "dart:io" show File;
import "dart:math" as math show sqrt, min, max;
import "dart:typed_data" show Uint8List;
import "package:flutter/services.dart" show PlatformException;
import "package:logging/logging.dart";
@@ -399,10 +400,28 @@ Future<MLResult> analyzeImageStatic(Map args) async {
final startTime = DateTime.now();
// Decode the image once to use for both face detection and alignment
final safePath = await safePathFromImagepath(imagePath);
final format = safePath.split('.').last;
// final (image, rawRgbaBytes) = await decodeImageFromPath(imagePath);
final bool decodeInRust = canRustDecodeImage(imagePath);
late (
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt,
Uint8List,
BigInt,
BigInt
) rustResults;
if (decodeInRust) {
rustResults = await processImageMlFromPath(imagePath: imagePath);
} else {
final (image, rawRgbaBytes) = await decodeImageFromPath(imagePath);
rustResults = await processImageMlFromData(
rgbaData: rawRgbaBytes,
width: image.width,
height: image.height,
);
}
final (
rawRgbaBytes,
imageHeight,
@@ -413,17 +432,17 @@ Future<MLResult> analyzeImageStatic(Map args) async {
clipBytes,
clipHeight,
clipWidth
) = await processImageMlFromPath(imagePath: safePath);
) = rustResults;
final decodedImageSize =
Dimensions(height: imageHeight.toInt(), width: imageWidth.toInt());
final decodeTime = DateTime.now();
final decodeMs = decodeTime.difference(startTime).inMilliseconds;
_logger.info(
'ML processing in rust took ${DateTime.now().difference(decodeTime).inMilliseconds} ms for format $format',
'ML total image processing (in rust) took ${DateTime.now().difference(decodeTime).inMilliseconds} ms',
);
final decodedImageSize =
Dimensions(height: imageHeight.toInt(), width: imageWidth.toInt());
final result = MLResult.fromEnteFileID(enteFileID);
result.decodedImageSize = decodedImageSize;
String faceMsString = "", clipMsString = "";
final pipelines = await Future.wait([
runFaces

234
mobile/rust/Cargo.lock generated
View File

@@ -146,29 +146,6 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
"which",
]
[[package]]
name = "bit_field"
version = "0.10.2"
@@ -181,12 +158,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bitstream-io"
version = "2.5.3"
@@ -249,15 +220,6 @@ dependencies = [
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-expr"
version = "0.15.8"
@@ -274,17 +236,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "color_quant"
version = "1.1.0"
@@ -397,17 +348,6 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "enumn"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "env_logger"
version = "0.10.2"
@@ -424,16 +364,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[package]]
name = "exr"
version = "1.72.0"
@@ -520,12 +450,6 @@ dependencies = [
"syn",
]
[[package]]
name = "four-cc"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "431a4c31778fde52b4400de34975f219eeca55cc829a9de157cd743a5b230ecb"
[[package]]
name = "futures"
version = "0.3.31"
@@ -652,12 +576,6 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "half"
version = "2.4.1"
@@ -692,15 +610,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "image"
version = "0.25.4"
@@ -800,12 +709,6 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "lebe"
version = "0.5.2"
@@ -829,47 +732,6 @@ dependencies = [
"once_cell",
]
[[package]]
name = "libheif-rs"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c32c0a0c970782707070f11c8612bced800b916af4ddaf6229161dc3ceb907"
dependencies = [
"enumn",
"four-cc",
"libc",
"libheif-sys",
]
[[package]]
name = "libheif-sys"
version = "2.1.1+1.17.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f60b29be1ef3ab2aba61344f09a18c3edf552bf4f9fbec9bd68b9ea6f98e71f8"
dependencies = [
"bindgen",
"libc",
"pkg-config",
"vcpkg",
"walkdir",
]
[[package]]
name = "libloading"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "lock_api"
version = "0.4.12"
@@ -1083,7 +945,7 @@ version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0"
dependencies = [
"bitflags 1.3.2",
"bitflags",
"crc32fast",
"fdeflate",
"flate2",
@@ -1105,16 +967,6 @@ dependencies = [
"zerocopy",
]
[[package]]
name = "prettyplease"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.89"
@@ -1321,7 +1173,6 @@ dependencies = [
"bytemuck",
"flutter_rust_bridge",
"image",
"libheif-rs",
"resize",
"rgb",
]
@@ -1332,34 +1183,6 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee"
dependencies = [
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -1577,12 +1400,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version-compare"
version = "0.2.0"
@@ -1595,16 +1412,6 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@@ -1694,45 +1501,6 @@ version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"

View File

@@ -11,5 +11,4 @@ flutter_rust_bridge = "=2.5.1"
image = "0.25.4"
resize = "0.8.7"
rgb = "0.8.50"
bytemuck = "1.16.0"
libheif-rs = "1.0.2"
bytemuck = "1.16.0"

View File

@@ -1,5 +1,4 @@
use image::ImageBuffer;
use libheif_rs::{ColorSpace, HeifContext, LibHeif, RgbChroma};
use resize::{px::RGB, Pixel::RGB8, Type::Lanczos3, Type::Mitchell};
use rgb::FromSlice;
@@ -16,36 +15,55 @@ pub fn process_image_ml_from_path(
usize,
usize,
) {
// Check the image format by checking the file extension in the image_path string (~0ms)
let format = image_path.split('.').last().unwrap().to_lowercase();
// Load the image from the path (~200ms)
let img: image::DynamicImage = image::open(image_path).expect("Failed to open image");
let img = if format == "heic" || format == "heif" {
let lib_heif = LibHeif::new();
let ctx = HeifContext::read_from_file(image_path).expect("Failed to read HEIF file");
let handle = ctx
.primary_image_handle()
.expect("Failed to get primary image handle");
let decoded = lib_heif
.decode(&handle, ColorSpace::Rgb(RgbChroma::Rgb), None)
.expect("Failed to decode image");
let plane = decoded
.planes()
.interleaved
.expect("Failed to get interleaved plane");
let rgb_data = plane.data.to_vec();
let img = image::DynamicImage::from(
ImageBuffer::<image::Rgb<u8>, _>::from_raw(decoded.width(), decoded.height(), rgb_data)
.expect("Failed to create image buffer"),
);
img
} else {
let img = image::open(image_path).expect("Failed to open image");
img
};
// Process the image
let results = process_image_ml(img);
// Load the image (~200ms)
// let img = image::open(image_path).expect("Failed to open image");
results
}
pub fn process_image_ml_from_data(
rgba_data: Vec<u8>,
width: u32,
height: u32,
) -> (
Vec<u8>,
usize,
usize,
Vec<u8>,
usize,
usize,
Vec<u8>,
usize,
usize,
) {
// Load the image from the data
let img = image::DynamicImage::from(
ImageBuffer::<image::Rgb<u8>, _>::from_raw(width, height, rgba_data)
.expect("Failed to create image buffer"),
);
// Process the image
let results = process_image_ml(img);
results
}
fn process_image_ml(
img: image::DynamicImage,
) -> (
Vec<u8>,
usize,
usize,
Vec<u8>,
usize,
usize,
Vec<u8>,
usize,
usize,
) {
// Get dimensions for resized images (0ms)
let (width, height) = (img.width() as usize, img.height() as usize);
let scale_face = f32::min(640.0 / width as f32, 640.0 / height as f32);

View File

@@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
default_rust_auto_opaque = RustAutoOpaqueNom,
);
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.5.1";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1741400115;
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -804230794;
// Section: executor
@@ -68,6 +68,37 @@ fn wire__crate__api__image_processing__process_clip_impl(
},
)
}
fn wire__crate__api__image_processing__process_image_ml_from_data_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
rgba_data: impl CstDecode<Vec<u8>>,
width: impl CstDecode<u32>,
height: impl CstDecode<u32>,
) {
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::DcoCodec, _, _>(
flutter_rust_bridge::for_generated::TaskInfo {
debug_name: "process_image_ml_from_data",
port: Some(port_),
mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
},
move || {
let api_rgba_data = rgba_data.cst_decode();
let api_width = width.cst_decode();
let api_height = height.cst_decode();
move |context| {
transform_result_dco::<_, _, ()>((move || {
let output_ok = Result::<_, ()>::Ok(
crate::api::image_processing::process_image_ml_from_data(
api_rgba_data,
api_width,
api_height,
),
)?;
Ok(output_ok)
})())
}
},
)
}
fn wire__crate__api__image_processing__process_image_ml_from_path_impl(
port_: flutter_rust_bridge::for_generated::MessagePort,
image_path: impl CstDecode<String>,
@@ -154,6 +185,12 @@ fn wire__crate__api__simple__init_app_impl(port_: flutter_rust_bridge::for_gener
// Section: dart2rust
impl CstDecode<u32> for u32 {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> u32 {
self
}
}
impl CstDecode<u8> for u8 {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> u8 {
@@ -228,6 +265,13 @@ impl SseDecode
}
}
impl SseDecode for u32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
deserializer.cursor.read_u32::<NativeEndian>().unwrap()
}
}
impl SseDecode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -342,6 +386,13 @@ impl SseEncode
}
}
impl SseEncode for u32 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
serializer.cursor.write_u32::<NativeEndian>(self).unwrap();
}
}
impl SseEncode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
@@ -405,6 +456,15 @@ mod io {
String::from_utf8(vec).unwrap()
}
}
impl CstDecode<Vec<u8>> for *mut wire_cst_list_prim_u_8_loose {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> Vec<u8> {
unsafe {
let wrap = flutter_rust_bridge::for_generated::box_from_leak_ptr(self);
flutter_rust_bridge::for_generated::vec_from_leak_ptr(wrap.ptr, wrap.len)
}
}
}
impl CstDecode<Vec<u8>> for *mut wire_cst_list_prim_u_8_strict {
// Codec=Cst (C-struct based), see doc to use other codecs
fn cst_decode(self) -> Vec<u8> {
@@ -475,6 +535,18 @@ field8: Default::default(), }
wire__crate__api__image_processing__process_clip_impl(port_, image_path)
}
#[no_mangle]
pub extern "C" fn frbgen_photos_wire__crate__api__image_processing__process_image_ml_from_data(
port_: i64,
rgba_data: *mut wire_cst_list_prim_u_8_loose,
width: u32,
height: u32,
) {
wire__crate__api__image_processing__process_image_ml_from_data_impl(
port_, rgba_data, width, height,
)
}
#[no_mangle]
pub extern "C" fn frbgen_photos_wire__crate__api__image_processing__process_image_ml_from_path(
port_: i64,
@@ -503,6 +575,17 @@ field8: Default::default(), }
wire__crate__api__simple__init_app_impl(port_)
}
#[no_mangle]
pub extern "C" fn frbgen_photos_cst_new_list_prim_u_8_loose(
len: i32,
) -> *mut wire_cst_list_prim_u_8_loose {
let ans = wire_cst_list_prim_u_8_loose {
ptr: flutter_rust_bridge::for_generated::new_leak_vec_ptr(Default::default(), len),
len,
};
flutter_rust_bridge::for_generated::new_leak_box_ptr(ans)
}
#[no_mangle]
pub extern "C" fn frbgen_photos_cst_new_list_prim_u_8_strict(
len: i32,
@@ -514,6 +597,12 @@ field8: Default::default(), }
flutter_rust_bridge::for_generated::new_leak_box_ptr(ans)
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_list_prim_u_8_loose {
ptr: *mut u8,
len: i32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct wire_cst_list_prim_u_8_strict {