How to save pdf file in flutter? - flutter

I have a pdf file. I want to write that file in phone memory? Below is the code.
First I am scanning then I am converting the image to pdf, Now I want to save that pdf to phone memory. Please help me.
void onDocumentScanner(BuildContext context) async {
try {
File scannedDocumentFile;
var doc = await DocumentScannerFlutter.launchForPdf(context);
if (doc != null) {
refreshDownloadedFiles();
scannedDocumentFile = doc;
String fileName = basename(scannedDocumentFile.path);
final directory = (await getExternalStorageDirectory())!.path;
File saveFilePath = File('$directory/$fileName');
saveFilePath.openWrite(); //Here I want to save to the file
print("Path = $fileName");
Get.toNamed(AppRoutes.viewDownloadedFile,
arguments: [scannedDocumentFile.path, fileName, folderId])!
.whenComplete(() {
refreshFetchedData();
});
}
} catch (e) {
print(e);
}
}

I haven't seen the .openWrite() method before, but the documentation says that it has 2 named arguments FileMode and encoding - try to specify them.
If it won't work, I can only share my solution, with .writeAsBytes method.
Instead of saveFilePath.openWrite() you can bundle the data first and then save it.
final byteData = await rootBundle.load(fileName);
await saveFilePath.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));

Related

How to pass header to URL in Flutter

I have a question regarding how to view a PDF from URL.
I’m using flutter_pdfview library and I try to get a PDF from an URL and to view it in my Flutter app.
The problem is that my URL can be accessed ONLY with a token (session ID/header), but I don’t know how to pass it because is not working on the way I do it at the moment.
Here is an example of how the owner of the flutter_pdfview library is getting the PDF from an URL (without a Header): https://github.com/endigo/flutter_pdfview/blob/master/example/lib/main.dart#L49
And here is my code where I don’t know how else to pass the header than like this:
Future<File> createFileOfPdfUrl() async {
Completer<File> completer = Completer();
if (kDebugMode) {
print("Start download file from internet!");
}
try {
String url =
"$customURL.pdf";
if (kDebugMode) {
print("url: $url");
}
final filename = url.substring(url.lastIndexOf("/") + 1);
var client = HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(url));
request.headers.add(
HttpHeaders.acceptHeader,
HeaderValue(
"text/plain", {'APPAUTH': '${widget.authService.loginToken}'})); // this method doesn't seems to work for me. I'm getting an empty PDF.
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
var dir = await getApplicationDocumentsDirectory();
if (kDebugMode) {
print("Download files");
print("${dir.path}/$filename");
}
File file = File("${dir.path}/$filename");
await file.writeAsBytes(bytes, flush: true);
completer.complete(file);
} catch (e) {
throw Exception('Error parsing asset file!');
}
return completer.future;
}
DO NOT do this:
request.headers.add(
HttpHeaders.acceptHeader, // here is the problem
HeaderValue(
"text/plain", {'APPAUTH': '${widget.authService.loginToken}'}));
SOLUTION for me:
request.headers.add("APPAUTH", "12345abcde67890defgh");
For some reason if you provide a HeaderValue you also need to provide a string value before it, which can be HttpHeaders.acceptHeader or HttpHeaders.serverHeader etc. I tried a lot of them from that enum list and none worked for me so I used the above solution where you don't need to pass that HttpHeader value type.

Image is not saving on mobile device after taking picture with camera package

I am trying to save an image to my local mobile device when I use this code from the pub.dev example page of the camera package. However I am not finding the file saved on the device. Can anyone please help me with how to save the image taken to a given path
void onTakePictureButtonPressed() {
takePicture().then((XFile? file) {
if (mounted) {
setState(() {
imageFile = file;
videoController?.dispose();
videoController = null;
});
if (file != null) {
showInSnackBar('Picture saved to ${file.path}');
}
}
});
}
Using await ImagePicker.pickImage(...), you are already on the right track because the function returns a File.
The File class has a copy method, which you can use to copy the file (which is already saved on disk by either the camera or by lying in gallery) and put it into your application documents directory:
// using your method of getting an image
final File image = await ImagePicker.pickImage(source: imageSource);
// getting a directory path for saving
final String path = await getApplicationDocumentsDirectory().path;
// copy the file to a new path
final File newImage = await image.copy('$path/image1.png');
setState(() {
_image = newImage;
});
You should also note that you can get the path of the image file from ImagePicker using image.path, which will also contain the file ending that you might want to extract and you can save your image path by using newImage.path.
You can use path provider and save the images like this
https://pub.dev/packages/path_provider
final XFile? image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final String newFile = await getApplicationDocumentsDirectory().path;
final var fileName = basename(file.path);
final File localImage = await image.saveTo('$newFile/$fileName');

how to give title in flutter to pdf file before save to download folder?

I want exactly this page in flutter
I'm not sure where that screen is coming from. But you can try the file_picker_writable plugin. (shameless plug).
Future<void> _openFilePickerForCreate() async {
final rand = Random().nextInt(10000000);
final fileInfo = await FilePickerWritable().openFileForCreate(
fileName: 'newfile.$rand.codeux',
writer: (file) async {
final content = 'File created at ${DateTime.now()}\n\n';
await file.writeAsString(content);
},
);
if (fileInfo == null) {
_logger.info('User canceled.');
return;
}
final data = await _appDataBloc.store.load();
await _appDataBloc.store
.save(data.copyWith(files: data.files + [fileInfo]));
}
}
this will open a folder chooser dialog for the user and a default file name (given by fileName).
This code example will open the following dialog:

Flutter form builder package image picker firestore flutter

i am using FormBuilderImagePicker from package Flutter form builder
I want to use the img path but i am not able to do so
sending() async {
var storageimage =
FirebaseStorage.instance.ref().child('/google/google');
var task = storageimage.putFile();
imgurl = await (await task.onComplete).ref.getDownloadURL();
// await Firestore.instance.collection('twst').add(
// {
// 'img': imgurl.toString(),
// },
// );
}
i want to use that function with the imagepicker
but the problem is i am not able to find path to use putfile
To get the path of the FormBuilderImagePicker, the toString() method of the class prints the path.
Here is an example of how you can print in a container the Text field including FormBuilderImagePicker which have the path.
Then you will need to pass the image or file to the putFile method.
You can also use the ImagePicker pickImage class method to get the file.
sending() async {
File image;
try {
//Get the file from the image picker and store it
image = await ImagePicker.pickImage(source: ImageSource.gallery);
// Throws error when you don't select any image or when you don't have permissions
} on PlatformException catch (e) {
return;
}
//Create a reference to the location you want to upload to in firebase
StorageReference reference = FirebaseStorage.instance.ref().child("/google/google");
//Upload the file to Firebase
StorageUploadTask uploadTask = reference.putFile(image);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
// Waits till the file is uploaded then stores the download URL
String url = await taskSnapshot.ref.getDownloadURL();
}

Are fonts from the google_fonts package for flutter automatically stored in cache?

I'm reading the google_fonts documentation and I'm mostly here for clarification.
"With the google_fonts package, .ttf or .otf files do not need to be stored in your assets folder and mapped in the pubspec. Instead, they can be fetched once via http at runtime, and cached in the app's file system. This is ideal for development, and can be the preferred behavior for production apps that are looking to reduce the app bundle size."
Do I have to follow an extra step to cache the fonts, or should it happen automatically assuming I use the following code from the documentation:
Text(
'This is Google Fonts',
style: GoogleFonts.lato(),
),
I think I'm tripped up by the wording here. When it says the fonts can be fetched once at runtime, I want to know if that's what happens by default.
I am currently doing some font library research for custom fonts, and what I see in Google Fonts per:
https://github.com/material-foundation/google-fonts-flutter/blob/develop/lib/src/google_fonts_variant.dart
Looks pretty directly that it does per the code:
Future<void> saveFontToDeviceFileSystem(String name, List<int> bytes) async {
final file = await _localFile(name);
await file.writeAsBytes(bytes);
}
Future<ByteData> loadFontFromDeviceFileSystem(String name) async {
try {
final file = await _localFile(name);
final fileExists = file.existsSync();
if (fileExists) {
List<int> contents = await file.readAsBytes();
if (contents != null && contents.isNotEmpty) {
return ByteData.view(Uint8List.fromList(contents).buffer);
}
}
} catch (e) {
return null;
}
return null;
}
At runtime it checks in:
https://github.com/material-foundation/google-fonts-flutter/blob/develop/lib/src/google_fonts_base.dart
Future<void> loadFontIfNecessary(GoogleFontsDescriptor descriptor) async {
final familyWithVariantString = descriptor.familyWithVariant.toString();
final fontName = descriptor.familyWithVariant.toApiFilenamePrefix();
// If this font has already already loaded or is loading, then there is no
// need to attempt to load it again, unless the attempted load results in an
// error.
if (_loadedFonts.contains(familyWithVariantString)) {
return;
} else {
_loadedFonts.add(familyWithVariantString);
}
try {
Future<ByteData> byteData;
// Check if this font can be loaded by the pre-bundled assets.
final assetManifestJson = await assetManifest.json();
final assetPath = _findFamilyWithVariantAssetPath(
descriptor.familyWithVariant,
assetManifestJson,
);
if (assetPath != null) {
byteData = rootBundle.load(assetPath);
}
if (await byteData != null) {
return _loadFontByteData(familyWithVariantString, byteData);
}
// Check if this font can be loaded from the device file system.
byteData = file_io.loadFontFromDeviceFileSystem(familyWithVariantString);
if (await byteData != null) {
return _loadFontByteData(familyWithVariantString, byteData);
While it doesn't work for me directly, it is the base of dynamic_fonts which I am evaluating:
https://pub.dev/packages/dynamic_fonts/
I agree though, the wording isn't totally clear if its handling caching or not but looks to be per the code.