40

I'm trying on Postman. And it works

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

Zeffry Reynando
  • 3,445
  • 12
  • 49
  • 89

8 Answers8

82

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'];
}
xKobalt
  • 1,498
  • 2
  • 13
  • 19
Nhật Trần
  • 2,522
  • 1
  • 20
  • 20
  • 2
    On single image upload its work, but how to upload multiple images from List using FormData ?, please possible help about this. thank you – Qutbuddin Bohra Jul 05 '20 at 13:58
  • 2
    using a loop man! for(int i=0;i – Nhật Trần Jul 05 '20 at 16:41
  • yes, i solve this with formdata mapentry under list.foreach loop. – Qutbuddin Bohra Jul 06 '20 at 13:54
  • FormData formData = FormData.fromMap({ "file": await MultipartFile.fromFile(file.path, filename: fileName,contentType: MediaType.parse("image/png")), }); after adding contentType:MediaType.parse('image/png'); my image posted on server try this if any one have porblem – ankush Aug 06 '20 at 12:53
  • Unhandled Exception: DioError [DioErrorType.RESPONSE]: Http status error [400] – Bawantha Sep 28 '20 at 11:35
  • 1
    `using a loop man!` This is usually a bad idea, if your backend fails half way through for some reason you will have inconsistent / partially saved data. Better to let your api do an "all or nothing" and let your consuming app know about it in a response. – nategurutech Feb 04 '21 at 19:44
  • I keep getting error 415, Unsupported MediaType of application/octet-stream, any work around? – Naufal Rajabi Feb 17 '23 at 02:50
  • For web: FormData formData = FormData.fromMap({ "file": await MultipartFile.fromBytes(imageBytes, filename:fileName), }); – Mahboob Ahmed Mar 24 '23 at 12:13
39

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:

  1. 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);
    
    }
    
  2. 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));
    }
    
  3. 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';
    }
    
Seddiq Sorush
  • 2,709
  • 2
  • 20
  • 20
14

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

Doan Bui
  • 3,572
  • 25
  • 36
7

The following code uploads multiple image files from a dio client to a golang server.

  1. 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));
  1. 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()
}
Dharman
  • 30,962
  • 25
  • 85
  • 135
function1983
  • 971
  • 11
  • 14
1

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(),
)
Mrudul Addipalli
  • 574
  • 6
  • 10
0

Use UploadFileInfo.fromBytes if you're working with memory images (The error message above shows that your file is invalid and doesn't exist).

Mohammad Shahhoud
  • 469
  • 3
  • 6
  • 16
  • sorry,can you tell me what memory images ? i dont know about this – Zeffry Reynando Aug 15 '19 at 13:03
  • When you're uploading image from gallery, you can't access the image directly (because you're building your app for two different platforms Android and IOS), so it's better to work with the file bytes not the file path. For your case, try using ```UploadFileInfo.fromBytes(_image.readAsBytes(), 'image.png');``` – Mohammad Shahhoud Aug 15 '19 at 13:08
  • I'm using ` "image": UploadFileInfo.fromBytes(utf8.encode("Hellow Word"), '$_image')` , i'm get `message "Http status error [404]" ` ```DioErrorType (DioErrorType.RESPONSE)``` – Zeffry Reynando Aug 15 '19 at 13:10
  • 404 Status Code is ```Page Not Found```, so please check your link first and then try again. – Mohammad Shahhoud Aug 15 '19 at 13:13
  • If i'm using ` "image": UploadFileInfo.fromBytes(_image.readAsBytes(), 'image.png')` give me error ```The argument type 'Future>' can't be assigned to the parameter type 'List'``` . But if i'm write ```"image": UploadFileInfo.fromBytes(_image.readAsBytesSync(), 'image.png')``` error disappear. It's Different using `readAsBytes` and `readAsBytesSync` ? – Zeffry Reynando Aug 15 '19 at 13:14
  • Use this: ```UploadFileInfo.fromBytes(await _image.readAsBytes(), 'image.png')``` – Mohammad Shahhoud Aug 15 '19 at 13:16
  • give me `error :null message :"Http status error [404]" ` but i'm sure my Url API is correct. what's mean `"Http status error [404]"` this ? – Zeffry Reynando Aug 15 '19 at 13:24
  • sure, i'm already test in Postman, on top description i'm edit. it's works. i'm suspicious the image not found on app – Zeffry Reynando Aug 15 '19 at 13:48
  • If you comment sending the image, is this problem still exist? – Mohammad Shahhoud Aug 15 '19 at 13:50
  • If i,m just sending textcontroller not error,but if i'm include image error show. – Zeffry Reynando Aug 15 '19 at 21:08
0

Hi there are many issue in file upload

  1. 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.

  2. you might not able to get the file in above android version

  3. 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

Amit
  • 468
  • 5
  • 16
0

enter image description here

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);
Rasel Khan
  • 2,976
  • 19
  • 25