Flutter Web - Save ui.Image to png File - flutter

I need some help with my code, I use the
"FilePicker.platform.saveFile()"
function to get the path on Windows Version (but not works on Web) and then
"final imageFuture = await controller
.renderImage(backgroundImageSize)
.then<Uint8List?>((ui.Image image) => image.pngBytes);
final imgFile = File(path);
imgFile.writeAsBytesSync(imageFuture!);
"
to save my image to disk, this works perfectly on Windows, but not on the web version.I need an alternative to save ui.Image (web Version) to PNG File on disk. 🙏🙏

I was able to solve my problem only, however the solution works only in release mode (after the build process).
import 'dart:html' as html;
import 'dart:js' as js;
final backgroundImageSize = Size(backgroundImage!.width.toDouble(),
backgroundImage!.height.toDouble());
final imageFuture = await controller
.renderImage(backgroundImageSize)
.then<Uint8List?>((ui.Image image) => image.pngBytes);
(imageFuture != null)
? js.context.callMethod(
"saveAs",
[
html.Blob([imageFuture]),
'output-image.png',
],
)
: print('Image is null');
It is necessary to add inside your web/index.html file:
<script src="https://cdnjs.cloudflare.com/ajax/libs/amcharts/3.21.15/plugins/export/libs/FileSaver.js/FileSaver.min.js"></script>

Related

How to create a Button that allow user to download a specific file Flutter

I create a flutter app and I have this one CSV file that used as a template for user. I want to provide a Button that allow user to download this CSV file, so they can use it to have CSV file that already have our template.
The problem is I don't know if the best way is to first store the file online and get the url and use it on the flutter downloader URL or keep it in the local code asset and refer to that file when user tap the download template button. Currently I'm applying the second option and it doesn't work (I don't know if this option is possible or not), the download always fail. I'm using flutter_downloader package.
How to fix this ?
Here's my code, Is something wrong with my code ?
/// Check if the file exist or not
if (await File(externalDir!.path + "/" + fileName).exists()) {
OpenFilex.open(externalDir!.path + "/" + fileName);
} else {
/// Download the file if it doesn't exist in the user's device
final String localPath = (await getApplicationDocumentsDirectory()).path;
/// Dummy file name I want use (it exist in my asset dir"
const String fileName = 'add.png';
final data = await rootBundle.load('assets/logo/add.png');
final bytes = data.buffer.asUint8List();
final File file = File('$localPath/$fileName');
await file.writeAsBytes(bytes);
/// Download the file
final taskId = await FlutterDownloader.enqueue(
url: '',
savedDir: localPath,
fileName: fileName,
showNotification: true,
openFileFromNotification: true,
);
}
To load a file from the AppBundle and then save it to the users phone, do the following:
Put the file in assets/filename.csv and declare it in your pubspec like this:
flutter:
assets:
- assets/filename.csv
Load the file in your code:
import 'package:flutter/services.dart' show ByteData, rootBundle;
(...)
var data = (await rootBundle.load('assets/filename.csv)).buffer.asInt8List();
Save the data to a file (you need the path-provider package if you want to copy the exact code):
import 'package:path_provider/path_provider.dart' as pp;
(...)
var path = (await pp.getApplicationDocumentsDirectory()).path;
var file = File('$path/filename.csv');
await file.writeAsBytes(data, flush: true);
Edit: As Stephan correctly pointed out, if you want to store the file in the downloads folder, you will find additional information about that here. Thank you Stephan!

Flutter's SharePlus plugin refusing to share images claiming 'The source file doesn't exist'

Flutter's SharePlus plugin is refusing to share images, complaining
PlatformException(Share failed, assets/slideshow/tom_riddle_harry_potter_tour.webp: The source file doesn't exist., null, null)
The source file does exist, it's correctly declared in pubspec.yaml, and displayed in the app elsewhere using Image.asset(... using the same path.
I've tried numerous things, I tried giving XFile the MimeType, that didn't work.
I thought 'maybe it just won't work on web', so I eliminated image sharing in the web app.
Well that got sharing in the web app working, using a fallback, but the problem persisted on Android. So I tried omitting the image's path; just using the file name (with extension). Nope.
I tried specifying the image path string in a different manner, shouldn't work, didn't.
I tried reading the code for XFile and so far as I can see instantiating an XFile using an image path is perfectly valid.
Share.shareXFiles([XFile("assets/slideshow/${presentLocation.pictureList[0]}",
mimeType: "image/webp",
name: presentLocation.name.split(".")[0])],
subject: presentLocation.name + presentLocation.emoji,
text: shareStr,
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size).then((shareResult) async =>
{
if (shareResult.status ==
ShareResultStatus.success)
{
await MyApp.analytics.logShare(
contentType: "URL shared",
itemId: presentLocation.name,
method: "with image")
}
});
Am I misunderstanding XFile? What should I do?
Try this,
var asset = "assets/slideshow/${presentLocation.pictureList[0]}";
ByteData imagebyte = await rootBundle.load(asset);
final temp = await getTemporaryDirectory();
final path = '${temp.path}/temp_image_name.png';
File(path).writeAsBytesSync(imagebyte.buffer.asUint8List());
await Share.shareXFiles(path,
mimeType: "image/webp",
// rest of code
To create temporary directory, path-provider package might be needed if you already don't have it.
https://pub.dev/packages/path_provider

Flutter Web: Show PDF or Any File from Assets on another browser tab or window

Recently, I was working on the portfolio website where I need to show the user's CV which was in the PDF format on another tab.
Since this was a standalone Web Project, I didn't want to handle PDF viewing for iOS and Android.
First, you need to install this package: universal_html
flutter pub add universal_html
import the package in your file
import 'package:universal_html/html.dart' as html;
And here is the method:
Future<void> showCV() async {
var bytes = await rootBundle.load("assets/files/cv.pdf"); // location of your asset file
final blob = html.Blob([bytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
html.window.open(url, "_blank");
html.Url.revokeObjectUrl(url);
}
Voila !
var bytes = await rootBundle.load("assets/files/cv.pdf"); // location of your
asset file
final blob = html.Blob([bytes], 'application/pdf');
final url = html.Url.createObjectUrlFromBlob(blob);
html.window.open(url, "_blank");
html.Url.revokeObjectUrl(url);
Does it work in web hosting also ? because in my case this code is working in local host but not in web host.

Get file path from system directory using Flutter web (chrome) to read file content Eg: CSV or Text file

Package tried: https://pub.dev/packages/file_picker
Tried the example code implementation shared via GitHub. But the file path is returned as null for
web platform. Where same implementation in mobile platform return the path as expected.
https://github.com/miguelpruivo/flutter_file_picker/blob/master/example/lib/src/file_picker_demo.dart
Things aware of:
Path_Provider - Not supported for web
dart-io-library - Not supported for web
Open issue in Flutter Repo
Goal is to read the file from the path and not to upload. Any workaround to achieve this will be helpful.
Flutter channel: beta
As mentioned in the file_picker FAQ:
Paths aren't inaccessible from browsers since those provide fake paths. If you want to create a File instance to upload it somewhere, like FireStorage, you can do so with the bytes directly.
final result = await FilePicker.platform.pickFiles(type: FileType.any, allowMultiple: false);
if (result.files.first != null){
var fileBytes = result.files.first.bytes;
var fileName = result.files.first.name;
print(String.fromCharCodes(fileBytes));
}
I have a function for picking image from computer. Might work for you.
import 'dart:html';
void uploadImage({#required Function(File file) onSelected}) {
InputElement uploadInput = FileUploadInputElement()..accept = 'image/*';
uploadInput.click();
uploadInput.onChange.listen((event) {
final file = uploadInput.files.first;
final reader = FileReader();
reader.readAsDataUrl(file);
reader.onLoadEnd.listen((event) {
onSelected(file);
});
});
}

File modified data is always current time

I am using the following code snippet to attempt to retrieve the modified time of a file:
import 'dart:io';
import 'package:image_picker/image_picker.dart';
final picker = ImagePicker();
final pickedFile = await picker.getVideo(source: ImageSource.gallery);
final file = File(pickedFile.path);
print("file modified time: ${file.lastModifiedSync().toIso8601String()}");
Whenever I run the the above snippet, regardless of the file, it prints the current dateTime as opposed to the file's modified dataTime
The way the image_picker work is it creates a temporary copy of the file which you are about to upload in your app. With this implementation, the "current date" you are mentioning is the logically the file's "last modified date" (or creation date). So for now, you may not be able to retrieve it using this plugin.
However, with Flutter's Platform Channels, you should be able to retrieve the file's attributes, eg. for Android, using BasicFileAttributes in native code.
For example in Android:
File file = ...;
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
long lastModifiedAt = attr.lastModifiedTime();
Then using platform channels, you can pass the data like this to Flutter:
result.success(lastModifiedAt)
References
BasicFileAttributes
https://stackoverflow.com/a/48431255/10942908
Flutter's Platform Channels
I don't believe this information is available, unfortunately (at least on Android, not sure about iOS)
Tested using the file_picker package, hope that can help up with the image_picker.
You can use the cross_file package.
FilePickerResult? result = await FilePicker.platform.pickFiles();
final resultFile = result.files.first;
final resultFilePath = resultFile.path;
if (resultFilePath == null) {
throw EntityPathException();
}
/// Class from cross_file package
final xfile = XFile(resultFilePath);
final lastModified = await xfile.lastModified();
You can use multi_image_picker package instead. The creation time of the selected image(s) can be accessed through the MetaData class as indicated below:
List<Asset> images = await MultiImagePicker.pickImages(maxImages: 10, enableCamera: true);
Metadata metadata = await images[0].metadata;
DateTime takenOn = metadata.exif.dateTimeOriginal;