I try to call the tesseract C api within flutter. So far without success. The function "TessBaseAPIInit3" requires the 2nd and 3rd parameter to be of type Pointer<Char>. The following is what dart run ffigen generated out of tesseract's capi.h:
import 'dart:ffi' as ffi;
...
int TessBaseAPIInit3(
ffi.Pointer<TessBaseAPI> handle,
ffi.Pointer<ffi.Char> datapath,
ffi.Pointer<ffi.Char> language,
) {
return _TessBaseAPIInit3(
handle,
datapath,
language,
);
}
late final _TessBaseAPIInit3Ptr = _lookup<
ffi.NativeFunction<
ffi.Int Function(ffi.Pointer<TessBaseAPI>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>>('TessBaseAPIInit3');
late final _TessBaseAPIInit3 = _TessBaseAPIInit3Ptr.asFunction<
int Function(ffi.Pointer<TessBaseAPI>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>)>();
The following is my code which calls TessBaseAPIInit3 which requires 3 parameters of type Pointer<TessBaseAPI>, Pointer<Char>, Pointer<Char>. The string literals i create with toNativeUtf8 have type Pointer<Utf8> which i cast to Pointer<Char> in the hope that they are equivalent. But the cast from Pointer<Utf8> to Pointer<Char> gives an error.
import 'dart:ffi';
...
final DynamicLibrary tesseractDLL = DynamicLibrary.open(Platform.script.resolve("build/windows/runner/Debug/libtesseract-5.dll").toFilePath());
NativeLibrary tesseractLib = NativeLibrary(tesseractDLL);
final handle = tesseractLib.TessBaseAPICreate();
final Pointer<Char> dataPath = ''.toNativeUtf8() as Pointer<Char>;
final Pointer<Char> language = 'eng'.toNativeUtf8() as Pointer<Char>;
if (tesseractLib.TessBaseAPIInit3(handle, dataPath, language) != 0)
print("Error initializing tesseract\n");
The error message is: [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'Pointer<Utf8>' is not a subtype of type 'Pointer<Char>' in type cast
Any ideas what goes wrong? I have no idea how to create a string literal of type Pointer<Char>. The function 'toNativeUtf8' generates Pointer<Utf8>.
Is this "the right way" to call tesseract functions? Is it possible to use the c++ api anyhow? I don't want to use any wrapper, i would like to interact with the tesseract api directly.
Following did the trick. The native utf8 string needed to be cast to Char.
final dataPath = ''.toNativeUtf8().cast<Char>();
final language = 'eng'.toNativeUtf8().cast<Char>();
Related
I'm new to flutter?
Can someone explain to me what the following line of code means?
typedef RecoverCallback = Future<String?>? Function(String);
This line is contained in the auth.dart file of the flutter_login plugin
https://github.com/NearHuscarl/flutter_login/blob/master/lib/src/providers/auth.dart
So Function(String) Where is it implemented?
typedef RecoverCallback = Future<String?>? Function(String);
It's function-type alias, gives a function type a name that you can use when declaring fields and return types.
As you can see in 45 line of class Auth implementation, that function you need to pass to the constructor of
new Auth(onRecoverPassword: yourFunction);
yourFunction must be a Function that take some String parameter and return Future<String?> or null;
The reason I want to understand the above line of code is because
final error = await auth.onRecoverPassword!(auth.email);
error = null;
but no mail is sent to auth.email.
This post is a duplicate of the Github Issue here.
dart --version
Dart SDK version: 2.15.0-116.0.dev (dev) (Thu Sep 16 09:47:01 2021 -0700) on "linux_x64"
I've been looking up examples for callbacks and I have tried to get callbacks working for me in FFI.
My current situation
I have a function in my library which expects a pointer to a function. The bindings for the same generated by ffigen seem correct to me.
int SetCallback(
CallbackType callback,
) {
return _SetCallback(
callback,
);
}
late final _SetCallbackPtr =
_lookup<NativeFunction<Int32 Function(CallbackType)>>(
'SetCallback');
late final _SetCallback =
_SetCallbackPtr.asFunction<int Function(CallbackType)>();
where, typedef CallbackType = Pointer<NativeFunction<Void Function(Uint32)>>;.
What I want to do here is to setup this callback in Dart, pass it to the FFI, essentially using it as my callback as I would have in C. In my API which abstracts away from FFI code (which means I have a class MyLibrary full of static functions that the user will call directly, which in turn calls functions from an object _nativeLibrary of the class MyNativeLibrary I have created), I have:
static int SetCallback({required CallbackFuncDart callback}) {
Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);
int status = _nativeLibrary.SetCallback(
pointer,
);
if (STATUS_OK != status) {
throw LibLexemeException(status);
}
return status;
}
typedef CallbackFunc = Void Function(Uint32);
typedef CallbackFuncDart = void Function(int);
While the sqlite ffi example states here that
Features which dart:ffi does not support yet:
Callbacks from C back into Dart.
I believe the docs haven't been updated to reflect the changes at the samples here. The samples haven't been very clear due to them not having any C/C++ files, or an idea of how the C functions work. Even so, I think this example contains a segment(last code block) where a Dart function is being passed as a callback which I have replicated in my program. It is not clear to me how this will work but upon trying to compile my program I get:
ERROR: ../lib/library_lexeme.dart:180:74: Error: fromFunction expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code. Closures and tear-offs are not supported because they can capture context.
ERROR: Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);
The short version is that you can't pass your callnback as an argument:
static int SetCallback({required CallbackFuncDart callback}) {
Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback); // <-- this isn't considered a static function
It's quite annoying but you must use a static function defined ahead of time for your dart callbacks to be called from C.
Apparently for now only static functions can be passed via ffi. But if you have to access an instance's data and you're sure that the instance exists you can use my workaround. I use a static list to the instances. This is stupid and ugly but it works for me:
class CallbackClass {
static Int8 classCallback(int id) {
final instance = instanceList[id];
return instance.instanceCallback();
}
Int8 instanceCallback() { return instanceId; }
static List<CallbackClass> instanceList = <CallbackClass>[];
late final int instanceId;
CallbackClass {
instanceId = instanceList.length;
instanceList.insert(instanceId, this);
myFFImapping.passCallback(instanceId, Pointer.fromFunction<>(classCallback);)
}
}
I omitted the necessary c code, FFI mapping and casting to correct types for clarity, so it obviously won't compile like this.
APIs:
https://www.nseindia.com/api/option-chain-indices?symbol=NIFTY
https://www.nseindia.com/api/option-chain-indices?symbol=BANKNIFTY
API Call Method:
import 'package:http/http.dart';
import '../Models/fetched_data.dart';
Future<FetchedData?> fetchIndexDetails(String index) async {
final String url =
'https://www.nseindia.com/api/option-chain-indices?symbol=$index';
try {
final response = await get(
Uri.parse(url),
);
final FetchedData? fetchedData = fetchedDataFromJson(response.body);
return fetchedData;
} catch (e) {
print('$index Error: $e');
}
return null;
}
The json file is same for both the APIs, hence the model class too.
However, the second API call works smoothly but the first API call throws an error saying:
type 'double' is not a subtype of type 'int?'
Can anybody help me decode the problem here? Much tia :)
This is a JSON parsing issue for unmatched type parsing of the API and the your Dart Model ..
How to diagnose it?
You can always catch those errors while the development by enabling the dart debugger for uncaught exceptions, which gives you exactly the broken casting
type 'double' is not a subtype of type 'int?'
The API has returned a double value where an int is expected.
In your model or where appropriate replace the expected type to use num which int and double are both subtypes of
Check your model class where you have defined different variables and match with data type you are getting in response from the json.
There must be a variable you have defined in model class as int? but u r getting double as a response so u got to convert the data type .
Seems like you are trying to map a double to int?, the response had a double and you are assigning it to int?, add a breakpoint when mapping the response to see the corresponding field. You can try casting it to int or just changing the type all together.
I have the following code in dart, which decodes a string into a JSON object.
import 'dart:convert';
void main(){
var stringValue = "{\"last_supported\": \"2.00\", \"current\": \"2.00\"}";
var newValue = json.decode(stringValue);
print(newValue["last_supported"]);
}
The above code works fine, but when I change print statement to:
print(newValue.last_supported);
It gives me the following exception:
Uncaught TypeError: C.C_JsonCodec.decode$1(...).get$last_supported is not a function
Is it possible to use dot annotation to access properties, and how?
I'm guessing you come from a java-script background.
in dart object keys cannot be accessed through the . dot notation.
rather they are accessed like arrays with ['key_name'].
so that's why this line doesn't work
print(newValue.last_supported)
and this one does
print(newValue["last_supported"]);
dot notation in dart only works on class instances, not Map (similar to JavaScript objects).
look at the following :
class User {
final String name;
final int age;
// other props;
User(this.name, this.age);
}
Now when you create a new user object you can access its public attributes with the dot notation
final user = new User("john doe", 20); // the new keyword is optional since Dart v2
// this works
print(user.name);
print(user.age);
// this doesn't work because user is an instance of User class and not a Map.
print(user['name]);
print(user['age]);
For more about the new keyword you can read the v2 release notes here.
I have the following class in my code
abstract class DatabaseKey<T> implements Built<DatabaseKey<T>, DatabaseKeyBuilder<T>> {
DatabaseKey._();
factory DatabaseKey([void Function(DatabaseKeyBuilder<T>) updates]) = _$DatabaseKey<T>;
String get name;
}
Then, I define the following generic typedef function:
typedef ObserveDatabaseEntity = Observable<DatabaseEntity<T>> Function<T>(DatabaseKey<T> key);
But, when I try to use it as follows, the code has an error.
static ObserveConfigurationValue observe(
GetConfigurationState getState,
ObserveDatabaseEntity observeDatabaseEntity,
) {
assert(getState != null);
assert(observeDatabaseEntity != null);
return <KT>(ConfigKey<KT> key) {
return Observable.just(getState())
.flatMap((state) {
final dbKey = _databaseKeyFromConfig<KT>(key);
return observeDatabaseEntity(dbKey)
.map(_configValueFromDatabaseEntity);
});
}
}
DatabaseKey<T> _databaseKeyFromConfig<T>(ConfigKey<T> key) {
return DatabaseKey((build) => build
..name = key.value,
);
}
The error I am getting is:
The argument type DatabaseKey can't be assigned to the parameter DatabaseKey.
I see nothing wrong with this code or why it shouldn't work, but maybe my understanding of what can be written in Dart is wrong. What would be the correct way to write this, if possible at all?
EDIT#1:
Note:
The typedef ObserveDatabaseEntity is in one file
The static ObserveConfigurationValue observe(GetConfigurationState getState, ObserveDatabaseEntity observeDatabaseEntity) is is another file
From playing around, it seems that placing them in a single file, the error disappears.
Still, I believe that this should work in separate files as well,
This error looks like an import mismatch.
In dart, you can import file either through relative path or package.
import 'lib/some_file.dart'; //relative
import 'package:myapp/lib/some_file.dart'; //package
There's really no better way but once you choose one, you have to stick to it. If you don't (meaning you have imported a file using a package import and the same file elsewhere with a relative path) Dart will place them in two different namespaces and think they are two different classes.