Choose a file (image, pdf, doc) and upload to server flutter android - flutter

I'm working with ASP.NET rest APIs. The task is I have to choose only one thing i.e image, pdf, docs file and send it to server. For picking files, I'm using the following library
file_picker: ^3.0.3
After successfully picking the file when I send it to the server, the response from the server is 403 forbidden.
// this is picking image code
ElevatedButton(
onPressed: () async {
FilePickerResult result = await FilePicker.platform.pickFiles();
if (result != null) {
PlatformFile file = result.files.first;
ApiClient.apiClient.uploadDocumentApi(file.path);
}
},
style: ElevatedButton.styleFrom(
primary: kPrimaryColor,
elevation: 0.0,
),
child: Text('Select'),
),
// this is API code
Future<void> uploadDocumentApi(String filePath) async {
print('pathh: ' + filePath);
String url = 'www.example.com';
var request = http.MultipartRequest(
'POST',
Uri.parse(url),
);
// request.files.add(await http.MultipartFile.fromPath('', filePath));
request.files.add(
http.MultipartFile(
'',
File(filePath).readAsBytes().asStream(),
File(filePath).lengthSync(),
filename: filePath.split("/").last,
),
);
http.StreamedResponse response = await request.send();
print(response.statusCode);
print(response.reasonPhrase);
if (response.statusCode == 200) {
print('success');
print(response.stream.bytesToString());
} else {
print('fail');
print(response.reasonPhrase);
}
}

As the error code indicates its related to authentication of your request. make sure your set your jwt correctly in your request header if needed and check it with backend side

Related

How to send Images through Multipart in Flutter

I want to send three images to my server. I have tried following. There are no errors, no exception but I can't send pictures to the server. Can you help me where I am making the error?
File? image1;
I am picking images from gallery
Future pickImage1() async {
try {
final image = await ImagePicker().pickImage(source: ImageSource.gallery,imageQuality: 75);
if (image == null) return;
final imagePermanent = await saveImagePermanently(image.path);
setState(() => image1 = imagePermanent);
} on PlatformException catch (e) {
print('failed to pick image $e');
}
}
It's how I am trying to send images to the server
uploadImage1(File imageFile1,File imageFile2, File imageFile3 ) async {
var postUri = Uri.parse("https://my link");
var request = http.MultipartRequest('POST', postUri);
request.files.add( http.MultipartFile.fromBytes("image1", imageFile1.readAsBytesSync(), filename: "Photo1.jpg", ));
request.files.add( http.MultipartFile.fromBytes("image2", imageFile1.readAsBytesSync(), filename: "Photo2.jpg", ));
request.files.add( http.MultipartFile.fromBytes("image3", imageFile1.readAsBytesSync(), filename: "Photo3.jpg", ));
await request.send().then((response) {
if (response.statusCode == 200)
{
print("Uploaded");
}
else {
print('error');
}
});
}
what I got in my console is
error
Here is the button where I call this function
ElevatedButton(
onPressed: () {
uploadImage1(image1!, image2!, image3!);
print('pressed');
},
child: const Text(' upload '),
),
Do not use both await and then together. Just use await to wait for the execution of the asynchronous function to finish.
final response = await request.send();
if (response.statusCode == 200) {
print("Uploaded");
} else {
print('error');
}
I have a sample code that uploads local images to Pl#nNet, it can be of any help to you, the output for that sample code is like this:
Start fetching...
Fetching done!
{query: {project: all, images: [dc5f659df9a4bcf90fc109830564d821], organs: [leaf],
...
{id: 6411486}}], version: 2022-02-14 (5.1), remainingIdentificationRequests: 197}
Done!

Cannot upload image chosen from gallery on Flutter: "Cannot extract a file path from a blob"

I have this image uploading API:
http://localhost:1234/simpleApi/image/upload
Given an image file test_image.jpg, here's how you upload it via HTTPie:
http POST http://localhost:1234/simpleApi/image/upload file#test_image.jpg
If uploaded succesfully, an UUID will be returned.
Now I'm trying to do the same thing on Flutter, first pick the image from gallery, then call the image upload API:
pickImage() async {
XFile? result;
try {
result = await ImagePicker().pickImage(
source: ImageSource.gallery,
imageQuality: 70,
maxWidth: 1024,
);
} on PlatformException {
Get.snackbar('', 'Cannot access gallery...');
}
if (result != null) {
setState(() {
_imgPath = result!.path;
});
}
}
uploadImage(String pathToFile) async {
var IMAGE_UPLOAD_URL = 'http://localhost:1234/simpleApi/image/upload'
var postUri = Uri.parse("IMAGE_UPLOAD_URL");
var request = new http.MultipartRequest("POST", postUri);
request.files.add(new http.MultipartFile.fromBytes('file', await File.fromUri(Uri.parse(pathToFile)).readAsBytes(),
contentType: new MediaType('image', 'jpeg')));
request.send().then((response) {
if (response.statusCode == 200) print("Upload OK");
else ("Upload failed.");
});
}
After calling pickImage, it returns a value like this:
blob:http://localhost:64692/a4b07098-0e83-46e2-8bdd-7a0a93aedec3
Passing that value to uploadImage gives this error:
Error: Unsupported operation: Cannot extract a file path from a blob
URI
How to fix this? I tested this on Flutter 2.2.3
You have everything right, the only thing you have to take note of is which platform are you reading this image from, when you check the example on Pub.dev you will notice that you have to check using kIsweb, that way the system will read your blob as a network image.
Obx(() => controller.filepath.value == ""
? Text(
"Select image",
style: TextStyle(fontSize: 20),
)
: Semantics(
label:
'image_picker_example_picked_image',
**child: kIsWeb
? Image.network(
controller.filepath.value)
: Image.file(
File(controller.filepath.value)),
)**
instead of URI you can use this
http.MultipartFile.fromBytes(
'image',
uint8list,
filename: imageName,
);

How to send files in flutter

I am trying to send files to server with flutter but it return this error:
Unhandled Exception: type 'List<File>' is not a subtype of type 'String' in type cast
Code
I've commented code below for better understanding
late List<File> newDoc = [];
// Select files
ElevatedButton(
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf', 'doc', 'docx', 'ppt', 'pptx'],
);
if(result != null) {
// Not sure if I should only get file path or complete data (this was in package documentation)
List<File> files = result.paths.map((path) => File(path!)).toList();
newDoc = files;
} else {
// User canceled the picker
}
},
child: Text('Select Files'),
),
SizedBox(height: 15.0),
// Send files to server
ElevatedButton(
onPressed: () async {
//save
var response = await http.post(
Uri.parse('https://example.come/upload/${args.id}'),
body: {
'documents': newDoc, // send array of my selected files to server
},
headers: {
HttpHeaders.authorizationHeader: '$userToken',
HttpHeaders.acceptHeader: 'application/json'
},
);
print('request::: $response');
// if (response.statusCode == 200) {
// .....
// } else {
// .....
// }
//save
},
child: Text('Save'),
),
Any suggestions?
Update
I've changed my http request to code below but my server receives empty body (the request does not send my files to backend)
var request = http.MultipartRequest('POST', uri);
request.headers['authorization'] = '$userToken';
request.headers['acceptHeader'] = 'application/json';
newDoc.map((k) async {
request.files.add(await http.MultipartFile.fromPath(
'documents', k.path
));
});
var response = await request.send();
var response2 = await http.Response.fromStream(response);
print('request::: ${response2.statusCode}');
print('request::: ${response2.body}'); // return as []
You have to use MultipartRequest to upload files. For example:
var uri = Uri.parse('https://example.com/create');
var request = http.MultipartRequest('POST', uri)
..fields['user'] = 'nweiz#google.com'
..files.add(await http.MultipartFile.fromPath(
'package', 'build/package.tar.gz',
contentType: MediaType('application', 'x-tar')));
var response = await request.send();
if (response.statusCode == 200) print('Uploaded!');
So for you it is like that:
final request = net.MultipartRequest("post", Uri.parse("https://example.come/upload/${args.id}"));
for (final file in files) {
request.files.add(await MultipartFile.fromPath(file.uri.pathSegments.last, file.path));
}
request.headers[HttpHeaders.authorizationHeader] = '$userToken';
request.headers[HttpHeaders.acceptHeader] = 'application/json';
final response = await request.send();
file.uri.pathSegments.last is a file name.
Your post call should look like this
var response = await http.post(
Uri.parse('https://example.come/upload/${args.id}'),
body: {
'documents': newDoc.map((e) => e.path).toList().join(', '),
},
headers: {
HttpHeaders.authorizationHeader: '$userToken',
HttpHeaders.acceptHeader: 'application/json'
},
);
The newDoc variable is List of Files, so convert the List of files to list of Strings (paths) using newDoc.map((e) => e.path).toList().join(', ')

How can I use flutter uploader and chunk uploader on the same request

I am searching for a way to upload a chunked image in a background task in flutter for Android. I already took a look at flutter_uploader and chunked_uploader plugins but it don't seems they are compatible.
Here is the documentation for the API I am trying to upload to:
piwigo upload async endpoint
Right now I am using a non chunked request with Dio to another endpoint:
void uploadPhotos(List<Asset> photos) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
Map<String, String> queries = {"format":"json", "method": "pwg.images.upload"};
photos.forEach((element) async {
ByteData byteData = await element.getByteData();
List<int> imageData = byteData.buffer.asUint8List();
FormData formData = FormData.fromMap({
"category": widget.category,
"pwg_token": prefs.getString("pwg_token"),
"file": MultipartFile.fromBytes(
imageData,
filename: element.name,
),
"name": element.name,
});
Response response = await API.dio.post("ws.php",
data: formData,
queryParameters: queries,
);
if (response.statusCode == 200) {
print(response.data);
if(json.decode(response.data)["stat"] == "ok") {
SnackBar snackBar = SnackBar(
content: Text("Successfully uploaded ${element.name}"),
duration: Duration(seconds: 2),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
} else {
print("Request failed: ${response.statusCode}");
}
);
}
So, is there a way to use the two plugins for a single request and if not, what should I use to fulfill my needs ?

Flutter Dio : How to Upload Image?

I'm trying on Postman. And it works
I want upload some image to rest-api using Package DIO Package ,
I'm new for this package (i'm use this package just for CRUD operation) and i'm got problem when upload image operation.
i'm already reading documentation and nothing see for upload images. I'm try this code(ref on documentation) and got some error :
error:FileSystemException
message :"Cannot retrieve length of file"
OSError (OS Error: No such file or directory, errno = 2)
"File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'"
Type (FileSystemException)
message:FileSystemException: Cannot retrieve length of file, path = 'File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'' (OS Error: No such file or directory, errno = 2)
DioErrorType (DioErrorType.DEFAULT)
name:"DioErrorType.DEFAULT"
Api.dart
Future uploadImage({dynamic data,Options options}) async{
Response apiRespon = await dio.post('$baseURL/mahasiswa/upload/',data: data,options: options);
if(apiRespon.statusCode== 201){
return apiRespon.statusCode==201;
}else{
print('errr');
return null;
}
}
View.dart
void uploadImage() async {
FormData formData = FormData.from({
"name_image": _txtNameImage.text,
"image": UploadFileInfo(File("$_image"), "image.jpg")
});
bool upload =
await api.uploadImage(data: formData, options: CrudComponent.options);
upload ? print('success') : print('fail');
}
_image is type FILE
I hope who expert with this package can help me with this code and suggest me for upload images.
Thanks.
Full View.dart Code
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mosque/api/api_mosque.dart';
class UploadImage extends StatefulWidget {
#override
_UploadImageState createState() => _UploadImageState();
}
class _UploadImageState extends State<UploadImage> {
ApiHelper api = ApiHelper();
File _image;
TextEditingController _txtNameImage = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_left),
onPressed: () => Navigator.pop(context, false),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.file_upload),
onPressed: () {
uploadImage();
},
)
],
),
body: _formUpload(),
);
}
Widget _formUpload() {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
TextField(
controller: _txtNameImage,
keyboardType: TextInputType.text,
decoration: InputDecoration(hintText: "Nama Image"),
maxLength: 9,
textAlign: TextAlign.center,
),
SizedBox(
height: 50.0,
),
Container(
child: _image == null
? Text('No Images Selected')
: Image.file(_image),
),
SizedBox(
height: 50.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Icon(Icons.camera),
onPressed: () => getImageCamera(),
),
SizedBox(
width: 50.0,
),
RaisedButton(
child: Icon(Icons.image),
onPressed: () => getImageGallery(),
)
],
)
],
),
);
}
void uploadImage() async {
FormData formData = FormData.from({
"name_image": _txtNameImage.text,
"image": UploadFileInfo(File("$_image"), "image.jpg")
});
bool upload =
await api.uploadImage(data: formData, options: CrudComponent.options);
upload ? print('success') : print('fail');
}
getImageGallery() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = imageFile;
});
}
getImageCamera() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = imageFile;
});
}
}
In Dio latest version, UploadFileInfo method has been replaced by MultipartFile class. And here the way how to use to post image, video or any file:
Future<String> uploadImage(File file) async {
String fileName = file.path.split('/').last;
FormData formData = FormData.fromMap({
"file":
await MultipartFile.fromFile(file.path, filename:fileName),
});
response = await dio.post("/info", data: formData);
return response.data['id'];
}
Even this question is asked a while ago, I believe the main issue is the size of image especially with Laravel.Flutter Image Picker library offers some functionalities to reduce the size of Image, I solved it with bellow steps:
Create a method to get the Image, I am using Camera to Capture the photo
Future getImage() async {
File _image;
final picker = ImagePicker();
var _pickedFile = await picker.getImage(
source: ImageSource.camera,
imageQuality: 50, // <- Reduce Image quality
maxHeight: 500, // <- reduce the image size
maxWidth: 500);
_image = _pickedFile.path;
_upload(_image);
}
Create _upload method to upload the photo, I am using Dio package Dio Package
void _upload(File file) async {
String fileName = file.path.split('/').last;
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(
file.path,
filename: fileName,
),
});
Dio dio = new Dio();
dio.post("http://192.168.43.225/api/media", data: data)
.then((response) => print(response))
.catchError((error) => print(error));
}
On the server side, I am using Laravel Laravel, I handle the request as follow
public function store(Request $request)
{
$file = $request->file('file');
$extension = $file->getClientOriginalExtension();
$fullFileName = time(). '.'. $extension;
$file->storeAs('uploads', $fullFileName, ['disk' => 'local']);
return 'uploaded Successfully';
}
In the latest version of Dio :
It should look like this.
String fileName = imageFile.path.split('/').last;
FormData formData = FormData.fromMap({
"image-param-name": await MultipartFile.fromFile(
imageFile.path,
filename: fileName,
contentType: new MediaType("image", "jpeg"), //important
),
});
If without this line.
contentType: new MediaType("image", "jpeg")
Maybe it will cause an error: DioError [DioErrorType.RESPONSE]: Http status error [400] Exception
And get MediaType in this package: http_parser
The following code uploads multiple image files from a dio client to a golang server.
dioclient.dart
FormData formData = FormData.fromMap({
"name": "wendux",
"age": 25,
"other" : "params",
});
for (File item in yourFileList)
formData.files.addAll([
MapEntry("image_files", await MultipartFile.fromFile(item.path)),
]);
Dio dio = new Dio()..options.baseUrl = "http://serverURL:port";
dio.post("/uploadFile", data: formData).then((response) {
print(response);
}).catchError((error) => print(error));
golangServer.go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func uploadFile(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(200000)
if err != nil {
fmt.Fprintln(w, err)
return
}
formdata := r.MultipartForm
files := formdata.File["image_files"]
for i, _ := range files {
file, err := files[i].Open()
defer file.Close()
if err != nil {
fmt.Fprintln(w, err)
return
}
out, err := os.Create("/path/to/dir/" + files[i].Filename)
defer out.Close()
if err != nil {
fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
return
}
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
return
}
fmt.Fprintf(w, "Files uploaded successfully : ")
fmt.Fprintf(w, files[i].Filename+"\n")
}
}
func startServer() {
http.HandleFunc("/uploadFile", uploadFile)
http.ListenAndServe(":9983", nil)
}
func main() {
fmt.Println("Server starts!")
startServer()
}
I have found a solution, where I am uploading file a specific directory which is generated different camera package which requires file path to save jpg file in the provided path.
and I was fetching file name with path and passing to
DIO package
which was giving file length issue, to I have implemented below steps to solve the issue
get File Name With Full Path from directory
create a File from the Path
File(directoryFilePathWithExtension);
and pass File.path to the dio package
MultipartFile.fromFile(
File(directoryFilePathWithExtension).path,
filename: DateTime.now().toIso8601String(),
)
Use UploadFileInfo.fromBytes if you're working with memory images (The error message above shows that your file is invalid and doesn't exist).
Hi there are many issue in file upload
try in android Api 21 because it did not have android permissions if api is working in android api 21 then it wil also work on above versions.
you might not able to get the file in above android version
you just need
FormData formData = FormData.fromMap({
"av_document": await MultipartFile.fromFile(_filePath,filename:
_fileName),
});
to upload any file or image to server and one more thing to note
_filePaths = await FilePicker.getMultiFilePath(type: _pickingType,
fileExtension: _extension);
_fileName = _filePath.split('/').last
by using this process u can upload file or image to server
I am using
dio: ^4.0.6 (for uploading)
flutter_native_image: ^0.0.6+1 (for reducing image size)
to reduce file size
File? compressedFile = profileImage.value == null
? null
: await FlutterNativeImage.compressImage(
profileImage.value?.path ?? '',
quality: 20,
percentage: 60);
dio formData map
var formData = dio.FormData.fromMap({
"name": input['name']!.text,
"profile_pic": await dio.MultipartFile.fromFile(compressedFile.path),
"birth_date": input['dob']!.text,})
request ->
response = await _dio.post(url, data: formData);