I am using ImageEditor package to merge different images. below is my code. its working perfectly fine without using Isolate, when i use it with isolate, i get null error.
Working code without Isolate
startEditing() async {
for (var i = 0; i < image1.length || i == 0; i++) {
if (image1.isNotEmpty) {
img1 = await File(image1[i].path).readAsBytes();
}
for (var i = 0; i < image2.length || i == 0; i++) {
if (image2.isNotEmpty) {
img2 = await File(image2[i].path).readAsBytes();
}
final ImageEditorOption optionGroup = ImageEditorOption();
optionGroup.outputFormat = const OutputFormat.png(100);
optionGroup.addOptions([
MixImageOption(
x: 0,
y: 0,
width: 1000,
height: 1000,
target: MemoryImageSource(img1),
),
MixImageOption(
x: 0,
y: 0,
width: 1000,
height: 1000,
target: MemoryImageSource(img2),
),
]);
try {
final Uint8List? result = await ImageEditor.editImage(
image: mainImg, imageEditorOption: optionGroup);
if (result == null) {
image = null;
} else {
await saveImage(result, index);
setState(() {
image = MemoryImage(result);
index++;
});
}
} catch (e) {
print(e);
}
}
}
}
Code with Isolate not working
startEditing(SendPort sendPort) async {
for (var i = 0; i < image1.length || i == 0; i++) {
if (image1.isNotEmpty) {
img1 = await File(image1[i].path).readAsBytes();
}
for (var i = 0; i < image2.length || i == 0; i++) {
if (image2.isNotEmpty) {
img2 = await File(image2[i].path).readAsBytes();
}
final ImageEditorOption optionGroup = ImageEditorOption();
optionGroup.outputFormat = const OutputFormat.png(100);
optionGroup.addOptions([
MixImageOption(
x: 0,
y: 0,
width: 1000,
height: 1000,
target: MemoryImageSource(img1),
),
MixImageOption(
x: 0,
y: 0,
width: 1000,
height: 1000,
target: MemoryImageSource(img2),
),
]);
try {
final Uint8List? result = await ImageEditor.editImage(
image: mainImg, imageEditorOption: optionGroup);
if (result == null) {
image = null;
} else {
await saveImage(result, index);
image = MemoryImage(result);
index++;
sendPort.send(image);
}
} catch (e) {
print(e);
}
}
}
}
saveImage method
Future<String> saveImage(Uint8List bytes, int i) async {
final name = '${filenames[i]}';
final result = await ImageGallerySaver.saveImage(bytes, name: name);
print(result);
return result['filePath'];
}
Receiving in main thread
getImageas() async {
ReceivePort receiverPort =
ReceivePort();
final isolate =
await Isolate.spawn(startEditing, receiverPort.sendPort);
receiverPort.listen((data) {
print('Receiving: ' + data + ', ');
});
}
I get this error:
I/flutter (21937): Null check operator used on a null value
in this line:
final Uint8List? result = await ImageEditor.editImage(
image: mainImg, imageEditorOption: optionGroup);
I am sure that img1, img2, mainImg, image1, image2 values are not null... check 1000 times. I have also used flutter compute, and same result.
Flutter plugins that call into native code (such as image_editor) do not work in isolates spawned by Isolate.spawn.
The flutter_isolate package spawns isolates from native code for this reason. You should be able to use it to call image_editor in an isolate. (Disclaimer: I've never used flutter_isolate.)
Related
so i'm new to getX package i'm trying to convert my actual app into getX.
I'm having an error that's causing my api response to say this in the console :
I/flutter ( 4915): Error 401
I/flutter ( 4915): Response Body getAllUserBikes
I/flutter ( 4915): {"statusCode":401,"error":"Unauthorized","message":"Invalid token."}
My home_page_controller.dart
class HomePageController extends GetxController{
UserController userController = Get.put(UserController());
StorageController storageController = Get.put(StorageController());
List<Bike> bikeList = [];
String query = '';
Rx<UserModel> user = UserModel().obs;
Color black = Colors.black;
Color vert = Color.fromARGB(255, 118, 157, 103);
Color petrole = Color.fromARGB(255, 32, 56, 100);
Color nocolor = Color.fromARGB(255, 155, 155, 155);
Color beige = Color.fromARGB(255, 253, 239, 206);
//Functions
Color textColor(Color backgroundColor) {
if (backgroundColor == petrole || backgroundColor == black) {
return Colors.white;
} else if (backgroundColor == beige) {
return black;
} else {
return Colors.black;
}
}
Color getColorFromString(String stringColor) {
if (stringColor == "pétrole" || stringColor == "petrole") {
return petrole;
} else if (stringColor == "noir") {
return black;
} else if (stringColor == "vert eau") {
return vert;
} else if (stringColor == "beige") {
return beige;
} else {
return nocolor;
}
}
final bicycodeDefault = [0x14, 0x22, 0x01, 0x00];
final bicycode = hex.decode(14.toString());
Future<void> initBikeList() async {
List<Bike> list = await APIBike().getAllNotFinishedBikes(jwt: user.value.jwt);
developer.log('Ma liste = ${list.toString()}');
List<Bike> maList = list;
for (int i = 0; i == list.length; i++) {
//RangeError (RangeError (index): Invalid value: Valid value range is empty: 0)
if (list[i].status == "assembling") {
maList.first = list[i];
}
bikeList = maList;
update();
}
}
init() async {
await initBikeList();
}
void onInit() {
super.onInit();
init();
//APIBle().generateBicycode();
}
void getStorage() {
user.value = UserModel.storageFromJson(storageController.getData(key: "user"));
// print(storageController.getData(key: "user"));
}
Future initStorage() async {
getStorage();
}
}
my API (only the part where it fetch all the data into a list)
Future<List<Bike>> getAllNotFinishedBikes({
required String jwt,
}) async {
var client = new http.Client();
var response = await client
.get(Uri.parse("$serverAddress/bikes?status=ne_finish"), headers: {
"Content-Type": 'application/json',
'Authorization': 'Bearer $jwt'
});
if (response.statusCode == 200) {
print("SUCCESS getAllNotFinishedBikes");
print(response);
developer.log(response.body);
print("LENGHT");
developer.log(response.body.length.toString());
var body = response.body.toString();
final List<dynamic> parsed = jsonDecode(body) as List<dynamic>;
/*print("RAW BODY");*/
print("PARSED");
print(parsed);
try {
List<Bike> listOfBikes = createBikesList(parsed);
print(parsed.length.toString() + " bike(s) scanned successfully");
return listOfBikes;
} catch (e) {
print(
"Error while trying to parse parsed json in getAllNotFinishedBikes");
print(e);
return [];
}
} else {
print("Error " + response.statusCode.toString());
print("Response Body getAllUserBikes");
print(response.body);
return []; //we return an empty list
}
}
I feel like the problem is from how i did my controller, maybe a way to make my list observable with getX ?
I can provide more codes if needed.
Thanks u all, help is appreciated !
change this line :
for (int i = 0; i == list.length; i++) {
to
for (int i = 0; i < list.length; i++) {
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
void showEvsePanels() async{
tempEvses.sort((a, b) {
int nameComp = a.sort_availability.compareTo(b.sort_availability);
if (nameComp == stationAvailability.available.index) {
return a.distance.compareTo(b.distance); // '-' for descending
}
return nameComp;
});
setState(() {
if (evseSearchField.isEmpty){
int i = 0;
if (tempEvses.length != 0){
evsePanels.clear();
while (i < tempEvses.length){
evsePanels.add(new EvsePanel(tempEvses[i], widget.appController, false));
i++;
}
}
}
else{
int i = 0;
if (tempEvses.length != 0){
evsePanels.clear();
while (i < tempEvses.length){
if (containsIgnoreCase(tempEvses[i].friendlyName, evseSearchField))
evsePanels.add(new EvsePanel(
tempEvses[i], widget.appController, false));
i++;
}
}
}
});
}
List<Evse> tempEvses = [];
Future fetch() async {
if (isLoading) return;
isLoading = true;
const limit = 10;
final url = Uri.parse('https://everywhere-dev.iccs.gr:18083/evse/getEvsesPaged?page=$page&pageLimit=$limit');
final response = await http.get(url);
if (response.statusCode == 200) {
final List newItems = json.decode(response.body)["results"];
setState(() {
page++;
isLoading = false;
if (newItems.length <limit) {
hasMore = false;
}
tempEvses.addAll(newItems.map<Evse>((items) {
final evseID = items['evseID'];
final friendlyName = items['friendlyName'];
final street = items['street'];
final streetNumber = items['streetNumber'];
final region = items['region'];
final lat = items['lat'] ?? 0.0;
final lng = items['lng'] ?? 0.0;
final connectorList = items['connectorList'];
final cpSerial = items['cpSerial'];
final img = items['img'];
return new Evse(evseID: evseID, friendlyName: friendlyName, street: street, streetNumber: streetNumber, region: region, lat: lat, lng: lng, connectorList: [connectorList], cpSerial: cpSerial, img: img);
}).toList());
for(int i=0 ; i<tempEvses.length; i++ ){
this.tempEvses[i].calculateDistance(widget.appController.currentLocation);
// this.tempEvses[i].calculateAvailability();
this.tempEvses[i].isEvseFavorite(widget.appController.favoritesList);
this.tempEvses[i].storePlugCounters();
}
showEvsePanels();
});
}
}
i have live text recognition i used library https://pub.dev/packages/google_mlkit_text_recognition and https://pub.dev/packages/camera,
but i have some problem...
i need detect text only in marked part...
Get live preview function:
//
Future _processCameraImage(CameraImage image) async {
final WriteBuffer allBytes = WriteBuffer();
for (final Plane plane in image.planes) {
allBytes.putUint8List(plane.bytes);
}
final bytes = allBytes.done().buffer.asUint8List();
final Size imageSize =
Size(image.width.toDouble(), image.height.toDouble());
//
final camera = cameras[_cameraIndex];
final imageRotation =
InputImageRotationValue.fromRawValue(camera.sensorOrientation) ??
InputImageRotation.rotation0deg;
final inputImageFormat =
InputImageFormatValue.fromRawValue(image.format.raw) ??
InputImageFormat.nv21;
final planeData = image.planes.map(
(Plane plane) {
return InputImagePlaneMetadata(
bytesPerRow: plane.bytesPerRow,
height: plane.height,
width: plane.width,
);
},
).toList();
//
final inputImageData = InputImageData(
size: imageSize,
imageRotation: imageRotation,
inputImageFormat: inputImageFormat,
planeData: planeData,
);
final inputImage =
InputImage.fromBytes(bytes: bytes, inputImageData: inputImageData);
//
widget.onImage(inputImage);
}
Processing image function:
//
Future<void> processImage(InputImage inputImage) async {
if (!_canProcess) return;
if (_isBusy) return;
_isBusy = true;
final recognizedText = await _textRecognizer.processImage(inputImage);
//
if (mounted) {
for (var element in recognizedText.blocks) {
for (var line in element.lines) {
for (var txt in line.elements) {
if (txt.text.length == 17) {
setState(() {
_text = txt.text;
});
}
}
}
}
}
_isBusy = false;
}
}
I had a similar task, I used the module mask_for_camera_view
create your own frame and find the values of the cropped picture
more details & photo example in github
I'm retrieving data from Firebase Storage and Firestore, to show the items in a list with the icon (if the item is a file) or the image (if is image). The problem is, If I get all the images in one time it doesn't load all.. It loads at maximum 20 and crashes due to memory leaking. So My idea is to do a list which gets 10 elements by time, and when the user scroll down to the bottom of the results, it loads more 10 and subsequently. But, I was using Future builder and with it I cant update the list when I need and the problem continues, so now, I'm trying to get in a stream and show with a StreamBuilder to be able to update the list dynamically.
this is my controller:
loadList(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
for(int i = 0; i < retorno.items.length ; i++){
var url = await retorno.items[i].getDownloadURL();
conteudo.add(
ItemLab(
tipo: 'FILE',
elemento: retorno.items[i],
imageUrl: url,
),
);
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("less than 9");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
});
for(int i = 0; i < items.length; i ++){
//print(items[i]);
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: items[i],
),
);
}
}else{
await databaseReference
.collection("lab_${pathSlashless}_url")
.snapshots().forEach((element) {
element.docs.forEach((f) {
if(f.data().isNotEmpty){
print(f.data());
if(f.data().keys.contains("videos")){
conteudo.add(
ItemLab(
tipo: 'PASTA',
pastaVideo: findFolderName(f.reference.path)
),
);
}else{
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: f.data(),
),
);
}
}
});
});
}
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
return Stream.value(conteudo);
}
And here my list:
return StreamBuilder(
stream: ctrl.loadList(submenu),
builder: (ctx, snapshot) {
But, if I run this code it throws this error:
type 'Future' is not a subtype of type 'Stream'
How Can I handle that to be able to update the list dynamically using a stream instead of a Future
You can't await .snapshots(), as it returns stream, you can change it to get. Also learn more about flutter firebase realtime and normal use case, check the flutter fire docs
loadList(String submenu, [int limit]) async {
var parts = submenu.split('/');
var pathSlashless = parts[0].trim();
var subPathSlashless = parts.sublist(1).join('/').trim();
var snapshot = await _storage.ref().child("/${submenu}");
var retorno = await snapshot.listAll();
List<ItemLab> conteudo = [];
if(subPathSlashless.isEmpty || subPathSlashless == null){
retorno.prefixes.forEach((element) {
conteudo.add(
ItemLab(
tipo: 'PASTA',
elemento: element,
),
);
});
}
for(int i = 0; i < retorno.items.length ; i++){
var url = await retorno.items[i].getDownloadURL();
conteudo.add(
ItemLab(
tipo: 'FILE',
elemento: retorno.items[i],
imageUrl: url,
),
);
if(limit != null){
if(conteudo.length > limit){
hasMore = true;
return Stream.value(conteudo);
}else{
hasMore = false;
print("less than 9");
}
}
}
try {
if(subPathSlashless.isNotEmpty){
print(subPathSlashless);
List items;
(await databaseReference
.collection("lab_${pathSlashless}_url")
.get()).docs.forEach((f) {
if(f.data()['videos'] != null){
items == null ? items = f.data()['videos'] :
items.addAll(f.data()['videos']);
};
print("ITEMS :::: >>> ${items}");
});
for(int i = 0; i < items.length; i ++){
//print(items[i]);
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: items[i],
),
);
}
}else{
(await databaseReference
.collection("lab_${pathSlashless}_url")
.get()).docs.forEach((f) {
if(f.data().isNotEmpty){
print(f.data());
if(f.data().keys.contains("videos")){
conteudo.add(
ItemLab(
tipo: 'PASTA',
pastaVideo: findFolderName(f.reference.path)
),
);
}else{
conteudo.add(
ItemLab(
tipo: 'VIDEO',
elemento: null,
video: f.data(),
),
);
}
}
});
}
}catch(e){
print(e);
}
pathSlashless = null;
subPathSlashless = null;
conteudo = checkDuplicateFolder(conteudo, submenu);
return conteudo;
}
And the list
return FutureBuilder(
future: ctrl.loadList(submenu),
builder: (ctx, snapshot) {
I want to send multiple string values from one smartphone device to another device via Bluetooth in flutter. I have seen flutter_blue and flutter_bluetooth_searial package examples also but i cant find anything that sends multiple strings values via Bluetooth. can anyone please suggest how i can be able to achieve this task?
I used flutter_bluetooth_searial in one of my projects, here is the the whole class including: sending data (multiple strings), receiving data, connect, disconnect, auto-pairing, ...etc
Hope you find this helpful.
import 'dart:async';
import 'dart:typed_data';
import 'dart:convert' show utf8;
import 'package:flutter/foundation.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
class BluetoothStore extends ChangeNotifier {
var _instance = FlutterBluetoothSerial.instance;
var _dataBuffer = '';
void Function(String) _onDataCallback = (String data) {};
StreamSubscription<Uint8List> _dataSubscription;
StreamSubscription<BluetoothDiscoveryResult> _scannedDevicesSubscription;
BluetoothDiscoveryResult _connectedDevice;
BluetoothConnection _connection;
var name = "...";
var address = "...";
var pinNum = "1234";
var isScanning = false;
var _isConnecting = false;
var _autoPair = false;
var scannedDevices = List<BluetoothDiscoveryResult>();
var state = BluetoothState.UNKNOWN;
BluetoothStore() {
initBluetooth();
}
bool get autoPair => _autoPair;
bool get isConnecting => _isConnecting;
bool get isConnected => _dataSubscription != null;
set autoPair(bool value) {
_autoPair = value;
if (value) {
_instance.setPairingRequestHandler((request) {
if (request.pairingVariant == PairingVariant.Pin)
return Future.value(pinNum);
return Future.value("");
});
} else {
_instance.setPairingRequestHandler(null);
}
notifyListeners();
}
void initBluetooth() async {
// Get bluetooth initial state
this.state = await _instance.state;
this.address = await _instance.address;
this.name = await _instance.name;
notifyListeners();
_instance.onStateChanged().listen((state) {
this.state = state;
_reset();
});
}
Future<bool> pairWith(BluetoothDevice device) async {
var pairedDevices = await _instance.getBondedDevices();
if (pairedDevices.length < 7) {
var result = await _instance.bondDeviceAtAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.bonded : BluetoothBondState.none,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
return Future.value(false);
}
// Notice the return value
Future<bool> unpairFrom(BluetoothDevice device) async {
var result = await _instance.removeDeviceBondWithAddress(device.address);
if (result) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
type: device.type,
bondState:
result ? BluetoothBondState.none : BluetoothBondState.bonded,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
}
return Future.value(result);
}
Future<bool> enable() => _instance.requestEnable();
Future<bool> disable() => _instance.requestDisable();
Future<void> openSettings() => _instance.openSettings();
Future<bool> connectTo(BluetoothDevice device) async {
_isConnecting = true;
if (isConnected) await _connection.close();
notifyListeners();
try {
var connection = await BluetoothConnection.toAddress(device.address);
_isConnecting = false;
_connection = connection;
_dataSubscription = connection.input.listen(_onDataReceived);
_dataSubscription.onDone(_onDisconnect);
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == device.address;
});
_connectedDevice = scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: device.name ?? '',
address: device.address,
bondState: device.bondState,
type: device.type,
isConnected: true,
),
rssi: scannedDevices[deviceIndex].rssi,
);
notifyListeners();
return Future.value(true);
} catch (_) {
_isConnecting = false;
_dataSubscription = null;
_connection = null;
notifyListeners();
return Future.value(false);
}
}
Future<List<BluetoothDevice>> pairedDevices() async {
var result = await _instance.getBondedDevices();
return Future.value(result);
}
void disConnect() async {
if (isConnected) {
this.unpairFrom(_connectedDevice.device);
_connection.dispose();
}
}
void startScanning() {
isScanning = true;
scannedDevices.clear();
notifyListeners();
if (isConnected) scannedDevices.add(_connectedDevice);
_scannedDevicesSubscription = _instance.startDiscovery().listen((device) {
scannedDevices.add(device);
});
_scannedDevicesSubscription.onDone(() async {
isScanning = false;
notifyListeners();
});
}
void _onDataReceived(Uint8List data) {
// Allocate buffer for parsed data
var backspacesCounter = 0;
data.forEach((byte) {
if (byte == 8 || byte == 127) backspacesCounter++;
});
var buffer = Uint8List(data.length - backspacesCounter);
var bufferIndex = buffer.length;
// Apply backspace control character
backspacesCounter = 0;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i] == 8 || data[i] == 127) {
backspacesCounter++;
} else {
if (backspacesCounter > 0) {
backspacesCounter--;
} else {
buffer[--bufferIndex] = data[i];
}
}
}
// Create message if there is new line character
var dataString = String.fromCharCodes(buffer);
var index = buffer.indexOf(13);
if (~index != 0) {
// \r\n
var data = backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer = _dataBuffer + dataString.substring(0, index);
_onDataCallback(data);
_dataBuffer = dataString.substring(index);
} else {
_dataBuffer = (backspacesCounter > 0
? _dataBuffer.substring(0, _dataBuffer.length - backspacesCounter)
: _dataBuffer + dataString);
}
}
void _onDisconnect() {
// reset
if (this.state == BluetoothState.STATE_ON) {
var deviceIndex = scannedDevices.indexWhere((scannedDevice) {
return scannedDevice.device.address == _connectedDevice.device.address;
});
scannedDevices[deviceIndex] = BluetoothDiscoveryResult(
device: BluetoothDevice(
name: _connectedDevice.device.name ?? '',
address: _connectedDevice.device.address,
type: _connectedDevice.device.type,
bondState: _connectedDevice.device.bondState,
),
rssi: _connectedDevice.rssi,
);
}
_reset();
}
void _reset() {
_dataBuffer = '';
_isConnecting = false;
_dataSubscription = null;
_scannedDevicesSubscription = null;
_connectedDevice = null;
_connection = null;
if (this.state != BluetoothState.STATE_ON) {
scannedDevices.clear();
}
notifyListeners();
}
void onDataReceived(void Function(String) callback) {
_onDataCallback = callback;
}
bool sendData(String data) {
try {
data = data.trim();
if (data.length > 0 && isConnected) {
_connection.output.add(utf8.encode(data + "\r\n"));
return true;
}
} catch (e) {
return false;
}
return false;
}
void dispose() {
_instance.setPairingRequestHandler(null);
if (isConnected) _dataSubscription.cancel();
_scannedDevicesSubscription?.cancel();
super.dispose();
}
}
You can consume this class using ChangeNotifierProvider
ChangeNotifierProvider<BluetoothStore>.value(value: BluetoothStore())