Send picture to server api with post request [FLUTTER] - flutter

I want to take picture, which should contain just a few letters, with my phone and then send it to a server where it will convert the picture to a text string.
My imported packages:
import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
I currently have this camera function:
// Camera implementation
File? _image;
final ImagePicker _picker = ImagePicker();
Future getImage() async {
final image = await _picker.pickImage(source: ImageSource.camera);
setState(() {
_image = File(image!.path);
});
}
And I use it in this button:
// Camera button
ElevatedButton.icon(
onPressed: getImage,
icon: const Icon(Icons.camera_alt_rounded),
label: const Text('Scan'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green[500]),
textStyle: MaterialStateProperty.all(const TextStyle(fontSize: 26)),
)
)
I have tested to just send some data to jsonplaceholder and it works, but I can't get understand how to implement it to a picture that should be sent to my server.
// Send Data to the Server (TEST VERSION)
postDataTest() async{
try{
var response = await http.post(Uri.parse("https://jsonplaceholder.typicode.com/posts"),
body: {
"id": 1.toString(),
"name": "Hax",
}
);
print(response.body);
} catch(e){
print(e);
}
}
TLDR. I want to take a picture and send it to a server.

Use multipart
Upload(File img) async {
var uri = Uri.parse(uploadURL);
var request = new http.MultipartRequest("POST", uri);
request.files.add( new http.MultipartFile.fromBytes("file", img.readAsBytesSync(), filename: "Photo.jpg", contentType: new MediaType("image", "jpg")));
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}

Picture to text for archive this you need to convert image into base64. Check this link
However, it's generally a bad idea to store large blobs of binary data in your database. you will end up wasting bandwidth transmitting data.it also decrease mobile app performance while you read large blob data. you don't need as well as unnecessary encoding and decoding.
You can send picture to server using multipart api request.
So you can archive mutipart request with api in various packages
https - dart documentation
Dio
You can also check multipartRequest on Stackoverflow.

I managed to solve it with this function:
// Upload camera photo to server
Future uploadImage() async {
final uri = Uri.parse("url to the server");
var request = http.MultipartRequest('POST', uri);
var takenPicture = await http.MultipartFile.fromPath("image", _image!.path);
request.files.add(takenPicture);
var response = await request.send();
if(response.statusCode == 200){
print('Image uploaded!');
} else{
print('Image not uploaded');
}
}

file.path is path of image u can use file picker or image picker in flutter
baseimage = "";
if(file.path != '') {
List<int> imageBytes = file.readAsBytesSync();
baseimage = base64Encode(imageBytes);
}
send image as a string and decode base64 in your server
laravel exemple using spatie media
if (isset($request->image)) {
$fiche_client->addMediaFromBase64($request->image)
->usingFileName(Str::random(10).'.png')
->toMediaCollection('magasin');
}

Related

how to upload image to the server against different key using MultupartFile in Flutter..?

suppose you have to upload image to the Server using MultipartFile for a single key like "image". you can easily can do it but if you have different types of keys for file like
"image", "logo", "banner" etc
so how can you handle this for different types keys..
it is working for single key like "image"
final request = http.MultipartRequest('PUT', url,);
request.fields.addAll(body.toMap());
request.headers.addAll(headers);
if (body.image.isNotEmpty) {
final file = await http.MultipartFile.fromPath('image', body.image);
request.files.add(file);
}
Add additional fields if needed
request.fields['field1'] = 'value1';
request.fields['field2'] = 'value2';
full code
import 'dart:io';
import 'package:http/http.dart' as http;
uploadImage(File imageFile) async {
final url = 'http://example.com/upload-image';
var request = http.MultipartRequest('POST', Uri.parse(url));
// Create a MultipartFile from the image file
var image = await http.MultipartFile.fromPath('image', imageFile.path);
// Attach the MultipartFile to the MultipartRequest
request.files.add(image);
// Add additional fields if needed
request.fields['field1'] = 'value1';
request.fields['field2'] = 'value2';
// Send the MultipartRequest to the server
var response = await request.send();
// Check the response status code
if (response.statusCode == 200) {
// Image upload successful
print('Image uploaded successfully');
} else {
// Image upload failed
print('Image upload failed with status ${response.statusCode}');
}
}
I think this will help you

Send image picker file to the backend

So I have this code that picks the image
Container(
child: ElevatedButton(
onPressed: () async {
result = await FilePicker.platform
.pickFiles(allowMultiple: true);
if (result == null) {
print("No file selected");
} else {
setState(() {
result?.files.forEach((element) {
attachmentController.text =
element.name;
statusController.text = "pending";
});
});
result?.files.forEach((element) {
print(element.name);
});
}
},
and I wanted to send this image to the backend of laravel but first, I have an attachment controller that saves the element.name but turns out it's just a name. May I please know how to save the image in the controller and if any links to show how to save that in the laravel backend please?
Thank you
If you are only picking images i will suggest you to use the image_picker package.
In your widget file :
File? image;
...
image= await ImagePicker.pickImage(source: ImageSource.gallery);
setState({});
You can use Image.file, widget factory method to show the image.
In your Api file :
import 'package:http/http.dart' as http;
import 'dart:convert';
...
var response = await http.post('example.com/api',
body: {
'image': base64Encode(await imageFile.readAsBytes()),
},
);
Depending on your Laravel you handle the request, decode it from base64 and save it to a folder.

Sending base64 image from flutter

I'm facing a strange issue lately. I have to send a base64 encoded image from flutter to a remote API. The problem is that I convert the image using below code:
Future getProfileImage() async {
final _pickedFile =
await _imagePicker.getImage(source: ImageSource.gallery);
_profileImage = await File(_pickedFile!.path);
print("${_pickedFile.toString()}");
//print("${_pickedFile.path}");
List<int> _profileImageBytes = await _profileImage!.readAsBytesSync();
_profileImageBase64 = await base64Encode(_profileImageBytes);
print("$_profileImageBase64");
}
But when I try to send using following code:
Future updateProfile() async {
print("$_profileImageBase64");
String pre = "data:image/jpg;base64,";
String imageString = '';
print("$imageString");
if (_profileImageBase64 == null) {
imageString = '';
} else {
imageString = "$pre$_profileImageBase64";
}
String apiUrl = "http://162.0.236.163:3000/api/users/profile-update";
Map<String, String> header = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': "Bearer ${widget.user.token}"
};
print(
"Bearer ${widget.user.token}, ${_firstName!.controller!.text}, ${_lastName!.controller!.text}");
//print("$imageString");
//log(imageString);
Map<String, String> body = {
'firstName': _firstName!.controller!.text,
'lastName': _lastName!.controller!.text,
'image': imageString
};
print("${body["image"]}");
http.Response reponse =
await http.post(Uri.parse(apiUrl), body: body, headers: header);
//print("${jsonDecode(reponse.body)}");
var data = jsonDecode(reponse.body) as Map;
print("$data");
if (data["status"] == 1) {
widget.user.first = _firstName!.controller!.text;
widget.user.last = _lastName!.controller!.text;
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('firstName', widget.user.first.toString());
prefs.setString('lastName', widget.user.last.toString());
}
setState(() {});
}
it fails. Strange thing is that when I print the string at the start of above method, it shows different value, but when I print body["image"] it is slightly different string. Moreover, what is surprising is that when I copy any of these Strings from console, and hardcode them for image String, the code is successful. I can't figure out why I cannot successfully send the image using a String variable, which effectively has same code. Can anyone help please?
Edit: I have just realized that the string may not be printed in console completely. When I check the length of the String it is almost 314000 characters for base64 (220kb file). But in console few thousands appear. The one from console can be successfully
sent, but full string fails. Can this be due to limitation on server end
Well, if there isn't a problem with authorization, and shorter strings are successfully saved, then it sounds like some form of data validation is performed on the server-side (API) that is limiting either that field or the entire message body.
If the data is being stored in a database, make sure the image field is large enough to hold that many characters.
One suggestion to try is to reduce the size of the image before you convert it to base64. There are a few optional arguments on the getImage method in the 'image_picker' package that allows you to specify a maxHeight (width would be proportional) and image quality.
import 'dart:async';
import 'dart:io' as Io;
import 'dart:convert';
import 'package:image_picker/image_picker.dart';
final pickedFile = await picker.getImage(
source: ImageSource.gallery,
maxHeight: 150,
imageQuality: 90,
);
final bytes = await pickedFile.readAsBytes();
final b64img = base64.encode(bytes);

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/File to Strapi (Flutter Web)

I'm trying to upload an image to Strapi through Flutter Web. I'm aware (from this link) that I need to use FormData to do so. I've researched on many ways to do this and I stumble across Dio and of course Http.
Both solutions gave me errors:
Unsupported operation: MultipartFile is only supported where dart:io is available.
I've tried this code:
var request = new http.MultipartRequest("POST", Uri.parse(url));
request.files.add(
await http.MultipartFile.fromPath(
"files",
imageFilePath,
),
);
request.send().then((response) {
if (response.statusCode == 200) print("Uploaded!");
print(response.statusCode);
}).catchError((e) => print(e));
As suggested here.
And many other getting errors or Empty Data (400), when I use MultipartFile.fromBytes(...).
I'm just trying to upload a file, therefore I assume my body should only contain the FormData with as files as it's mentioned on Strapi's Documentation.
So, I searched on the Flutter Discord for some help and I found out that my problem happens because Flutter Web can't use 'dart:io' , and using 'dart:html' takes away the use of all of Flutter's platforms.
I ended up using this imports:
import 'dart:convert';
import 'dart:typed_data';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:path/path.dart';
import 'package:async/async.dart';
and this is the function I created and worked:
Future<bool> uploadImage(
String imageFilePath,
Uint8List imageBytes,
) async {
String url = SERVERURL + "/uploadRoute";
PickedFile imageFile = PickedFile(imageFilePath);
var stream =
new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var uri = Uri.parse(url);
int length = imageBytes.length;
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('files', stream, length,
filename: basename(imageFile.path),
contentType: MediaType('image', 'png'));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
I had this issue using Strapi and this solution worked like a charm.
Upload file during entry creation with Flutter
dio: ^3.0.10, mime: ^1.0.0 and http_parser.
The main part is the key name of the file if it's foo, so you have to change files.image with files.foo for file upload
final mimeType = mime.lookupMimeType(imageFile.path, headerBytes: [0xFF, 0xD8])?.split('/');
FormData formData = new FormData.fromMap(
{
"files.image": await MultipartFile.fromFile(
imageFile.path,
filename: imageFile.path.split('/').last,
contentType: MediaType(mimeType?[0], mimeType?[1]),
),
"data": jsonEncode({
"title": title,
"summary": summary,
"content": content,
}),
},
);
Response response = await _dio.post(
"/blogs",
data: formData,
options: Options(),
);
In Flutter Web:
I am using node.js with express as backend source I have created the following simple method to upload image and text data to localhost server using xamp
String url = 'http://localhost:8080/blog_upload';
var request = http.MultipartRequest('POST', Uri.parse(url));
imagebytes = await image.readAsBytes();
List<int> listData = imagebytes!.cast();
request.files.add(http.MultipartFile.fromBytes('field_name', listData ,
filename:'myFile.jpg'));
request.fields['name'] = 'Mehran Ullah Khan';
request.fields['country'] = 'Pakistan';
var response = await request.send();
I have used the following dependencies in the above method.
http: ^0.13.3
image_picker: ^0.8.2
how we used the image_picker?
first globally declare image and imagebytes
image = await ImagePicker().pickImage(source: ImageSource.gallery);
And this is the method in the backend I have used.
app.post('/blog_upload', upload.single('field_name'), async (req, res, next) => {
let data = {name_db: req.body['name'], Country_db:req.body['country'],};
let sqlq = `INSERT INTO TableName SET ? `;
db.query(sqlq, data, (insertionErr, insertionResult) => {
if (insertionErr) {
console.log('failed_upload');
throw insertionErr;
}
else {
console.log('done_upload');
res.send(insertionResult);
}
});
});
In the above method I have used
multer and express packages
You can see full details for multer and express in this link
#Diego Cattarinich Clavel
String url = Constants.BASE_URL + HttpUrls.categories;
PickedFile imageFile = PickedFile(path);
var stream =
new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
var uri = Uri.parse(url);
int length = imageBytes.length;
var request = new http.MultipartRequest(
"PUT",
uri,
);
var multipartFile = new http.MultipartFile(
'files.categoryImage',
stream,
length,
filename: basename(imageFile.path),
contentType: MediaType('image', 'png'),
);
request.files.add(multipartFile);
request.fields['data'] = '{"category":$category}';
print(request.url);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});