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.
Related
I have a floating action button that I want a user to click to take a picture with their camera and then have that image replace the camera icon on the floating action bar button.
Here is the code for my FAB, and including uploading the image to firestore storage.
floatingActionButton: FloatingActionButton.large(
heroTag: "add image",
backgroundColor: const Color(0xFF93C3B9),
child: (imageURL == ' ')
? const Icon(Icons.add_a_photo_outlined)
: Image.network(imageURL),
//open add gear page
onPressed: () async {
// todo: upload an image to Firebase Storage
//Take picture
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(source: ImageSource.camera);
if (file == null) return;
String uniqueFileName =
DateTime.now().millisecondsSinceEpoch.toString();
//Get reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child('images/$userID');
Reference referenceImageToUpload =
referenceDirImages.child(uniqueFileName);
try {
//upload image
await referenceImageToUpload.putFile(File(file.path));
//get download URL
setState(() async {
imageURL = await referenceImageToUpload.getDownloadURL();
print(imageURL);
});
//upload path to fireStore database
} catch (error) {}
},
),
After the image uploads it's like the set state is not working to replace the icon with the image. The odd part is is I crtl-s and save in Visual Studio Code then the widgets seem to rebuild and then the image is visible there...
So after playing around with my code a bit I decided to edit the above code and take tha await function out of the setState() and make setState() not async anymore:
//get download URL
String tempUrl = await referenceImageToUpload.getDownloadURL();
setState(() {
print("--------- Set State -----------");
imageURL = tempUrl;
print("--------- Set State end -----------");
});
print("New image url $imageURL ------------");
not sure why it works, but this solves my issue.
By your description of the issue, I think you might be using StatelessWidget instead of StatefulWidget.
You see the button change when performing a hotreload because the value of imageURL is correctly changing internally, but you need a StatefulWidget to update the UI also.
Hope it helps!
I`m using this package https://pub.dev/packages/image_crop
I want to upload a 4000x4000 quality picture to the server after converting it to 1080.
Firstly, I do the below
final pickedFile = await ImagePicker()
.pickImage(source: ImageSource.gallery, imageQuality: 100);
if (pickedFile == null) {
return;
}
final file = File(pickedFile.path);
final sample = await ImageCrop.sampleImage(
file: file, preferredWidth: 4000, preferredHeight: 4000
);
and then secondly I do the below
final sample = await ImageCrop.sampleImage(
file: file_tmp!,
preferredSize: (4000 / scale).round(),
);
and then lastly I do the below
final full = class_image.copyResize(image,
height: 1080, width: 1080);
I don't know if I'm getting it right now. Every time I change the value of preferredSize, the size of the final image file seems to change, and in the case of image_crop, the first scale is automatically set to 0.5, which causes deterioration in image quality.
First of all, I want to change the scale to 1.0, and I want it to come out without enlarging the screen. (This seems to cause quality degradation)
And please check if my logic is okay
If anyone knows this package well, please reply.
I am using the Image package to handle and process images in a flutter app. In this case, I am downloading the users profile pic and attempting to resize it and crop it to a circle. However, it does not appear to be cropping the image at all. Am I missing something here?
import 'package:image/image.dart' as ui;
final getProfile = await http.get(Uri.parse(profilePicPath));
final profileFile = File('${(await getTemporaryDirectory()).path}/image.png');
await profileFile.create(recursive: true);
await profileFile.writeAsBytes(getProfile.bodyBytes);
ui.Image profileImage = ui.decodeImage(profileFile.readAsBytesSync());
ui.copyCropCircle(profileImage, radius: 10);
Edit: I need to keep the image as a file and will not be shown in the UI (eventually used to overlay in another image file).
For anyone who runs into this issue, it was only a slight modification that got it to work. This pulls in the photo, stores it, resizes it, and then crops it to a cricle.
import 'package:image/image.dart' as ui;
final getProfile = await http.get(Uri.parse(profilePicPath));
final profileFile = File('${(await getTemporaryDirectory()).path}/image.png');
await profileFile.create(recursive: true);
await profileFile.writeAsBytes(getProfile.bodyBytes);
ui.Image profileImage = ui.decodeImage(profileFile.readAsBytesSync());
profileImage = ui.copyResize(profileImage, height: 100, width: 100);
profileImage = ui.copyCropCircle(profileImage, radius: 50);
i am new to Flutter.
I build simple demo app in which user can fill simple form and once user press button then those data will save into SQLite DB.
There's only 3 content. Title, Image Path (Image saved to DocumentDirectory), Location Details.
Add Screen
Listing Screen
Below is my code to copy image to path.
Future<void> _takePicture() async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 600,
);
if (pickedFile == null) {
return;
}
setState(() {
_storedImage = File(pickedFile.path);
});
final appDir = await syspaths.getApplicationDocumentsDirectory();
String relativePath = '/' +
DateTime.now().millisecondsSinceEpoch.toString() +
path.basename(pickedFile.path);
String newPath = '${appDir.path}' + relativePath;
final savedImage = await File(pickedFile.path).copy('$newPath');
widget.onSelectImage(savedImage);
}
Listing Item Code
child: Card(
elevation: 5,
child: ListTile(
leading: CircleAvatar(
backgroundImage: FileImage(greatPlaces.items[index].image),
),
title: Text(greatPlaces.items[index].title),
subtitle: Text(
greatPlaces.items[index].location.address),
onTap: () {
print(greatPlaces.items[index].image);
//Go to detail page...
},
),
)
ISSUE ==> When i add new place and view the added place list then images are loading fine but when i stop and rerun project then i am getting below error and image is not loading.
ERROR
════════ Exception caught by image resource service
════════════════════════════ The following FileSystemException was
thrown resolving an image codec: Cannot open file, path =
'/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg'
(OS Error: No such file or directory, errno = 2) When the exception
was thrown, this was the stack
#0 _File.open. (dart:io/file_impl.dart:356:9) (elided 13 frames from dart:async) Path:
/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg ════════════════════════════════════════════════════════════════════════════════
I downloaded app container and confirm image exist at the same place. greatPlaces.items[index].image return the File
NOTE: ==> Same code working fine in Android Devices.
it will be very helpful if someone help me with this. Thanks
Path of the documents directory changes on iOS after each app update. Therefore, one can not store absolute paths to the files stored in this directory. Instead, it is required to store the relative paths and then join them with the value returned by getApplicationDocumentsDirectory() every time to access the files.
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;
});
}