I'm sharing a picture that I've taken previously with the camera using image_picker. It works fine on the emulator but not on my device:
onPressed: () async {
ByteData image = await rootBundle.load(team.avatar.path);
...
},
This is the error with the path:
Unable to load asset:
/storage/emulated/0/Android/data/drodriguez.apps.Words/files/Pictures/scaled_2eccad3d-382e-462e-b124-b8fa06a2a32b791445736175256137.jpg
The image is being shown without errors so the path is 100% correct:
Image.file(
_orderedTeams[index].avatar,
fit: BoxFit.cover,
height: 92.0,
width: 92.0,
)
Do I need to add something else maybe on the pubspec.yml?
You can't use the rootBundle to access files on the phone. The rootBundle (as said in its docs) only works for files packaged with the application when was built (probably saved on assets, declared on pubspec, etc).
If you want to load an image from the phone, this maybe help.
ANSWER
This function can read a filePath and return a Uint8List (a byteArray):
Future<Uint8List> _readFileByte(String filePath) async {
Uri myUri = Uri.parse(filePath);
File audioFile = new File.fromUri(myUri);
Uint8List bytes;
await audioFile.readAsBytes().then((value) {
bytes = Uint8List.fromList(value);
print('reading of bytes is completed');
}).catchError((onError) {
print('Exception Error while reading audio from path:' +
onError.toString());
});
return bytes;
}
And, to get a ByteData just:
var path = 'Some path to an image';
var byteArray = _readFileByte(path);
ByteData data = ByteData.view(byteArray.buffer);
(The answer is based on this)
Related
I am doing some image processing and building in my app using the Image package. In this case, I am building a LinearProgressIndicator widget that is then converted into an image file, that is then merged into a larger image later on. However, the functions to build and take the image of the progress indicator widget isn't being waited on and the following error is observed
FileSystemException: Cannot open file, path = '/Users//Library/Developer/CoreSimulator/Devices//data/Containers/Data/Application//Library/Caches/bar.png' (OS Error: No such file or directory, errno = 2)
However, the progress indicator file is being created (I can see the cache), and then if I rerunning the image processing it works just fine (because now the file is there). However, I need it work on the first time. Here is what I have for image processing
import 'package:image/image.dart' as ui;
Future<File> instagramChalShare(BuildContext context, double progress) async {
//this is where it does not appear the progressBarPathFunct is being waited on
final testFile = await progressBarPathFunct(context, progress);
ui.Image tester = ui.decodeImage(testFile.readAsBytesSync());
//image is then resized
ui.Image progressResized = ui.Image(600, 90);
ui.drawImage(progressResized, tester);
//now progress bar is merged into larger image
final mergedImage = ui.Image(width, height);
ui.copyInto(mergedImage, progressResized, blend: true);
List<int> imageFile = ui.encodePng(mergedImage);
final imageFilePath = await File('${(await getTemporaryDirectory()).path}/temp.png').create();
print('picture finished $imageFilePath');
return imageFilePath.writeAsBytes(imageFile);
}
Here is the function to build the LinearProgressIndictor, convert it to an image, and create a file where the image is held.
Future<File> progressBarPathFunct(BuildContext context, double progress) async {
final progressFile = File('${(await getTemporaryDirectory()).path}/bar.png');
var indicator = LinearPercentIndicator(
percent: progress > 1.0 ? 1.0 : progress,
width: context.size.width,
lineHeight: 13,
),
barRadius: Radius.circular(20),
);
screenshotController.captureFromWidget(
InheritedTheme.captureAll(context, Material(child: indicator)),
).then((capturedProgress) async {
await progressFile.create(recursive: true);
await progressFile.writeAsBytes(capturedProgress);
});
print('progress bar path from functions ${progressFile.path}');
return progressFile;
}
This function is working, but it seems the top one creating the merged Image file is not waiting for this function to finish before attempting to complete.
Edit
I am following the example from the screenshot package to generate an image of a widget that is not on the screen.
I'm trying to capture QrImage using screenshot package specifically .captureFromWidget method, I'm not building the widget QrImage, because I don't want to show it just print it out using the sumni_printer package.
I tried to show the QR before printing when it was an image, and it showed flawsly as it is.
here's the code:
Future<Uint8List> getQRBytes(String data) async {
QrImage qr = QrImage(
data: data,
size: 100,
);
ScreenshotController screenshotController = ScreenshotController();
Screenshot(
controller: screenshotController,
child: qr,
);
Uint8List bytes = await screenshotController.captureFromWidget(qr);
return bytes;
}
and the results when printed in sumni printer:
this is how I import the Uint8List when printing:
Uint8List qr = await getQRBytes(data);
await SunmiPrinter.printImage(qr);
here's how it looks in the app
It turns out it's the sunmi_printer package...
there's a new package, sunmi_printer_plus
it solved my issue and it's an amazing package
I'm making a Flutter project where an image is displayed in listview and the user can share, favourite or download the image. I'm stuck on the downloading part. Is it possible to save an image file onto the phone's storage for offline use?
What I want to happen is I can create and write an image file
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/$title.txt');
}
// Write an image by obtaining an image through a URL
and then be able to access it through
Image.file('$path/$title.txt')
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
));
I have managed to upload an image using the image picker package as shown below:
final picker = ImagePicker();
Future selectPhoto() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
The image has been displayed on the device where I have a remove button which I can use to remove the image and upload another before saving it.
child: Container(
height: height * 0.2,
width: width * 0.2,
child: Image.file(
_image,
fit: BoxFit.fill,
),
),
My question is how can I remove the image from cache as this piece is not working
onTap: () {
setState(() {
imageCache.clear();
print('removes $_image');
});
},
You have a misunderstanding of what the cache is compared to explicitly storing a file in memory with your code. Flutter may store images that you use in widgets in a cache so that they may load faster in the future. imageCache.clear(); does clear the cache and is likely doing it's work in your code. However, your method of checking if the image is still cached is flawed.
imageCache.clear(); only clears the cache, it does not delete the file that you're passing to the Image.file widget. This means that _image(the file variable you have stored in memory) will persist even over the cache clearing. To truly delete this image you could use the delete method or if you just want to stop showing the image, deference the file by setting the file reference to null:
_image = null;
Solved it by calling a method within the button which had set state method where the path was returned back to null
clearimage() {
setState(() {
_image = null;
});
}