base64Decode removes pages from a pdf in base64? - flutter

I am using dio package to make a GET request to a server to retrieve a PDF file.
The request is working fine, I get the PDF in base64.
I get the response.data, and I use base64Decode to get the Uint8List, I save the file in the storage.
class FileSaverHelper {
Future<String> save({required String filename, required Uint8List bytes}) async {
final String tempDir = (await getTemporaryDirectory()).path;
final filePath = "$tempDir/$filename";
await File(filePath).writeAsBytes(bytes);
return filePath;
}
}
class OpenFileHelper {
final FileSaverHelper fileSaverHelper = Get.find();
Future<void> open({
required String filename,
required Future<Uint8List> Function() onDownload
}) async {
final Uint8List bytes = await onDownload();
final filePath = await fileSaverHelper.save(
filename: filename,
bytes: bytes
);
if(await File(filePath).exists()){
OpenFilex.open(filePath);
}
}
}
When I open the PDF it has only the first page and when I test the base64 that the server sends in the site Base64 to PDF, the PDF decoded has the amount of pages correctly (which is two).
Why after I use base64Decode(response.data), save the PDF to the storage, open it, it has only the first page but in the site the amount of pages is correct?

I found the problem is with the GET request, since the base64 retrieve by the server only through flutter, the file is retrieved incomplete.

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.

How to convert an Image instance to File instance in Flutter?

I am using VideoThumbanil class to fetch an Uint8List image of a video like this:
final uint8List = await VideoThumbnail.thumbnailData(video: videoFile.path,);
After doing so, i am converting the Uint8LIST to an Image using the following code:
Image image = Image.memory(uint8List);
What I want to do is to convert this image to a File class instance so that I can upload this image to my server. Code for uploading on server is:
void asyncFileUpload(File file) async {
//create multipart request for POST or PATCH method
var request = http.MultipartRequest("POST", Uri.parse("127.0.0.1/upload"));
//create multipart using filepath, string or bytes
var pic = await http.MultipartFile.fromPath("image", file.path);
//add multipart to request
request.files.add(pic);
var response = await request.send();
//Get the response from the server
var responseData = await response.stream.toBytes();
var responseString = String.fromCharCodes(responseData);
print(responseString);
}
You can fetch the path to the temporary directory:
final tempDir = await getTemporaryDirectory();
After doing so, you can create a File in that temporary directory:
File fileToBeUploaded = await File('${tempDir.path}/image.png').create();
This way your file has a path and it's instance has been created. Now, you can write the file as:
fileToBeUploaded.writeAsBytesSync(uint8List);
Now, you can use fileToBeUploaded as File that is actually an image.
Complete code:
final uint8List = await VideoThumbnail.thumbnailData(video: videoFile.path,);
final tempDir = await getTemporaryDirectory();
File fileToBeUploaded = await File('${tempDir.path}/image.png').create();
fileToBeUploaded.writeAsBytesSync(uint8List);
asyncFileUpload(fileToBeUploaded);
Since you already have the uint8 list you can try
File fileTpSend = File.fromRawPath(Uint8List uint8List);
Based on your code you need to import 'dart:io' and user fromRawPath function from File class (check snippet below)
import 'dart:io';
final uint8List = await VideoThumbnail.thumbnailData(video:videoFile.path);
final imageAsFile = File.fromRawPath(uint8List);
await asyncFileUpload(imageAsFile);
But this method doesn't work for Flutter WEB

Flutter cannot get download url firebase-storage

While trying to upload byteArray to the bucket in firebase storage, the file uploads to the storage but I cannot get the downloadUrl back from the file. I am getting the reference of bucket like this:
Future<Reference> get storageRef async {
final _bucketUrl = await bucketUrl;
return FirebaseStorage.instanceFor(bucket: _bucketUrl).ref();
}
And Uploading image like this:
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = await uploadTask;
return snapshot.ref.getDownloadURL();
}
From above code I am getting this error:
Unhandled Exception: type 'NoSuchMethodError' is not a subtype of type 'Exception'.
It works if I get reference for the FirebaseStorage only and not the bucket like this:
Future<Reference> get storageRef{
return FirebaseStorage.instance.ref();
}
I cannot implement without using bucket reference because there can be different bucket urls depending on the tenants. What am I doing wrong?
Edit => Recent Developments:
I found out that it works if I get the downloadurl from the _refUrl itself. i.e:
String downloadUrl = _refUrl.getDownloadUrl();
It works but I can't help but wonder if it is correct implementation.
Your edit makes perfect sense since you have the reference to the uploaded file with _refUrl, fetching its long-lived download URL works as expected (That's how I have done it before btw). I don't have access to a project with FirebaseStorage to test this, but You can try printing snapshot.ref.fullPath and compare it with the fullPath of _refUrl.
try this
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = (await uploadTask);
String url = await snapshot.ref.getDownloadURL(); // await
return url;
}

Flutter AZURE BLOB IMAGE UPLOAD - How to upload image captured using mobile camera to azure blob storage

I have been working for few since yesterday to try upload an image to azure blob storage taken using mobile camera form iOS/Android device.
I am able to upload the files but for some reason they being corrupted not able to open the image uploaded.
Please check the image error while opening the uploaded image
I am using flutter package http with different approach all work in uploading image file to azure blob store but it gets corrupted somehow , I tried forcing the ContentType to image/jpeg but no help.
Here is code I am using an http API -
takePicture() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
String fileName = basename(pickedFile.path);
uploadFile(fileName, image);
} else {
print('No image selected.');
}
});
}
First approach -->
http.Response response = await http.put(
uri,
headers: {
"Content-Type": 'image/jpeg',
"X-MS-BLOB-TYPE": "BlockBlob",
},
body: image.path,
);
print(response.statusCode);
Using Approach second -->
final data = image.readAsBytesSync();
var dio = Dio();
dio.options.headers['x-ms-blob-type'] = 'BlockBlob';
dio.options.headers['Content-Type'] = 'image/jpeg';
try {
final response = await dio.put(
'$url/$fileName?$token',
data: data,
onSendProgress: (int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.statusCode);
} catch (e) {
print(e);
}
Approach third -->
var request = new http.MultipartRequest("PUT", postUri);
request.headers['X-MS-BLOB-TYPE'] = 'BlockBlob';
request.headers['Content-Type'] = 'image/jpeg';
request.files.add(
new http.MultipartFile.fromBytes(
'picture',
await image.readAsBytes(),
),
);
request.send().then((response) {
uploadResponse.add(response.statusCode);
}, onError: (err) {
print(err);
});
Help here is much appreciated.
If you want to upload the image to Azure Blob Storage in the flutter application, you can use the Dart Package azblob to implement it. Regarding how to use the package, please refer to here.
For example
import 'package:image_picker/image_picker.dart';
import 'package:flutter/material.dart';
import 'package:azblob/azblob.dart';
import 'package:mime/mime.dart';
...
//use image_picker to get image
Future uploadImageToAzure(BuildContext context) async {
try{
String fileName = basename(_imageFile.path);
// read file as Uint8List
Uint8List content = await _imageFile.readAsBytes();
var storage = AzureStorage.parse('<storage account connection string>');
String container="image";
// get the mine type of the file
String contentType= lookupMimeType(fileName);
await storage.putBlob('/$container/$fileName',bodyBytes: content,contentType: contentType,type: BlobType.BlockBlob);
print("done");
} on AzureStorageException catch(ex){
print(ex.message);
}catch(err){
print(err);
}
Unfortunately, the multipart form is causing break of image. I don't know how it works on azure side, because there is little or no information about multipart uploads, but it's clearly broken because of multipart form. I replicated the problem in .net core application and whenever i am using multipart form data to upload image - it is broken. When i am using simple ByteArrayContent - it works. I couldn't find flutter equivalent to ByteArrayContent, so i am lost now :( The package mentioned by #Jim is useless for me, because i want to give clients sas url, so they have permission to upload image on client side. I do not want to store azure storage account secrets in flutter app.
EDIT. I found the solution to send raw byte data with Dio package. You can do that also with http package.
final dio = new Dio();
final fileBytes = file.readAsBytesSync();
var streamData = Stream.fromIterable(fileBytes.map((e) => [e]));
await dio.put(uploadDestinationUrl,
data: streamData,
options: Options(headers: {
Headers.contentLengthHeader: fileBytes.length,
"x-ms-blob-type": "BlockBlob",
"content-type": "image/jpeg"
}));

Flutter: How to encode and decode audio files in Base64 format?

I'm building a ChatBot app using Dialogflow and I want to implement Voice Recognition feature in my app. As you know Dialogflow provide us a feature to detect intent on the basis of audio but it only accepts audio in the form of base64. The problem for me is that I'm unable to encode the audio file into Base64. I'm new to Flutter Development so if in case I'm missing something or doing it in a wrong way then please let me know. Thanks!
I've tried this method but it's not giving me the proper output:
Future<String> makeBase64(String path) async {
try {
if (!await fileExists(path)) return null;
File file = File(path);
file.openRead();
var contents = await file.readAsBytes();
var base64File = base64.encode(contents);
return base64File;
} catch (e) {
print(e.toString());
return null;
}
}
You could do this:
List<int> fileBytes = await file.readAsBytes();
String base64String = base64Encode(fileBytes);
The converted string doesn't include mimetype, so you might need to include like this
final fileString = 'data:audio/mp3;base64,$base64String';