简体   繁体   中英

Flutter image upload when I select image from galery using image picker it will send using flutter and laravel REST API

I want to make a product image upload when I select image from gallery using image picker it will send using REST API. I'm looking up how to do so and I still don't get it, I tried different methods but always getting an errors occur. So if anyone knows whats best way to send image as multipart data to API. My goal is to connect flutter is frontend and laravel is backend. Thanks in advance

Flutter:

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

import 'package:image_picker/image_picker.dart';
import 'package:myapp/utils/api.dart';
import 'package:path/path.dart';
import 'package:flutter/foundation.dart' show kIsWeb;



class AddProduct extends StatefulWidget {
const AddProduct({Key? key}) : super(key: key);

@override
State<AddProduct> createState() => _AddProductState();
}

class _AddProductState extends State<AddProduct> {
bool _isLoading = false;
File? _image;

final _picker = ImagePicker();
// Implementing the image picker
Future<void> _openImagePicker() async {
final XFile? pickedImage =
    await _picker.pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
  setState(() {
    _image = File(pickedImage.path);
  });
}
}

@override
Widget build(BuildContext context) {

return Scaffold(
  body: Container(
    child: _isLoading ? const Center(child: CircularProgressIndicator()) : ListView(
      children: <Widget>[
        textSection(),
        imageProduct(),
        buttonSection(context) 

      ],
    ),
  ),
  appBar: AppBar(
      title: const Text('Add Product')
  ),      
);

}

Container buttonSection(BuildContext context) {
return Container(
  width: MediaQuery.of(context).size.width,
  height: 40.0,
  padding: const EdgeInsets.symmetric(horizontal: 15.0),
  margin: const EdgeInsets.only(top: 15.0),
  child: ElevatedButton(
    onPressed: () {
      setState(() {
        _isLoading = true;
      });          
      addProducts(context, File(_image!.path));
    },
    child: const Text("Create", style: TextStyle(color: Colors.white)),
  ),
);
}

final TextEditingController _productName = TextEditingController();
final TextEditingController _description = TextEditingController();
final TextEditingController _price = TextEditingController();

Container textSection() {
return Container(
  padding: const EdgeInsets.symmetric(horizontal: 15.0, vertical: 20.0),
  child: Column(
    children: <Widget>[
      TextFormField(
        controller: _productName,
        cursorColor: Colors.black,

        style: const TextStyle(color: Colors.black),
        decoration: const InputDecoration(
          hintText: "Product name",
          border: OutlineInputBorder(),
          hintStyle: TextStyle(color: Colors.black54),
        ),
      ),
      TextFormField(
        controller: _description,
        cursorColor: Colors.black,
        maxLines: 10,

        style: const TextStyle(color: Colors.black),
        decoration: const InputDecoration(
          hintText: "Description",
          border: OutlineInputBorder(),
          hintStyle: TextStyle(color: Colors.black54),
        ),
      ),
      TextFormField(
        controller: _price,
        cursorColor: Colors.black,

        style: const TextStyle(color: Colors.black),
        decoration: const InputDecoration(
          hintText: "Price",
          border: OutlineInputBorder(),
          hintStyle: TextStyle(color: Colors.black54),
        ),
      ), 
    ] 
  ),      
);
}

Widget imageProduct() {
return Center(
  child: Stack(children: <Widget>[
    SizedBox(
      width: 100,
      height: 100,
      child: _image != null ? (kIsWeb)
                ? Image.network(_image!.path,  fit: BoxFit.cover)
                : Image.file(_image!, fit: BoxFit.cover) : const Text('Please select an image'),
    ),        
    Positioned(
      bottom: 20.0,
      right: 20.0,
      child: InkWell(
        onTap: () {
          _openImagePicker();              
        },
        child: const Icon(
          Icons.camera_alt,
          color: Colors.teal,
          size: 28.0,
        ),
      ),
    ),
  ]),
);
}

Future addProducts(BuildContext context, File imageFile) async {

var token = 'abc';
 var request = http.MultipartRequest(
   'POST',
   Uri.parse(Api.baseUrl + 'product/new'),
);

Map<String, String> headers = {
  "Accept": "application/json",
  "Authorization": "Bearer " + token
};   
 request.files.add(await http.MultipartFile.fromPath('image', imageFile.path));
 request.headers.addAll(headers); 
 request.fields['product_name'] = _productName.text;
 request.fields['description'] = _description.text;
 request.fields['price'] = _price.text;
 
 var response = await request.send();
} 

}

I convert image to base64, I send base64 in the json to the API. In the API a convert base64 to image.

In flutter :

Future<String?> convertImgToBase64() async {
    try {
      File img = File(_imageFile!.path);
      final splitted = _imageFile!.path.split('.');
      final ext = splitted.last;
      final response = await img.readAsBytes();
      return "data:image/$ext;base64,${base64Encode(response)}";
    } catch (e) {
      //print(e.toString());
      return null;
    }
  }

In laravel :

public function convertImage(Request $request, $id) {
        if($request->has('avatar')) {
            $data = $request->avatar;
            if (preg_match('/^data:image\/(\w+);base64,/', $data, $type)) {
                $data = substr($data, strpos($data, ',') + 1);
                $type = strtolower($type[1]);
                $name = "avatar_{$id}.{$type}" ;
                if (!in_array($type, [ 'jpg', 'jpeg', 'png' ])) {
                    throw new \Exception('Invalid image type');
                }
                $data = str_replace( ' ', '+', $data );
                $data = base64_decode($data);
                if ($data === false) {
                    throw new \Exception('Base64_decode failed');
                }
            } else {
                throw new \Exception('Did not match data URI with image data');
            }
            Storage::disk('local')->put("gallery/avatars/{$name}", $data);
            return $name;
            /*/if (file_put_contents($destination_path.$name, $data) != false) {
                return $name;
            } else {
                throw new \Exception('Unable to save image');
            }*/

        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM