Flutter check if Asset image exists - flutter

Is it possible to conditionally load an asset image, only if it exists? Therefore you could load a default image if it does not exist in the Assets bundle.

One way you can check if the asset image exists is by trying to display it. If it throws an Exception, display a different widget instead.
Future<Widget> getAssetImage(String path) async {
try {
await rootBundle.load(path);
return Image.asset(path);
} catch (_) {
return SizedBox(); // Return this widget
}
}
Otherwise, you can check the AssetManifest.json and cross-check the asset to be used with the list before trying to access it.

Related

Flutter Exception Won't Catch Invalid Image Data

I have a synchronous method that reads an image from disk. I'm trying to handle all scenarios where the image didn't get saved properly and is corrupted.
If I place a fake.jpg in my app's documents folder and then run the below code on it, it crashes with: Invalid image data. So the Image.file portion of my code isn't catching an underlying exception.
Widget getPhotoFile(String path) {
final file = File(path);
try {
if (!file.existsSync()) throw Exception('Photo Not Available');
final photo = Image.file(
key: UniqueKey(),
file,
fit: BoxFit.cover,
);
return photo;
} catch (error) {
return Text('No Image');
}
}
Why won't my catch block work for the Image exception and return the Text widget instead?

How to retrieve an image from Firestore database - Flutter

i was wondering how to retrieve an image from Firestore, i was trying and reading and watching tutorials so i have come with this solution:
1- Upload images to Firebase storage.
2- Go to Firestore create a collection and a document with field name and value of image path. ( collection "majorChallenges", doc "challenge-1", field "source", value "image path url")
3- Initiate a Firestore Instance: var _fireStoreInstance = FirebaseFirestore.instance;
4- Access the Database collection using QuerySnapshot: QuerySnapshot qn = await _fireStoreInstance.collection("majorChallenges").get();
5- now after that am not sure how to setState, initState, return and display the image inside Scaffold or Container.
some tutorials are using the image link or name which is not efficient for me what if i have to change the image in the future so the best solution i believe must not use the image name it should access the collection and the doc and retrieve the image path.
i already set up the read and write permissions and i have accessed the database before to retrieve text so no authorisation problems, I would be very thankful if someone could complete the steps for us
I can now answer my own question, first of all it is wrong to specify this operation in steps because there are a lot of approaches to achieve this goal, and the approach i am using is pretty nice and simple using QuerySnapshot. so to retrieve picture we need simply do these steps (for my approach):
1- we need to declare a string variable then create asynchronous method that will fetch the image URL from Firestore and update the variable state using set state method, inside this method we can initiate a Firestore instance and a QuerySnapshot:
String img = "";
fetchMajorChallengeImage() async {
var _fireStoreInstance = FirebaseFirestore.instance;
QuerySnapshot qn =
await _fireStoreInstance.collection("majorChallenges").get();
setState(() {
img = qn.docs[0]["source"];
});
return qn.docs;
}
2- we will initiate the state using initState method and call our function inside:
void initState() {
fetchMajorChallengeImage();
super.initState();
}
3- now the image is retrieved and the path stored to "img" variable we declared, so we need to display the image, here its your choice where and how to display the image but for me this is how i displayed it:
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Image.network(img, height: 150, fit: BoxFit.fill),
],
),
);
}
note that it must be displayed inside Image.network() widget because the variable holds a URL value fetched from the firestore collection > doc > value and now the image is retrieved and displayed successfully.

Flutter: Crashlytics reporting Crashes when Image.asset loading fails even though it is being handled

In my app I have a large number of small logos available for loading by Image.asset. These logos are embedded in the app. These logos correspond to brands that my app currently knows about. However, there are there are other brands that I do not have logos for and I need to handle this also.
If for some reason I am trying to load a logo that I don't have in the app, I just want to show a blank text view. This seems to be all working fine BUT for some reason Crashlytics is saying there are app crashes BUT I don't think the app is actually crashing.
Here is an example of the error I see in Crashlytics...
Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError
Unable to load asset: logos/SZN-logo.png. Error thrown Instance of 'ErrorDescription'.
Can you see anything wrong with what I have here?
Widget getImage() {
try {
return Image.asset(getLogo()
, errorBuilder:
(BuildContext context, Object exception, StackTrace? stackTrace) {
return const Text('');
}
);
}
catch (e) {
return const Text('');
}
}

What is the proper way to load images in Flutter and handle exceptions on load

I'd like to know what is the proper way to load images from the device, and handle exceptions if the image is missing or corrupted. The user picking an image from the device and I want to open it. I'm using the image later in my code, so it is not enough for me just to show it in some widget.
Currently, I'm using the following code that works fine in most cases:
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
ImageProvider imageProvider = FileImage ( File ( path ), scale: 1 );
Completer<ImageInfo> completer = Completer();
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener((ImageInfo info, bool _) {
completer.complete(info);
}));
ImageInfo imageInfo = await completer.future;
return imageInfo.image;
}
But if the image is missing or corrupted, there is a print in the console "Exception caught by image resource service", but my exception catcher above this function not getting the exception.
Do I loading the image properly, or is there a better way?
In case this code is OK, how should I catch exceptions, particularly missing file or corrupted image?
I'm not sure about corrupted images, but in the case of missing files, you can store the File(path) in a variable and use varname.exists() to check before setting your ImageProvider.
Good question! :)
You can use a simpler code below, that loading an image just as you want.
import 'dart:ui' as ui;
Future<ui.Image> imageLoadFromDevice(String path) async {
await askPermissionForStorage();
File fileImage = File(path);
final Uint8List imageUint8List = await fileImage.readAsBytes();
final ui.Codec codec = await ui.instantiateImageCodec(imageUint8List);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
To catch exceptions from this code you can put it inside try-catch. Any exception while loading the image, should produce a general exception that can be caught and handled.
To handle errors from an ImageStream, use the onError argument to the ImageStreamListener constructor:
imageProvider.resolve(ImageConfiguration()).addListener(ImageStreamListener(
(ImageInfo info, bool _) { }, // called for success
onError: (Object error, StackTrace? stackTrace) { }, // called for error
));

How to access assets in package

The original question comes from flutter issue 32799
I develop a dart package, i need load some json file in runtime, but when I do this occur an error. load image is no problem ,the code:
void main() {
Future<void> loadAsset() async {
String value = await rootBundle
.loadString('lib/src/assets/JsonConfig/test.json');
//Image img = Image.asset('lib/src/assets/default-logo.png');
}
test('adds one to input values', () async {
await loadAsset();
});
}
my pubspec.yaml file like this:
flutter:
# To add assets to your package, add an assets section, like this:
assets:
- lib/src/assets/default-logo.png
- lib/src/assets/JsonConfig/test.json
- lib/src/assets/
To load assets from packages, you should add the prefix 'packages/<package_name>/' for the key to making it works.
Such as how AssetImage do
/// The name used to generate the key to obtain the asset. For local assets
/// this is [assetName], and for assets from packages the [assetName] is
/// prefixed 'packages/<package_name>/'.
String get keyName => package == null ? assetName : 'packages/$package/$assetName';
https://github.com/flutter/flutter/blob/fba99f6cf9a14512e461e3122c8ddfaa25394e89/packages/flutter/lib/src/painting/image_resolution.dart#L146
So add the prefix 'packages/<package_name>/' for the key will work on the demo above:
String value = await rootBundle
.loadString('packages/<package_name>/lib/src/assets/JsonConfig/test.json');