How to fix this error
I am trying to reduce the size of an image file and here i use flutter_image_compress
Future<File> compressFile(File file) async {
var result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
file.absolute.path,
quality: 66,
);
return result!;
}
compressAndGetFile takes a String path and a String targetPath. They must be different or you'll have an error.
try this :
final file = await ImagePicker().pickImage(source: source);
var fileFromImage = File(file.path);
var basename = path.basenameWithoutExtension(fileFromImage.path);
var pathString = fileFromImage.path.split(path.basename(fileFromImage.path))[0];
var pathStringWithExtension = "$pathString${basename}_image.jpg";
Future<File> compressFile(File file) async {
var result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
pathStringWithExtension,
quality: 66,
);
return result!;
}
Also make sure you added flutter_image_compress to your pubspec.yaml
Related
I want to add the function which can upload multiple Photo image via ImagePicker
In this code, I can just upload single photo, not mutiple.
This app operating by flutter, dart and firebase server.
[Code]
void dispose() {
textEditingController.dispose();
super.dispose();
}
File _image;
Future _getImage() async {
var image = await ImagePicker.pickImage(
source: ImageSource.gallery,
maxWidth: 1000,
maxHeight: 1000,
);
setState(() {
_image = image;
});
}
Future _uploadFile(BuildContext context) async {
if (_image != null) {
final firebaseStorageRef = FirebaseStorage.instance
.ref()
.child('post')
.child('${DateTime.now().millisecondsSinceEpoch}.png');
final task = firebaseStorageRef.putFile(
_image,
StorageMetadata(contentType: 'image/png'),
);
final storageTaskSnapshot = await task.onComplete;
final downloadUrl = await storageTaskSnapshot.ref.getDownloadURL();
await Firestore.instance.collection('post').add(
{
'contents': textEditingController.text,
'displayName': widget.user.displayName,
'email': widget.user.email,
'photoUrl': downloadUrl,
'userPhotoUrl': widget.user.photoUrl,
});
}
final images = await _picker.pickMultiImage(
maxHeight: 1024,
maxWidth: 1024,
imageQuality: 50,
);
I created here 3 functions used to pick files from imagePicker and to upload them to firebase storage.
first, pick images from gallery:
final imageFiles = await pickImages();
second, upload the images:
final path = 'path/where/you/want/to/save/your/images';
final imageUrls = uploadImages(imagesFiles, path)
print(imageUrls);
you can now use the images urls to save to firestore
Future<List<File>> pickeImages() async {
ImagePicker picker = ImagePicker();
final images = await picker.pickMultiImage(
maxHeight: 1000, maxWidth: 1000, imageQuality: 90);
List<File> files = [];
if (images == null || images.isEmpty) return [];
for (var i = 0; i < images.length; i++) {
final file = File(images[i].path);
files.add(file);
}
return files;
}
Future<String?> _uploadImageFile(File file, String path) async {
try {
final storage = FirebaseStorage.instance;
TaskSnapshot? taskSnapshot;
final storageRef = storage.ref().child(path);
final uploadTask = storageRef.putFile(file);
taskSnapshot = await uploadTask.whenComplete(() {});
final imageUrl = await taskSnapshot.ref.getDownloadURL();
return imageUrl;
} catch (e) {
throw Exception(e.toString());
}
}
Future<List<String>> uploadImages(
List<File> files,
String path,
) async {
final urls = <String>[];
try {
if (files.isNotEmpty) {
for (var i = 0; i < files.length; i++) {
final file = files[i];
final imagePath = '$path/${Random().nextInt(10000)}.jpg';
final url = await _uploadImageFile(file, imagePath);
urls.add(url!);
}
}
return urls;
} on FirebaseException {
rethrow;
}
}
Instead of using ImagePicker.pickImage, use ImagePicker.pickMultiImage. That gives you a List instead of an XFile. Then you can just upload all images in the list. For instance, add an image parameter to your _uploadFile Function so that its function signature is
Future _uploadFile(BuildContext context, XFile image)
and just upload all images like
for (final image of images) {
_uploadFile(context, image)
}
I have a function to save network image to local cache files, but I have a trouble when store the list file that I downloaded to List<XFile>. Here is my download function:
List<XFile>? imageFileList = [];
Future<File> downloadImage(url, filename) async {
var httpClient = HttpClient();
try {
var request = await httpClient.getUrl(Uri.parse(url));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
final dir = await getTemporaryDirectory();
File file = File('${dir.path}/$filename');
await file.writeAsBytes(bytes);
print('downloaded file path = ${file.path}');
return file;
} catch (error) {
print('download error');
return File('');
}
}
is there any way so I can save the file to imageFileList as :
imageFileList!.add(file);
Convert the file to XFile:
XFile file = new XFile(file.path);
Change your list type:
from this:
List<XFile>? imageFileList = [];
to this:
List<File>? imageFileList = [];
final ImagePicker _picker = ImagePicker();
getImage() async {
var images = await _picker.pickMultiImage();
images!.forEach((image) {
setState(() {
_imageFileList!.add(File(image.path));
});
});
}
I'm trying to give an image uploaded from camera a unique id before uploading to Firestore.
I've been using Reed Barger's https://www.udemy.com/course/build-a-social-network-with-flutter-and-firebase/ tutorial but some of the code he used has been deprecated. In this case, image compression.
His code to compress and set unique image id was
compressImage() async {
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
Im.Image imageFile = Im.decodeImage(file.readAsBytesSync());
final compressedImageFile = File('$path/img_$postId.jpg')
..writeAsBytesSync(Im.encodeJpg(imageFile, quality: 85));
setState(() {
file = compressedImageFile;
});
}
The libraries he used include
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as Im;
import 'package:uuid/uuid.dart';
His variables were
File file;
String postId = Uuid().v4();
Since then, the image_picker library allows me to compress the image by seting the imageQuality so there's no need for the image.dart package. How can I modify my code (below) to set a unique image id in the format Reed used?
PickedFile file;
String postId = Uuid().v4();
handleTakePhoto() async {
Navigator.pop(context);
file = (await ImagePicker().getImage(
source: ImageSource.camera,
maxHeight: 675.0,
maxWidth: 960,
imageQuality: 85,
));
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
final compressedImageFile = File('$path/img_$postId.jpg');
setState(() {
this.file = file;
file = compressedImageFile;
});
}
As it is, it returns an error that compressedFileImage can't be assigned to type PickedFile.
I've tried adding the cast as PickedFile but that doesn't work.
That's because you're creating a File instead of a PickedFile:
final compressedImageFile = File('$path/img_$postId.jpg');
Just change it to:
final compressedImageFile = PickedFile('$path/img_$postId.jpg');
This has worked so far. I've created a variable File storedImage; Then changed
setState(() {
this.file = file;
file = compressedImageFile;
}
to
setState(() {
this.file = file;
storedImage = File(file.path);
storedImage = compressedImageFile;
print(compressedImageFile); //For debugging
}
The print statement gives me the new uuid and name.
Trying to generate an Thumbnail image from video , the file is created but , errors as Invalid image on load .Using this package video_thumbnail
Creating thumbnail ,
Future<File> genThumbnail(url) async {
//WidgetsFlutterBinding.ensureInitialized();
Uint8List bytes;
final Completer<ThumbnailResult> completer = Completer();
bytes = await VideoThumbnail.thumbnailData(
video: url,
imageFormat: ImageFormat.JPEG,
maxHeight: 250,
maxWidth: 300,
timeMs: 0,
quality: 0);
int _imageDataSize = bytes.length;
print("image size: $_imageDataSize");
//final _image = Image.memory(bytes);
//var _file =File.fromRawPath(bytes);
Directory tempDir = await getTemporaryDirectory();
var uint8list = bytes;
var buffer = uint8list.buffer;
ByteData byteData = ByteData.view(buffer);
File file = await File('${tempDir.path}/img/THUMBNAIL${DateTime.now().toIso8601String()}.JPEG').writeAsBytes(
buffer.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));
return file;
}
Saving to firestore
await genThumbnail(fileurl).then((_thumbFIle) async{
String Thumbfileurl = await uploadFile(_thumbFIle, 'thumbnailOf${filenamewithoutExtension}.JPEG', 'videothumbnail');
await sendFileToFirestoreChat(fileType, fileurl, filenamewithoutExtension,Thumbfileurl);
return fileurl;
});
The Saved Image ,
https://firebasestorage.googleapis.com/v0/b/proj-inhouse.appspot.com/o/videos%2Fvideothumbnails%2FthumbnailOfVID-20210301-WA0006.JPEG?alt=media&token=fa4f23c1-601f-486b-97d1-c63e221166af
Posting this as a Community Wiki as it's based on #pskink comments.
To resolve, add the writeAsBytes(bytes) instead of writeAsBytes(buffer.asUint8List()). There is no need for any buffer.
Since I can't convert convert a file directly from url (e.g File(url)).
I am downloading the file and then use the temp file path.
I tried different files : images, pdfs and it's still incomplete.
Am I doing something wrong here?
Future<String> downloadFile() async {
print(imgUrl);
Dio dio = Dio();
try {
var dir = await getApplicationDocumentsDirectory();
await dio.download(imgUrl, "${dir.path}/${widget.name}.pdf",
onReceiveProgress: (rec, total) {});
path = "${dir.path}/${widget.name}.pdf";
setState(() {
downloading = false;
progressString = "Completed";
});
if (path != null) {
List<int> imageBytes = File(path).readAsBytesSync();
print("NEW BYTE : $imageBytes");
}
} catch (e) {
print(e);
}
return path;
}
Checkout this solution:-
https://gist.github.com/Nitingadhiya/3e029e2475eeffac311ecd76f273941f
Uint8List? _documentBytes;
getPdfBytes() async {
_documentBytes = await http.readBytes(Uri.parse('https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf'));
return _documentBytes;
}
Future<void> readPDf() async {
//Load the existing PDF document.
Uint8List documentInBytes = await getPdfBytes();
final PdfDocument document = PdfDocument(inputBytes: documentInBytes);
//Get the existing PDF page.
final PdfPage page = document.pages[0];
//Draw text in the PDF page.
page.graphics.drawString('Hello World!', PdfStandardFont(PdfFontFamily.helvetica, 12), brush: PdfSolidBrush(PdfColor(0, 0, 0)), bounds: const Rect.fromLTWH(0, 0, 150, 20));
//Save the document.
final List<int> bytes = await document.save(); //document.saveSync();
await saveAndLaunchFile(bytes, 'Invoice.pdf');
//Dispose the document.
document.dispose();
}
Future<void> saveAndLaunchFile(List<int> bytes, String fileName) async {
//Get the storage folder location using path_provider package.
String? path;
if (Platform.isAndroid || Platform.isIOS || Platform.isLinux || Platform.isWindows) {
final Directory directory = await path_provider.getApplicationSupportDirectory();
path = directory.path;
} else {
path = await PathProviderPlatform.instance.getApplicationSupportPath();
}
final File file = File(Platform.isWindows ? '$path\\$fileName' : '$path/$fileName');
await file.writeAsBytes(bytes, flush: true);
if (Platform.isAndroid || Platform.isIOS) {
//Launch the file (used open_file package)
// await open_file.OpenFile.open('$path/$fileName');
} else if (Platform.isWindows) {
await Process.run('start', <String>['$path\\$fileName'], runInShell: true);
} else if (Platform.isMacOS) {
await Process.run('open', <String>['$path/$fileName'], runInShell: true);
} else if (Platform.isLinux) {
await Process.run('xdg-open', <String>['$path/$fileName'], runInShell: true);
}
}