Upload image flutter web with dio formdata - flutter

I am trying using file_picker and dio packages to upload files as form data.
This is for flutter web and it seems MultipartFile.fromFile is not accepted.
What I tried is the following:
if (result != null) {
for (var file in result.files) {
final formData = FormData.fromMap({
...someOtherData,
'file': File(file.name), // <------ I guess this is where the issue is, I also tried file instead of File(file.name)
});
dio.post(
url,
data: formData,
);
}
}

Ok, I found it, leaving here for someone having the same problem
if (result != null) {
for (var file in result.files) {
final formData = FormData.fromMap({
...someOtherData,
'file': MultipartFile.fromBytes(file.bytes as List<int>)
});
dio.post(
url,
data: formData,
);
}
}

If anyone is still wondering how to get it working on both mobile and web (This is using the image_picker's PickedFile as the image variable type) :
FormData body;
final bytes = await image.readAsBytes();
final MultipartFile file = MultipartFile.fromBytes(bytes, filename: "picture");
MapEntry<String, MultipartFile> imageEntry = MapEntry("image", file);
body.files.add(imageEntry);
**
The catch is that the filename is required on web and is automatically assigned on mobile.**

Related

Error Uploading file to server with Flutter

I have a flutter application that select and upload audio file to server with asp.net rest api.
my flutter code as follows
uploadFile() async {
print(file.path);
var postUri = Uri.parse("http://192.168.1.100:5041/api/fileup/up");
var request = new http.MultipartRequest("POST", postUri);
request.fields['user'] = 'blah';
request.files.add(new http.MultipartFile.fromBytes('file', await File.fromUri(Uri.parse(file.path)).readAsBytes(),contentType: MediaType('audio','mp3')
));
request.send().then((response) {
if (response.statusCode == 200) {
print("Uploaded!");
}else{
print(response.reasonPhrase);
}
});
}
my file.path value for above flutter code is "/data/user/0/com.mydomain.myappname/cache/file_picker/Over_the_Horizon.mp3" which is returned from file picker.
I am able to upload file with postman, but flutter code gives me 500: Internal Server Error
Postman Screenshot
tried with several codes found on stack overflow , all gave me same error
Did you tried with DIO?
You can accomplish this with DIO, like this:
FormData formData = new FormData.fromMap({
"file": await MultipartFile.fromFile(file.path,
filename: file.path.split('/').last)
});
await dio.post('http://192.168.1.100:5041/api/fileup/up', data: formData, onSendProgress: (int begin, int end) {
var initial = begin;
var done = end;
print('$initial $end');
});

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"
}));

Upload image to Azure blob using Flutter (iOS/Android)

How can we upload images(.jpg, .png) to Azure blob storage. Not getting any insight to start with.
If you have used example would love to see and try if that is the way to do, any working example/url would help get started with
Here is i am trying to upload .jpg file and getting 400 error,
image.forEach((element) async {
ImageDetailsUpload result = ImageDetailsUpload.fromJson(element);
var postUri = Uri.parse('$url/${result.fileName}?$code'); //Azure blob url
var request = new http.MultipartRequest("PUT", postUri); //Put method
request.files.add(
new http.MultipartFile.fromBytes(
'file',
await File.fromUri(Uri.parse(result.path)).readAsBytes(),
),
);
request.send().then((response) {
print(response.statusCode);
}, onError: (err) {
print(err);
});
});
image is a LIST and holds the fileName and File path, this is what i get as bytes (see image below)
Solved the issue of upload but image is being corrupted now on server -
image.forEach((element) async {
ImageDetailsUpload result = ImageDetailsUpload.fromJson(element);
var postUri = Uri.parse('$url/${result.fileName}?$code');
var request = new http.MultipartRequest("PUT", postUri);
request.headers['X-MS-BLOB-TYPE'] = 'BlockBlob';
request.files.add(
new http.MultipartFile.fromBytes(
'file',
await File.fromUri(Uri.parse(result.path)).readAsBytes(),
),
);
request.send().then((response) {
print(response.statusCode);
}, onError: (err) {
print(err);
});
});
this seems to haunting me.
There is more to the question, what i noticed is the file uploaded using postman to blob storage are store as actual image of type image/jpeg depending on what type of image i am uploading. But when uploading using application i am using as mutipart which is making th e stored file into of type multipart/form-data. Uploaded both types of image jpg/png both gives type as mentioned above.
[![enter image description here][3]][3]
check here if you are using HTTP
How to upload images and file to a server in Flutter?
check this code if you are using Dio
FormData formData = FormData.from({
"name": "wendux",
"age": 25,
"file": await MultipartFile.fromFile("./text.txt",filename: "upload.txt")
});
response = await dio.post("/info", data: formData);
and check Dio's documentation
https://pub.dev/packages/dio
Here is a working example from one of my codes
Future<UploadImageResultModel> uploadImage(File image, String memberToken,
{String type = "IMAGE"}) async {
var uri = Uri.parse('${Constants.baseUrl}member/UploadImage/$type');
var request = new http.MultipartRequest("POST", uri);
request.headers.addAll({
"Authentication": memberToken,
});
var stream = new http.ByteStream(DelegatingStream.typed(image.openRead()));
var length = await image.length();
var multipartFile = new http.MultipartFile('file', stream, length,
filename: image.path.split("/").last);
request.files.add(multipartFile);
var streamedResponse = await request.send();
var response = await http.Response.fromStream(streamedResponse);
if (response.statusCode != 200)
return UploadImageResultModel.fromJson(json.decode("{}"));
return UploadImageResultModel.fromJson(json.decode(response.body));
}
First, convert the image File to Stream as data will be a push to the blob container in form of a stream.
Future uploadImage(File file) async {
String fileName = file.path.split('/').last;
_logger.info("File Path: " + fileName);
String imageToken = "Get your own token";
String containerName = "Blob container name";
final fileBytes = file.readAsBytesSync();
var streamData = Stream.fromIterable(fileBytes.map((e) => [e]));
String uploadDestinationUrl = RollaConstants.HOST_IMAGE +
"/$containerName" +
"/$fileName" +
imageToken;
final Dio _dio = Dio();
Response response;
try {
response = await _dio.put(uploadDestinationUrl,
data: streamData,
options: Options(headers: {
Headers.contentLengthHeader: fileBytes.length,
"x-ms-blob-type": "BlockBlob",
"content-type": "image/jpeg"
}));
} catch (error, stacktrace) {
print("Exception occured: $error.response stackTrace: $stacktrace");
}
print("Blob response: " + response.statusCode.toString());
}

How to upload multiple Images through Api

I am trying to Upload Multiple Images through Api but i am not understanding how to send a list, I can upload a single image though. Tried alot of searches but does'nt helped, i also import multi_image_picker i can pick the images but the problem is in uploading.
Future<Map<String, dynamic>> _uploadImage(File image) async {
String value = '';
SharedPreferences pref2 = await SharedPreferences.getInstance();
value = pref2.getString("user_role");
final mimeTypeData =
lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');
// Intilize the multipart request
final imageUploadRequest = http.MultipartRequest('POST', apiUrl);
// Attach the file in the request
final file = await http.MultipartFile.fromPath('photo', image.path,
contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
// Explicitly pass the extension of the image with request body
// Since image_picker has some bugs due which it mixes up
// image extension with file name like this filenamejpge
// Which creates some problem at the server side to manage
// or verify the file extension
imageUploadRequest.files.add(file);
imageUploadRequest.fields['mobile'] = _mobileNo.text;
imageUploadRequest.headers.addAll({
'Content-Type': 'application/json',
'Authorization': Constants.authToken,
});
var response = await imageUploadRequest.send();
if (response.statusCode == 200) print('Done!');
final respStr = await response.stream.bytesToString();
return json.decode(respStr);
}
this an example of uploading files to your API with HTTP package
import 'package:http/http.dart' as http;
void uploadFiles(List<File> files) async {
final url = YOUR-API-LINK;
for (var file in files) {
// Create a multipart request
var request = http.MultipartRequest('POST', Uri.parse(url));
// Add the file to the request
request.files.add(http.MultipartFile.fromBytes(
'file',
file.readAsBytesSync(),
filename: file.path.split('/').last,
));
// Send the request
var response = await request.send();
// Check the status code
if (response.statusCode != 200) {
print('Failed to upload file');
}else{
print response.body;
}
}
}
for Dio use this
void uploadFiles(List<File> files) async {
final url = YOUR-API-LINK;
// Create a Dio client
var dio = Dio();
// Create a FormData object
var formData = FormData();
// Add the files to the FormData object
for (var file in files) {
formData.files.add(MapEntry(
'file',
await MultipartFile.fromFile(file.path, filename: file.path.split('/').last),
));
}
// Send the request
var response = await dio.post(url, data: formData);
// Check the status code
if (response.statusCode != 200) {
print('Failed to upload files');
}else {
print(response.data)
}
}
as you can see there not much difference between them in http you use MultipartRequest in dio you use FormData.

flutter dio upload files [pdf/ docs]

I am trying to upload files using dio package in my flutter application. I am sending my files through formdata. Here is my implementation:
Future<FormData> formData1() async {
return FormData.fromMap({
"title": "from app2",
"description": "app upload test",
"files": [
for (var i = 0; i < pathNames.length; i++)
await MultipartFile.fromFile(pathNames[i],
filename: fileNames[i])
]
});
}
Here is how I am sending my files.
_sendToServer() async {
Dio dio = Dio(
BaseOptions(
contentType: 'multipart/form-data',
headers: {
"Authorization": "$token",
},
),
);
dio.interceptors.add(
LogInterceptor(requestBody: true, request: true, responseBody: true));
FormData formData = await formData1();
try {
var response = await dio.post("http://url/api/upload",
data: formData, onSendProgress: (int send, int total) {
print((send / total) * 100);
});
print(response);
} on DioError catch (e) {
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else {
print(e.request.headers);
print(e.message);
}
}
}
The other fields in formdata are sent to the server but not the multipartfile. When I try and do the same from postman form-data, it uploads correctly. Am I doing something wrong here?
If you want to upload the file you can convert multipart array before calling API function because even if you put await in form data dio response will not wait for formdata object or you can use MultipartFile.fromFileSync() to get rid of await.
Let me show you in a simple way using my example. try to understand.
Multipart conversion
List multipartArray = [];
for (var i = 0; i < pathNames.length; i++){
multipartArray.add(MultipartFile.fromFileSync(pathNames[i], filename:
basename(pathNames[i])));
}
Api side
static Future<Response> createPostApi(multipartArray) async {
var uri = Uri.parse('http://your_base_url/post');
return await Dio()
.post('$uri',
data: FormData.fromMap({
"title": "from app2",
"description": "app upload test",
"files": multipartArray
}))
.catchError((e) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
});
}
Here is my code where I used file_picker flutter library and MediaType('application', 'pdf') to ensure that the content passed to the API was indeed a .pdf file.
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:http_parser/http_parser.dart';
static Future<dynamic> uploadfile(int userid, File file, String token) async {
var fileName = file.path.split('/').last;
print(fileName);
var formData = FormData.fromMap({
'title': 'Upload Dokumen',
'uploaded_file': await MultipartFile.fromFile(file.path,
filename: fileName, contentType: MediaType('application', 'pdf')),
"type": "application/pdf"
});
var response = await Dio().post('${urlapi}request/',
options: Options(
contentType: 'multipart/form-data',
headers: {HttpHeaders.authorizationHeader: 'Token $token'}),
data: formData);
print(response);
return response;
}
The file picker:
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path ??'file.pdf');
BlocProvider.of<UploadCubit>(context)
.uploadFile(statelogin.user.id, file,
statelogin.user.token);
}
Change formdata with following rest is fine
import 'package:path/path.dart' as pathManager;
import 'package:mime/mime.dart' as mimeManager;
FormData formdata = FormData();
formdata.add(
"files",
[UploadFileInfo(img, pathManager.basename(img.path),
contentType:
ContentType.parse(mimeManager.lookupMimeType(img.path)))]);
// here attachmentFile is File instance, which is set by File Picker
Map<String, dynamic> _documentFormData = {};
if (attachmentFile != null) {
_documentFormData['document_file'] = MultipartFile.fromFileSync(attachmentFile.path);
}
FormData formData = FormData.fromMap(_documentFormData);
try {
var response = await dio.post("http://url/api/upload",
data: formData, onSendProgress: (int send, int total) {
print((send / total) * 100);
});
print(response);
} on DioError catch (e) {
if (e.response != null) {
print(e.response.data);
print(e.response.headers);
print(e.response.request);
} else {
print(e.request.headers);
print(e.message);
}
}
Here you can use MultipartRequest class without using any of library to upload any kind of files using restAPI.
void uploadFile(File file) async {
// string to uri
var uri = Uri.parse("enter here upload URL");
// create multipart request
var request = new http.MultipartRequest("POST", uri);
// if you need more parameters to parse, add those like this. i added "user_id". here this "user_id" is a key of the API request
request.fields["user_id"] = "text";
// multipart that takes file.. here this "idDocumentOne_1" is a key of the API request
MultipartFile multipartFile = await http.MultipartFile.fromPath(
'idDocumentOne_1',
file.path
);
// add file to multipart
request.files.add(multipartFile);
// send request to upload file
await request.send().then((response) async {
// listen for response
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}).catchError((e) {
print(e);
});
}
I used file picker to pick file. Here is the codes for pick file.
Future getPdfAndUpload(int position) async {
File file = await FilePicker.getFile(
type: FileType.custom,
allowedExtensions: ['pdf','docx'],
);
if(file != null) {
setState(() {
file1 = file; //file1 is a global variable which i created
});
}
}
here file_picker flutter library.