'Cannot open file' after cropping image - flutter

The goal is to:
1) Allow the user to choose a picture [I use image_picker for that]
2) User crops image to a 1:1 aspect ratio [I use image_crop for that]
3) Upload image to Python backend
The problem:
After cropping image, attempting to read the image to Post it returns:
Unhandled Exception: FileSystemException: Cannot open file, path = '/data/user/0/com.example.AppName/cache/image_crop_26d4daef-e297-456c-9c6d-85d2e4c0d0662042323543401355956.jpg' (OS Error: No such file or directory, errno = 2)
The weird part is, I can display the image just fine within Flutter using `FileImage(_imageFile)' (considering _imageFile is the File variable)
It's just that I cannot use _imageFile.length() or even base64Encode(_imageFile.readAsBytesSync()).
Any ideas on what's happening and how to fix it?

path_provider plugin supports access to two filesystem locations:
Temporary directory,
Documents directory.
— The temporary directory is the cache and its content may be erased by the system at any time. So, storing data here is not good for us to get it later.
— The documents directory is the one we to choose now, this is a directory for the app to store files that only it can access
And You are using temporary directory (/data/user/0/com.example.AppName/cache/image_crop_26d4daef-e297-456c-9c6d-85d2e4c0d0662042323543401355956.jpg)
And if file is not erased then you can use following snippet to read file content:
final directory = await getTemporaryDirectory();
// For your reference print the AppDoc directory
final path = directory.path;
final file = File('$path/data.txt');
String contents = await file.readAsString();
return contents;

Related

Image Watermark Error: Unhandled Exception: FileSystemException: Cannot open file, path =''

I am new to Flutter and coding. I followed the guide here for how to add a watermark to an image. However, I am not using image picker, but using an image stored within Firebase, and a watermark that is an asset.
The code builds fine, but when I press the button to generate the watermarked image and eventually share it, I get the following error
Unhandled Exception: FileSystemException: Cannot open file, path = 'firebase url path' (OS Error: No such file or directory, errno = 2)
It is recognizing the path to the image in Firebase, but for some reason is saying the file isn't available. The error is being thrown on the 'decodeImage' portion of the code below.
Code snippet below
import '../backend/image_share/image_share.dart';
import 'package:image/image.dart' as ui;
import 'dart:io';
onPressed: () async {
//first image is a firebase path
final pickedFile = File('firebae path');
//second image is watermark and an asset
final watermark = File('assets/images/Share-small.png');
ui.Image originalImage = ui.decodeImage(pickedFile.readAsBytesSync());
ui.Image watermarkImage = ui.decodeImage(watermark.readAsBytesSync());
ui.drawImage(originalImage, watermarkImage);
ui.drawString(originalImage, ui.arial_24, 100, 120, 'Test!');
List<int> wmImage = ui.encodePng(originalImage);
final uploadUrl = await uploadData('new firebase data', wmImage);
final 'new firebase data' = FB collection(sharedImage: uploadUrl);
I am having trouble figuring out how to read/upload the image file before manipulating them.
The File class can only read/write files that are on the local system. It does not have any knowledge of files in Cloud Storage.
You will need to:
download the file from Cloud Storage,
add the watermark on the device, and then
write the resulting file back to Cloud Storage.

Cannot copy file to local storage android flutter

I am trying to pick image from gallery or camera by image_picker, and save image at specific location. My code work perfectly when i pick image from camera, but it through an exception when i pick from gallery while saving. Here is my code
onPressed: () async {
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
File tempFile = File(image.path);
tempFile = await tempFile.copy('storage/emulated/0/$image.name');
}
Above code through an exception
[ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: FileSystemException: Cannot copy file to 'storage/emulated/0//6544578463230218846.jpg', path = '/data/user/0/com.example.nysu/cache/image_picker6544578463230218846.jpg' (OS Error: No such file or directory, errno = 2)
First make sure that you have the required permissions:
For example for Android you need:
Also the file path seems a bit weird with the extra "/", you might want to fix that if it is not intentional:
'storage/emulated/0//6544578463230218846.jpg'
Like so:
tempFile = await tempFile.copy('storage/emulated/0$image.name');
Basic Flow of my application is that, firs i choose image from gallery or camera and then i input name for image from user and then i save image with user provided name to local storage.
So in between interval of choosing image and after that input name, cache memory for image picker is lost some time, because of this (OS Error: No such file or directory, errno = 2) happens.
To solve this i input name before choosing image, and instantly save image after choosing them. It works perfectly.

How to Save ByteData (Image) into Download directory in Flutter?

I'm trying to save a ByteData image generated from canvas into the device download folder. However, I was only able to save it into my apps android/data/ directory using the code below...
Future<void> saveImage(
String fileName,
ByteData image,
) async {
final directoryName = "Generated";
Directory directory = await getExternalStorageDirectory();
String path = directory.path;
await Directory('$path/$directoryName').create(recursive: true);
File('$path/$directoryName/$fileName.png').writeAsBytesSync(image.buffer.asInt8List());
}
but, it's not convenient for the user to go into this deep directory just to get the image, so I want to save it into the Download directory but I don't know how. I have tried several approaches but I keep on receiving permission errors. Like for example using this code below (downloads_path_provider)...
Directory directory = await DownloadsPathProvider.downloadsDirectory;
String path = directory.path;
File('$path/$fileName.png').writeAsBytesSync(image.buffer.asInt8List());
PS. It would be much better if there's a way to save it somewhere that will show in the Phone's Gallery
You can save images to gallery with this package on pub.dev : 'gallery_saver' : https://pub.dev/packages/gallery_saver

How to get the original path of an image chosen with image picker plugin in Flutter instead of copying to cache?

I'm making an Android app, and when using the image picker plugin;
final pickedFile = await ImagePicker().getImage(source: ImageSource.gallery);
File image = File(pickedFile.path);
the 'image' is a copy of the original image in the app's cache, however, I would like to directly use the original image's path to save it in my app because I don't want the apps cache size to grow. I saw that the deprecated method "pickImage" accomplished this (not copying to cache), but the new "getImage" seems to copy automatically and 'image's path is the path of the cached image.
How can I accomplish getting just the original path of the selected image without it being cached? (I'm assuming that using the original file's path would still work to display it in the app with FileImage(File(originalPath)), this is correct assumption?)
On iOS it was never possible to retrieve the original path and on Android it was only possible until SDK 30.
From FAQ of file_picker plugin,
Original paths were possible until file_picker 2.0.0 on Android, however, in iOS they were never possible at all since iOS wants you to make a cached copy and work on it. But, 2.0.0 introduced scoped storage support (Android 10) and with and per Android doc recommendations, files should be accessed in two ways:
Pick files for CRUD operations (read, delete, edit) through files URI and use it directly — this is what you actually want but unfortunately isn’t supported by Flutter as it needs an absolute path to open a File descriptor;
Cache the file temporarily for upload or similar, or just copy into your app’s persistent storage so you can later access it — this is what’s being done currently and even though you may have an additional step moving/copying the file after first picking, makes it safer and reliable to access any allowed file on any Android device.
I have an example for the file_picker package:
var filePath = '';
var fileExtension = '';
var fileName = '';
void buttonOnTap() async {
try {
filePath = await FilePicker.getFilePath(type: FileType.IMAGE);
if (filePath != null) {
fileName = filePath.split('/').last;
fileExtension = fileName.split('.').last;
} else {
filePath = '';
fileName = '';
fileExtension = '';
}
} catch (e) {}
if (filePath != '') {
Image.file(File(filePath), fit: BoxFit.cover);
}
}

Loading video files from device as `ByteData` flutter

I'm using the flutter camera package to record videos and save videos to a temporary directory after which I use flutter's ffmpeg package to do some transformation. However, to achieved this, I first had to make a copy of the recorded video to create the output file path.
The challenge comes in when I'm trying to load the asset from the device. The block of code below does the copying and renaming of the file.
static Future<File> copyFileAssets(String assetName, String localName) async {
ByteData assetByteData = await rootBundle.load(assetName);
final List<int> byteList = assetByteData.buffer
.asUint8List(assetByteData.offsetInBytes, assetByteData.lengthInBytes);
final String fullTemporaryPath =
join((await tempDirectory).path, localName);
return new File(fullTemporaryPath)
.writeAsBytes(byteList, mode: FileMode.writeOnly, flush: true);
}
The issue lies with this line ByteData assetByteData = await rootBundle.load(assetName);
I get this error message Unable to load asset: /storage/emulated/0/Android/data/com.timz/files/timz/1585820950555.mp4, but the weird thing is, this only happens when I run the build for the first. Everything else works fine on subsequent hot restarts.
I later got this fix by myself rootBundle is meant for loading only assets you've declared their paths on your pubspec.yaml but somehow, it miraculously loads the saved file when hot restart was applied.
Reading the file as bytes gave what I wanted as load it with root bundle. Here's the code below.
Uint8List assetByteData = await File(assetName).readAsBytes();