Failed assertion: line 854 pos 14: 'file != null': is not true - flutter

I'm trying to display an image using FileImage() but it's throwing the "'file != null': is not true" error. The image is coming from an Image Picker function. The wierd thing is that, I know that the file exists because when I try to print it, it shows me the path for the file.
EDIT: Here's the link to the entire code if you need to check it:
https://github.com/MBanawa/ecommerce_app/blob/master/lib/Admin/uploadItems.dart
Below is the function for the ImagePicker with a print method:
File imageFile;
pickImage(ImageSource imageSource) async {
Navigator.pop(context);
final pickedFile = await ImagePicker().getImage(source: imageSource);
setState(() {
imageFile = File(pickedFile.path);
print('Path $imageFile');
});
}
I trigger the function in an onPressed() by either camera or gallery :
camera:
onPressed: () => pickImage(ImageSource.camera),
gallery
onPressed: () => pickImage(ImageSource.gallery),
Below is how I call the imageFile:
Container(
height: 230.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(imageFile),
fit: BoxFit.cover,
),
),
),
),
),
),
The container above is inside a function called displayAdminUploadFormScreen() that gets called if imageFile is not null. I place that after the build method of my statefulwidget state:
#override
Widget build(BuildContext context) {
return imageFile == null
? displayAdminHomeScreen()
: displayAdminUploadFormScreen();
}
What I'm confused about is that, print() returns an actual link after taking a picture. here is a sample result when taking a picture using the camera:
I/flutter (16227): Path File: '/storage/emulated/0/Android/data/com.example.ecommerceapp/files/Pictures/068e58d6-88af-4b13-9453-c8c8d836083c5388058709499582194.jpg'
the exact error massage was:
The following assertion was thrown building UploadPage(dirty, dependencies:
[MediaQuery, _InheritedTheme, _LocalizationsScope-[GlobalKey#71a32]], state: _UploadPageState#0a649):
'package:flutter/src/painting/image_provider.dart': Failed assertion: line 854 pos 14: 'file !=
null': is not true.
When checking the links that that error gave, it points to FileImage(imageFile). If I open up FileImage, line 854 pos 14 is an assertion:
const FileImage(this.file, { this.scale = 1.0 })
: assert(file != null),
assert(scale != null);
I also tried the traditional way of creating an ImagePicker function. (the one in pub.dev) but it's still showing the same error. Any guidance will be much appreciated. Thank you!

it's because you are making a call of clearFormInfo() function inside IconButton widget. I believe that you wanted to call this function inside callback onPressed property.
So instead of:
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: clearFormInfo(),
)
Please use:
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
onPressed: () {
clearFormInfo();
},
),

You need to check if the imageFile is null. If it is, then you can use a simple Container until imageFile is not null. Try something like this:
Container(
height: 230.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: imageFile != null // Here is important!
? Container(
decoration: BoxDecoration(
image: DecorationImage(
image: FileImage(imageFile),
fit: BoxFit.cover,
),
),
)
: Container(),
),
),
),

displayAdminUploadFormScreen() is a function and not a widget right?
So does this function can get the value of imageFile correctly?
Try to print the imageFile at the start of this function, to check if you get the image path correctly.
displayAdminUploadFormScreen(){
print(imagePath);
.
// rest of code
.
}
If the result is null, then then you might need to pass the imageFile
displayAdminUploadFormScreen(File imageFile){
print(imagePath);
.
// rest of cocde
.
}
and
#override
Widget build(BuildContext context) {
return imageFile == null
? displayAdminHomeScreen()
: displayAdminUploadFormScreen(imageFile);
}

Have you set the permissions inside Info.plist and AndroidManifest.xml files?
Inside **/path/to/project/android/app/src/[debug/main/profile] you need to put something like
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Inside **/path/to/project/ios/Runnmer/Info.plist you need to put something like
<key>NSCameraUsageDescription</key>
<string>camera</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your photos for this</string>
I'm not 100% sure on the Android one as I haven't developed for Android yet, but i'm sure that's true of the iOS version.

Related

PlatformException(multiple_request, Cancelled by a second request, null, null) in imagePicker

I am using a riverpod provider class to handle picking of image from gallery. However, once an image is picked, I get the error: PlatformException(multiple_request, Cancelled by a second request null, null). Not sure where a second request is coming from. More importantly, no image is applied to my placeholder (CircleAvartar) due to this unknown cancellation.
Here are the two dart files in question and thanks for the help.
imageProvider file:
final myImageProvider =
ChangeNotifierProvider<ImageNotifier>((ref) => ImageNotifier());
class ImageNotifier extends ChangeNotifier {
ImageNotifier() : super();
final file = useState<File?>(null);
final imageFile = useState<XFile?>(null);
final imagePicker = ImagePicker();
Future<void> _pickImage(int type) async {
try {
XFile? userImage = await imagePicker.pickImage(
source: type == 1 ? ImageSource.gallery : ImageSource.camera,
imageQuality: 50,
);
imageFile.value = userImage;
// imageFile.value = XFile(userImage!.path);
} catch (e) {
print(e);
}
notifyListeners();
}
void showPicker(context) {
showModalBottomSheet(
backgroundColor: Theme.of(context).primaryColor,
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Wrap(
children: [
ListTile(
leading: const Icon(
Icons.photo_library,
color: Colors.white,
),
title: const Text(
'Photo Gallery',
style: TextStyle(fontSize: 22),
),
onTap: () => _pickImage(1),
),
ListTile(
leading: const Icon(
Icons.photo_camera,
color: Colors.white,
),
title: const Text(
'Camera',
style: TextStyle(fontSize: 22),
),
onTap: () => _pickImage(2),
),
ListTile(
leading: const Icon(
Icons.close,
color: Colors.white,
),
title: const Text(
'Cancel',
style: TextStyle(fontSize: 22),
),
onTap: () {
imageFile.value = null;
Navigator.of(context).pop();
},
),
],
),
);
},
);
notifyListeners();
}
AuthScreen dart file:
Widget build(BuildContext context, WidgetRef ref) {
final _passwordController = useTextEditingController();
final _passwordFocusScope = useFocusNode();
final _emailFocusScope = useFocusNode();
final _phoneFocusScope = useFocusNode();
final _confirmFocusScope = useFocusNode();
final _isVisible = useState<bool>(true);
var _authMode = useState<AuthMode>(AuthMode.login);
final imageProviderState = ref.watch(myImageProvider.notifier);
final deviceSize = MediaQuery.of(context).size;
final authMode = ModalRoute.of(context)?.settings.arguments as String;
switch (authMode) {
case 'login':
_authMode.value = AuthMode.login;
break;
case 'register':
_authMode.value = AuthMode.register;
break;
case 'google':
_authMode.value = AuthMode.google;
break;
case 'guest':
_authMode.value = AuthMode.guest;
break;
}
return Scaffold(
body: Stack(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(
height: 80,
),
Center(
child: _authMode.value == AuthMode.login
? const Text(
'Access Your Account',
style: TextStyle(
fontSize: 25,
),
)
: Row(
children: [
InkWell(
onTap: () =>
imageProviderState.showPicker(context),
// () => ref
// .read(myImageProvider.notifier)
// .showPicker(context),
child: CircleAvatar(
radius: 50,
backgroundImage:
imageProviderState.imageFile.value !=
null
? FileImage(
// File(ref
// .read(imageProvider.notifier)
// .imageFile
// .value!
// .path),
// )
File(imageProviderState
.imageFile.value!.path),
)
: null,
child: imageProviderState.imageFile.value ==
null
? const Icon(
Icons.camera,
// Icons.add_photo_alternate,
size: 30,
color: Colors.white,
)
: null,
),
),
After testing the code on a real device (iPhone and Android) I was able to select and attach a photo from gallery and camera to my form. The issue is with trying to do this task on a simulator even though one was able to do so once upon a time. Don't even bother anymore until Apple fixes this trouble. My advice is that you debug on a real device to ensure things are working as coded and you can return to the simulator/emulator afterwards. I lost a lot of time trying to make tis work on a simulator to no avail.
I have the latest Flutter 3.3.9 and Xcode 14.1 and this is still a problem. The workaround is very simple though after reading this issue. When using the image_picker, DO NOT pick the first image (with pink flowers):
In addition to my earlier answer and further tweaking with the dev in simulator environment, I just discovered that the uploaded image does show up upon a reload/restart. Weird but works if you must test in simulation mode. Simply restart and the uploaded image will show up. It is still a simulator issue though, IMHO.
It can help to double-click on the image you are selecting from the gallery instead of clicking only once.
For whatever reason, if I clicked only once, it would not show up and the same error as yours appeared.
If I clicked twice there was a short lag, but the image showed up.
Tested on iOS simulator - don't get this issue personally on my Android emulator.
I had this issue picking one of the default album images on my iOS simulator.
I was able to get around this by going to Safari, saving a png to Photos and then selecting that downloaded png in my Flutter app.
Thanks to Marc's post which pointed me in the right direction regarding HEIC support
Hi please have a look at this discussion:
https://github.com/flutter/flutter/issues/70436
on on the image picker package site we can see that it is a well known apple simulator issue. I would say that it should work for you on real devices (or try to test it only with particular pictures from iOS simulator photos)
Make sure ALLOW PHOTO ACCESS permission is set to either Selected Photos or All Photos. In my case, I had denied the permission so there was no error log on the console and the image picker was not opening.
PS I know it's not directly related to the SO's question but might be helpful if someone comes across this.
Don't bother about this issue much. This is just a simulator issue(mostly on iOS). Testing this on a real device is advisable.
I think it because it using 'pickimage' instead of 'pickMultiImage', so u are only allow to pick 1 image at a time, try to make ur 'imageFile' to null first before you pick another image.

Flutter Exception: Invalid image data

I am working on a Flutter application that uploads to and gets data from PostgreSQL Database.
I am using postgres: ^2.3.2 in pubspec.yaml file.
First, I am converting the image to base64.
And then, I am uploading the image to the database as BYTEA.
And when I query the image data from the database, it provides me with an integer list.
I searched the web, and found that I had to convert that list to Uint8List.
After converting it to Uint8List, I have to use the Image.memory method to convert the Uint8List to an image widget.
But when I do so, I get this error on the Debug Console:
═══════ Exception caught by image resource service ════════════════════════════
The following _Exception was thrown resolving an image codec:
Exception: Invalid image data
When the exception was thrown, this was the stack
#0 _futurize (dart:ui/painting.dart:5326:5)
#1 ImageDescriptor.encoded (dart:ui/painting.dart:5194:12)
#2 instantiateImageCodec (dart:ui/painting.dart:2048:60)
<asynchronous suspension>
════════════════════════════════════════════════════════════════════════════════
And this image on the device:
Device screenshot
The code is below:
import 'dart:typed_data';
import 'package:flutter/material.dart';
class ShowImage extends StatefulWidget {
const ShowImage({Key? key}) : super(key: key);
#override
_ShowImageState createState() => _ShowImageState();
}
class _ShowImageState extends State<ShowImage> {
dynamic _image;
Map data = {};
void setImage() async {
GetImage getImgObj = GetImage(connection: data['connection']);
dynamic imgBytes = await getImgObj.getImage();
print(imgBytes.runtimeType);
setState(() {
_image = Image.memory(imgBytes);
});
}
#override
Widget build(BuildContext context) {
data = ModalRoute.of(context)!.settings.arguments as Map;
// setImage();
return Scaffold(
appBar: AppBar(
title: Text("Show Image"),
centerTitle: true,
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: () {
setImage();
},
child: Text("Get Image"),
),
SizedBox(height: 10.0),
Container(
width: 100,
height: 350,
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: _image == null
? Align(
alignment: Alignment.center,
child: Text(
"Image not selected",
textAlign: TextAlign.center,
),
)
: Align(
alignment: Alignment.center,
child: _image,
),
),
],
),
),
),
);
}
}
class GetImage {
var connection;
GetImage({this.connection});
Future<dynamic> getImage() async {
int itemId = 1;
String query = "SELECT img FROM lawbreach WHERE lid = $itemId;";
List<dynamic> results = await this.connection.query(query);
final bytes = Uint8List.fromList(results[0][0]);
return bytes;
}
}
I tried searching every corner of the web, but couldn't find any solution.
Hope, someone here has an answer to my question :)
The reason why the Image widget throws an "Invalid image data" Exception is because the base64 that you're trying to load is invalid. You need to check if the encoded base64 image that you've downloaded is being encoded to base64 again. Decode the downloaded base64 encoded image before loading it to the widget.
Uint8List _imageBytesDecoded = base64.decode(encodedImage);
...
Image.memory(_imageBytesDecoded)
How I solved my own, I extracted the image because it was in zip folder and go to pubspect.yaml assets: - images/image_22.jpg then in my widget I then added child: Image.asset('images/image_22.jpg')

Show picture from assets or from files Flutter

I want to show a picture inside a CircleAvatar, if the user never inserted a picture before then the default picture "empty_profile.png" will appear, otherwise if the user already inserted a picture from gallery or camera then the last one will be shown.
This is the code :
File _file = null;
File variable declared at the beginning.
Future<void> changeImage() async { //This will change the picture
File tmp = await imgFromGallery();
setState(() {
_file = tmp;
});
return;
}
The function above will change _file value to the file picked from gallery.
Widget myAvatar() {
return GestureDetector(
onTap: null,
child: CircleAvatar(
radius: 55,
backgroundColor: Color(0xffFDCF09),
child: CircleAvatar(
radius: 50,
child: Container(
child: _file == null
? AssetImage("empty_profile.png")
: FileImage(_file),
),
),
),
);
}
Finally if file is still null then the asset image is loaded, otherwise if a new picture is choosen then FileImage(_file) will show the picked image.
I have a lots of error because I don't know very well how to handle files, their paths and show images...Can you explain me how I should do?
To include static images in your Flutter project, place them inside the "assets/images" folder. Then, make sure to add this folder to your pubspec.yml:
flutter:
assets:
- assets/images/
Next, you may have errors related to trying to render an AssetImage inside a CircleAvatar. To render the file as an Image widget instead, use Image.asset(<path>). Your example could be written as:
Widget myAvatar() {
return GestureDetector(
onTap: null,
child: CircleAvatar(
radius: 55,
backgroundColor: Color(0xffFDCF09),
child: _file == null
? Image.asset("assets/images/empty_profile.png")
: _file
),
);
}
Finally, a great resource for user-selected images is the image_picker library: https://pub.dev/packages/image_picker. For example, a "Select from Gallery" button could invoke the following code, which allows the user to crop the image and saves it as an Image widget:
PickedFile image = await picker.getImage(
source: ImageSource.gallery, // to select from camera, use ImageSource.camera
maxHeight: 1024,
maxWidth: 1024,
imageQuality: 50
);
try {
File croppedImage = await ImageCropper.cropImage( // use platform-native image cropping
sourcePath: image.path,
cropStyle: CropStyle.circle,
maxWidth: 512,
maxHeight: 512
);
setState(() { // refresh state to render new profile image
_file = Image.file(croppedImage)
})
} catch (err) {
print(err)
}
You can use CachedNetworkImage PlugIn - Update other details as per your need. This code show Network Images, if not available will show Assets Image.
new Container(
width: 140.0,
height: 140.0,
child: ClipOval(
child: CachedNetworkImage(
imageUrl: _profile == null ? "" : Api.baseURL + _profile,
placeholder: (context, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) => Image.asset(
"img/user.png",
fit: BoxFit.cover,
height: 140.0,
width: 140.0,
),
fit: BoxFit.cover,
height: 140.0,
width: 140.0,
),
),
),

'package:flutter/src/painting/_network_image_io.dart': Failed assertion: line 22 pos 14: 'url != null': is not true

class CustomCircleAvatar extends StatefulWidget {
final Image myImage;
final String initials;
CustomCircleAvatar({this.myImage, this.initials});
#override
_CustomCircleAvatarState createState() => new _CustomCircleAvatarState();
}
class _CustomCircleAvatarState extends State {
bool _checkLoading = true;
#override
void initState() {
super.initState();
widget.myImage.image.resolve(new ImageConfiguration()).addListener(
ImageStreamListener((ImageInfo info, bool synchronousCall) {
if (mounted) {
setState(() {
_checkLoading = false;
});
}
}));
}
#override
Widget build(BuildContext context) {
return _checkLoading == true
? new CircleAvatar(
child: new Text(
widget.initials,
style: TextStyle(fontSize: 60),
))
: new CircleAvatar(
backgroundImage: widget.myImage.image,
);
}
}
Positioned _profilePhoto(BuildContext context) {
return Positioned(
bottom: -70,
child: Container(
width: 150.0,
height: 150.0,
padding: EdgeInsets.all(3.0),
decoration: BoxDecoration(color: Colors.white, shape: BoxShape.circle),
child: CustomCircleAvatar(
myImage: Image.network(sellerPicture), // This sellerPicture i got from sharedPreferences
initials: '$sellerName'.substring(0, 1).toUpperCase(),
),
),
);
}
help me, the image Show from URL but the terminal say that URL != null is not true
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following assertion was thrown building ProfileScreen(dirty, state: _ProfileScreenState#29296):
'package:flutter/src/painting/_network_image_io.dart': Failed assertion: line 22 pos 14: 'url != null': is not true.
The code seems to be incomplete. If the error appears once but the image from the URL is still displayed on the widget, it's likely that the Widget tries to load the image from url that hasn't been initialized. Possibly during first render of the screen, url is still empty, and on reload (i.e. via setState()), the url has been initialized. A workaround for this issue is to set a default image url in the parameter.
Or add a checker for sellerPicture
Container(
/// Check if sellerPicture is null
child: sellerPicture != null ?
CustomCircleAvatar(
myImage: Image.network(sellerPicture), // This sellerPicture i got from
sharedPreferences
initials: '$sellerName'.substring(0, 1).toUpperCase(),
),
/// if sellerPicture is null, display a default image Widget
/// i.e. image from local Assets
: DefaultImageWidget(),
),
)

setState(() {}); Required in Android Flutter

After selecting image using image_picker: ^0.6.0+15 package, we received a file in Android and iOS, but the issue is with the display/render of the image in the UI.
//Display Image to user
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 20, bottom: 20),
child: _selectedImage == null
? Center(
child: Container(
child: Text('No Image selected'),
),
)
: Image.memory(
_selectedImage.readAsBytesSync(),
fit: BoxFit.contain,
),
),
)
setState(() {}); is required in Android but on iOS image display with out calling setState(() {}); glitches the UI on iOS if we call setState().
We have an option:
Future getImage(int sourceType) async {
_selectedImage = await ImagePicker.pickImage(
source: sourceType == 1 ? ImageSource.gallery : ImageSource.camera,
maxHeight: 500,
maxWidth: 500,
);
// to show Images in Images View
if (Platform.isAndroid) {
setState(() {});
}
}
But is there any explanation on setState() is not needed on iOS?
Any interface should be ready for multiple build() calls per second. You should be free to call setState() with no reservations anytime. When this is a problem, you are doing something wrong.
I think this is what's wrong in your case: you call _selectedImage.readAsBytesSync() in build(). You should do that elsewhere and keep info about it in fields of your class, which the build() function uses to simply convert that information to UI.