Flutter - how to compress an image - flutter

I am trying to compress image that is picked via file_picker package. I am compressing image with flutter_native_image. But image is not being compressed.
Where have I gone wrong?
P.S - I can't use image_picker package because it stopped working and I had to switch to file_picker.
class UploadSingleImageToFirestore extends StatefulWidget {
const UploadSingleImageToFirestore({super.key});
#override
State<UploadSingleImageToFirestore> createState() =>
_UploadSingleImageToFirestoreState();
}
class _UploadSingleImageToFirestoreState
extends State<UploadSingleImageToFirestore> {
File? _pickedImage;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarTitle(context, 'Upload Single Image'),
backgroundColor: ZayyanColorTheme.zayyanGrey,
body: _pickedImage != null
? Center(
child: Column(
children: [
ANPFormContainer(
fieldTitle: 'Single Image',
subTitle: 'Pick Single Image',
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 140),
child: Image.file(
File(_pickedImage!.path),
height: 300,
width: 300,
),
),
),
addVerticalSpacer(25),
ElevatedButton(
onPressed: () => pickImage(),
child: const Text('Pick Image')),
ElevatedButton(
onPressed: () => _updateMedia(),
child: const Text('Upload Images')),
],
),
)
: InkWell(
onTap: () => pickImage(),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.add_a_photo),
SizedBox(height: 10),
Text('Tap anywhere to pick images')
],
),
),
),
);
}
pickImage() async {
FilePickerResult? result =
await FilePicker.platform.pickFiles(type: FileType.image);
if (result != null) {
File file = File(result.files.single.path!);
print(file);
compressImage(file);
setState(() {
_pickedImage = file;
});
} else {
print("No file selected");
}
}
compressImage(path) async {
if (_pickedImage == null) return;
File compressedFile = await FlutterNativeImage.compressImage(
path,
quality: 10,
percentage: 20,
targetWidth: 600,
);
return compressedFile;
}
_updateMedia() async {
CollectionReference collectionRef =
FirebaseFirestore.instance.collection('Users');
final coverUrl = await context
.read<FirebaseStorageService>()
.saveCoverInCloudStorage(
file: _pickedImage!,
state: 'Test State',
township: 'Test Township',
propertyType: 'Test House',
propertyid: 'HYG-1234');
return collectionRef
.doc('gMH1s0XUIvWdD2fYfqMvPc915a03')
.update({
'logo': coverUrl,
})
.then((value) => ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Property Info Updated'))))
.catchError((error) => ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('+++ Failed to update user: $error"'))));
}
}

If your requirement is just images, Use image_picker instead of file_picker.
Fetching from image picker
You can use the built in imaqeQuality property from ImagePicker to compress the image. This property takes a value between 0 and 100 and represents a percentage of the original image quality.
File _image;
Future getImage() async {
var image = await ImagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 25,
);
setState(() {
_image = image;
});
}
Use flutter_native_image to compress
Future<File> compressFile(File file) async{
File compressedFile = await FlutterNativeImage.compressImage(file.path,
quality: 5,);
return compressedFile;
}
Also Refer: Flutter the best way to compress image

Related

Can't compress ImagePicker photo Flutter, returns null value

I tried compressing a photo taken using the ImagePicker Package, with the flutter_image_compress package. However, the photo '_file' returns a null value, instead of the newly compressed image. This code works when i dont try to compress it.
Future<Uint8List> testComporessList(Uint8List list) async {
var result = await FlutterImageCompress.compressWithList(
list,
minHeight: 1920,
minWidth: 1080,
quality: 96,
);
return result;
}
_selectImage(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return SimpleDialog(
title: const Text('Create a Post'),
children: [
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Take a photo'),
onPressed: () async {
Navigator.of(context).pop();
Uint8List file = await pickImage(
ImageSource.camera,
);
Uint8List file2 = await testComporessList(file);
setState(() async {
_file = await testComporessList(file2);
}
);
},
),
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
void clearImage() {
setState(() {**strong text**
_file = null;
});
}

Flutter, image_picker showing nothing when pressed

image_picker looks fine when i use it in emulator, when it's pressed it works properly but when i install it to my phone it does nothing when i pressed the button for image_picker no camera show just nothing change.
i think it has to be some persmission" things but i don't quite understand with it
method:
var selectedImagePath = ''.obs;
getImage(ImageSource ImageSource) async {
final pickedFile = await ImagePicker().pickImage(source: ImageSource);
if (pickedFile != null) {
selectedImagePath.value = pickedFile.path;
} else {
Get.snackbar('Error', 'No Image Selected');
}
}
display:
Scaffold(
body: SafeArea(
child: Column(
children: [
Obx(
() => Container(
width: double.infinity,
height: 400,
decoration: selectedImagePath == ''
? BoxDecoration(
color: Colors.grey,
)
: BoxDecoration(
color: Colors.grey,
image: DecorationImage(
image: FileImage(
File(
selectedImagePath.value,
),
),
fit: BoxFit.cover
),
),
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
getImage(ImageSource.camera);
},
child: Text('Take a photo'),
),
ElevatedButton(
onPressed: () {
getImage(ImageSource.gallery);
},
child: Text('Take from gallery'),
),
],
),
],
),
),
);
This works for me
File? _imageFile;
Future<void> getImage(
ImageSource source) async {
XFile? pickedFile = await ImagePicker()
.pickImage(source: source);
if (pickedFile != null) {
File selected = File(pickedFile.path);
_imageFile = selected;
}
}
Let me know if it works for you.
Here is my code, I'm using Provider Library to manage it.
Step 1:
//File? _image;
String? imgString;
ImagePicker? imagePicker = ImagePicker();
Step 2: Widget Code
Future getImage() async {
final dynamic image =
await imagePicker?.pickImage(source: ImageSource.gallery);
setState(() {
if (image != null) {
YourProvider.myImage = File(image.path);
YourProvider.pickedImage = true;
imgString = YourBaseUrl + YourProvider.myImage!.path;
debugPrint("Image: $imgString");
}
});
}
Step 3: Provider
bool pickedImage = false;
File? myImage;

Image is not getting Updated even after using setState In Flutter

I'm Using ImagePicker and ImageCropper Package to pick and crop an image from the gallery or by capturing using a camera. Everything is working fine but the Picked image is not updating on UI even after using the SetState method. When I press the button for image Selection Again Previously selected Image Appears on the UI. I have no Idea what Is causing this delay.
My ImageProcessing Class Code
class ImageProcess{
File _image, croppedFile;
final picker = ImagePicker();
//Getting Image From Gallery Or Camera.
File getImage(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: Container(
height: 250,
width: 250,
child: Row(
children: [
IconButton(
iconSize: 100,
icon: Icon(Icons.insert_photo),
onPressed: () async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery,imageQuality: 20);
_image = File(pickedFile.path);
croppedFile = await _cropImage();
Navigator.of(context).pop(true);
}),
IconButton(
iconSize: 100,
icon: Icon(Icons.camera),
onPressed: () async {
final pickedFile =
await picker.getImage(source: ImageSource.camera,imageQuality: 20);
_image = File(pickedFile.path);
croppedFile = await _cropImage();
Navigator.of(context).pop(true);
})
],
)),
);
});
return croppedFile;
}
//Cropping image which has been retrieved from gallery or gallery.
Future<File> _cropImage() async {
return await ImageCropper.cropImage(
sourcePath: _image.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
]
: [
CropAspectRatioPreset.square,
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Product Image Cropper',
toolbarColor: kDarkYellow,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.square,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Product Image Cropper',
));
}
}
Ui code
class AddItem extends StatefulWidget {
#override
_AddItemState createState() => _AddItemState();
}
class _AddItemState extends State<AddItem> {
File croppedFile;
ImageProcess im = new ImageProcess();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: kVeryDarkBlue,
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 20, 20, 0),
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height * 0.15,
width: MediaQuery.of(context).size.height * 0.15,
child: croppedFile == null
? ClipOval(
child:
Image.asset('assets/images/image.png'))
: ClipOval(child: Image.file(croppedFile))),
RaisedButton(onPressed: () {
croppedFile= im.getImage(context);
setState(() {
});
},child: Text('Press'),)
],
),
))),
);
}
}
I have tried every possible solution which came Into My mind.
Add Future in your getImage Method with some adjusts.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: AddItem(),
);
}
}
class AddItem extends StatefulWidget {
#override
_AddItemState createState() => _AddItemState();
}
class _AddItemState extends State<AddItem> {
File croppedFile;
ImageProcess im = new ImageProcess();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.blue,
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 20, 20, 0),
child: Column(
children: [
Container(
height: MediaQuery.of(context).size.height * 0.15,
width: MediaQuery.of(context).size.height * 0.15,
child: croppedFile == null
? ClipOval(
child: Image.asset('assets/images/image.png'))
: ClipOval(child: Image.file(croppedFile))),
RaisedButton(
onPressed: () async {
// Add await here
croppedFile = await im.getImage(context);
setState(() {});
},
child: Text('Press'),
)
],
),
))),
);
}
}
class ImageProcess {
File _image, croppedFile;
final picker = ImagePicker();
//Getting Image From Gallery Or Camera.
// now getImage is a future that wait for your choice.
Future<File> getImage(BuildContext context) async {
return await showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
content: Container(
height: 250,
width: 250,
child: Row(
children: [
IconButton(
iconSize: 100,
icon: Icon(Icons.insert_photo),
onPressed: () async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery, imageQuality: 20);
_image = File(pickedFile.path);
croppedFile = await _cropImage();
// croppedFile is the return of your ShowDialog
Navigator.of(context).pop(croppedFile);
}),
IconButton(
iconSize: 100,
icon: Icon(Icons.camera),
onPressed: () async {
final pickedFile = await picker.getImage(
source: ImageSource.camera, imageQuality: 20);
_image = File(pickedFile.path);
croppedFile = await _cropImage();
// croppedFile is the return of your ShowDialog
Navigator.of(context).pop(croppedFile);
})
],
)),
);
});
}
//Cropping image which has been retrieved from gallery or gallery.
Future<File> _cropImage() async {
return await ImageCropper.cropImage(
sourcePath: _image.path,
aspectRatioPresets: Platform.isAndroid
? [
CropAspectRatioPreset.square,
]
: [
CropAspectRatioPreset.square,
],
androidUiSettings: AndroidUiSettings(
toolbarTitle: 'Product Image Cropper',
toolbarColor: Colors.yellow,
toolbarWidgetColor: Colors.white,
initAspectRatio: CropAspectRatioPreset.square,
lockAspectRatio: false),
iosUiSettings: IOSUiSettings(
title: 'Product Image Cropper',
));
}
}
After Tweaking Some Lines of I have figured Out Where Was the Problem.
Code For RaisedButton In UI
RaisedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(15))),
content: Container(
height: 250,
width: 250,
child: Row(
children: [
IconButton(
iconSize: 100,
icon: Icon(Icons.insert_photo),
onPressed: () async {
croppedFile =
await im.getImageGallery();
setState(() {});
Navigator.pop(context);
}),
IconButton(
iconSize: 100,
icon: Icon(Icons.camera),
onPressed: () async {
croppedFile =
await im.getImageCamera();
setState(() {});
Navigator.pop(context);
})
],
)),
);
});
},
child: Text('Press'),
)
Code For ImageProcessing Class. I have Divided Large Function Into Two Sub Functions.
//Getting Image From Camera.
Future<File> getImageCamera() async{
final pickedFile = await picker.getImage(
source: ImageSource.camera,imageQuality: 20);
_image = File(pickedFile.path);
return _cropImage();
}
//Getting Image From Gallery
Future<File> getImageGallery() async{
final pickedFile = await picker.getImage(
source: ImageSource.gallery,imageQuality: 20);
_image = File(pickedFile.path);
return _cropImage();
}

Flutter image_picker package returns null when trying to retrieve a video from the gallery

I am trying to build an app that lets users select videos and upload them, so for this, I am using the image_picker package. However, I am currently running tests and whenever I try to select a video from the gallery, instead of getting a file back I get null. I don't know if the problem is with how I am using the package or with permissions, although according to the package you don't need permissions for android.
Below the function in my code that is giving me trouble:
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
The complete code (minus completely irrelevant things):
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:golfapp/data/course_data.dart';
import 'package:golfapp/data/user_data.dart';
import 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart';
import 'package:uuid/uuid.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:golfapp/data/semana_data.dart';
import 'package:golfapp/widgets/chewie_item.dart';
final StorageReference storageRef = FirebaseStorage.instance.ref();
final postsRef = Firestore.instance.collection('posts');
final DateTime timestamp = DateTime.now();
class DetailScreen extends StatefulWidget {
final int index;
final String photoUrl;
final String videoUrl;
DetailScreen({this.index, this.photoUrl, this.videoUrl});
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
bool isUploading = false;
bool selected = false;
List<File> files = [];
String postId = Uuid().v4();
TextEditingController captionController = TextEditingController();
showError() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Row(
children: [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: Text('Error'),
),
Icon(Icons.error_outline, size: 60.0),
],
),
content: SingleChildScrollView(
child: ListBody(
children: [
Text(
'Hubo un error con el video seleccionado.',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.w600,
fontSize: 17.0,
),
),
],
),
),
);
},
);
}
clearImage() {
setState(() {
this.selected = false;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File fileTaken = await ImagePicker.pickVideo(
source: ImageSource.camera,
maxDuration: Duration(seconds: 90),
);
setState(() {
if (fileTaken != null) {
this.files.add(fileTaken);
this.selected = true;
} else {
showError();
}
});
}
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
selectImage(parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Seleccionar video"),
children: <Widget>[
SimpleDialogOption(
child: Text("Tomar video"),
onPressed: handleTakePhoto,
),
SimpleDialogOption(
child: Text("Video de la galerĂ­a"),
onPressed: handleChooseFromGallery,
),
SimpleDialogOption(
child: Text("Cancelar"),
onPressed: () => Navigator.pop(context),
)
],
);
},
);
}
Future<String> uploadVideo(imageFile) async {
StorageUploadTask uploadTask = storageRef
.child(Provider.of<UserData>(context, listen: false).user.id)
.child(Provider.of<CourseData>(context, listen: false).course.uid)
.child(Provider.of<SemanaData>(context, listen: false).semana.uid)
.putFile(imageFile, StorageMetadata(contentType: 'video/mp4'));
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
createPostInFirestore({List<String> mediaUrl, String description}) {
postsRef
.document(Provider.of<UserData>(context, listen: false).user.id)
.collection("userPosts")
.document(Provider.of<CourseData>(context, listen: false).course.uid)
.setData({
"semana": Provider.of<SemanaData>(context, listen: false).semana.uid,
"postId": postId,
"ownerId": Provider.of<UserData>(context, listen: false).user.id,
"username": Provider.of<UserData>(context, listen: false).user.username,
"mediaUrl": mediaUrl,
"description": description,
"timestamp": timestamp,
"likes": {},
});
}
handleSubmit() async {
setState(() {
isUploading = true;
});
List<String> mediaUrlS = [];
for (File fileLoop in files) {
String mediaUrl = await uploadVideo(fileLoop);
mediaUrlS.add(mediaUrl);
}
createPostInFirestore(
mediaUrl: mediaUrlS,
description: captionController.text,
);
captionController.clear();
setState(() {
files = [];
isUploading = false;
postId = Uuid().v4();
selected = false;
});
}
Scaffold buildUploadForm() {
return Scaffold(
appBar: AppBar(
title: Text(
"Tu video",
style: TextStyle(color: Colors.black),
),
actions: [
FlatButton(
onPressed: files.length < 2 ? selectImage(context) : null,
child: Text(
'Seleccionar otro video',
),
),
FlatButton(
onPressed: isUploading ? null : () => handleSubmit(),
child: Text(
"Mandar",
),
),
],
),
body: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: files.length,
itemBuilder: (BuildContext context, int index) {
final File fileBuilder = files[index];
return Container(
height: 220.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
child: ChewieListItem(
videoUrl: fileBuilder.path,
network: false,
file: fileBuilder,
),
),
),
),
);
}),
);
}
Widget buildNormalScreen () {
return Container(
child: GestureDetector(
onTap: () {
selectImage(context);
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Theme.of(context).accentColor,
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Subir videos',
style: TextStyle(
fontFamily: 'Comfortaa',
fontSize: 17.0,
color: Colors.white,
),
),
],
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return !selected
? buildNormalScreen()
: buildUploadForm();
}
}
In the function at the top, I also tried doing something like ImagePicker.pickVideo().then((file){...}) but it didn't work.
I also added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> to my "android/app/src/main/AndroidManifest.xml" file.
I also tried adding android:requestLegacyExternalStorage="true" inside the <application> tag in my "android/app/src/main/AndroidManifest.xml" file, but then I get an error:
I don't know what I should be changing either in my code or in one of the files in the android folder, any help is deeply appreciated.
Thank you very much in advance
Put the condition in the same function.
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
);

Why I use setState in async funtion not update state (Flutter)?

Why my _image not update?
I need _image properties update when user pick new image from gallery or camera, but when user pick new images I use setState for set new value to _image but it didn't work(didn't update UI).
Here my code I have problem:
Sorry I cant full source because editor of stackoverflow complain to many code.
Statefull Class:
enum ChooseMedia { camera, gallery }
File _image;
void getImage(ChooseMedia media) async {
if (media == ChooseMedia.camera) {
var image = await ImagePicker.pickImage(source: ImageSource.camera);
var pathLocal = await getApplicationDocumentsDirectory();
await image.copy('${pathLocal.path}/profileImage.jpg').then((_) {
setState(() {
_image = image;
});
});
}
if (ChooseMedia.gallery == media) {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
var pathLocal = await getApplicationDocumentsDirectory();
await image.copy('${pathLocal.path}/profileImage.jpg').then((_) {
setState(() {
_image = image;
});
});
}
}
#override
Widget build(BuildContext context) {
return PopupMenuButton(
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(15))),
onSelected: (ChooseMedia media) {
getImage(media);
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<ChooseMedia>>[
const PopupMenuItem<ChooseMedia>(
value: ChooseMedia.gallery,
child: ListTile(
leading: Icon(
Icons.picture_in_picture,
),
title: Text('From galaxy'),
),
),
const PopupMenuItem<ChooseMedia>(
value: ChooseMedia.camera,
child: ListTile(
leading: Icon(Icons.camera),
title: Text('Take picture'),
),
),
],
child: Container(
decoration: BoxDecoration(),
padding: EdgeInsets.all(7),
child: CircleAvatar(
backgroundImage: _image == null
? AssetImage('assets/images/profile.jpg')
: FileImage(_image))),
);
}
You are mixing 'await' and 'then'
Just do
var copiedImage = await image.copy('${pathLocal.path}/profileImage.jpg');
setState(() {
_image = copiedImage;
});