I can't work out how to save to the camera roll (the equivalent of React Native's CameraRoll saveToCameraRoll()
).
Here is my main.dart
below, so you can try to replicate it.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
List<CameraDescription> cameras;
Future<Null> main() async {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]);
cameras = await availableCameras();
runApp(new CameraApp());
}
class CameraApp extends StatefulWidget {
@override
_CameraAppState createState() => new _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
String _appDirectoryPath;
CameraController controller;
Future<void> _requestAppDirectory() async {
// QUESTION: `path_provider` doesn't have getCameraRollDirectory()
Directory _appDirectory = await getApplicationDocumentsDirectory();
setState(() {
_appDirectoryPath = _appDirectory.path;
});
}
@override
void initState() {
super.initState();
_requestAppDirectory();
controller = new CameraController(cameras[0], ResolutionPreset.medium);
controller.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!controller.value.initialized) {
return new Container();
}
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.red,
),
home: new Scaffold(
body: new Center(
child: new AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: new CameraPreview(controller),
),
),
floatingActionButton: new FloatingActionButton(
tooltip: 'Increment',
child: new Icon(Icons.camera),
onPressed: () {
print('capturing');
print(_appDirectoryPath);
// QUESTION: this errors out
controller.capture(_appDirectoryPath);
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
}
And here is what I see in the logs.
I/flutter ( 5471): capturing
I/flutter ( 5471): /data/user/0/com.example.mycameraapp/app_flutter
W/LegacyRequestMapper( 5471): convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
W/LegacyRequestMapper( 5471): Only received metering rectangles with weight 0.
W/LegacyRequestMapper( 5471): Only received metering rectangles with weight 0.
I/RequestThread-0( 5471): Received jpeg.
I/RequestThread-0( 5471): Producing jpeg buffer...
W/LegacyRequestMapper( 5471): convertRequestMetadata - control.awbRegions setting is not supported, ignoring value
W/LegacyRequestMapper( 5471): Only received metering rectangles with weight 0.
W/LegacyRequestMapper( 5471): Only received metering rectangles with weight 0.
E/flutter ( 5471): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 5471): CameraException(IOError, Failed saving image)
E/flutter ( 5471): #0 CameraController.capture (package:camera/camera.dart:234:7)
E/flutter ( 5471): <asynchronous suspension>
E/flutter ( 5471): #1 _CameraAppState.build.<anonymous closure> (file:///Users/briankung/workspace/mobile/flutter/my_camera_app/lib/main.dart:84:24)
E/flutter ( 5471): #2 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:478:14)
E/flutter ( 5471): #3 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:530:30)
E/flutter ( 5471): #4 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
E/flutter ( 5471): #5 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
E/flutter ( 5471): #6 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:123:7)
E/flutter ( 5471): #7 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
E/flutter ( 5471): #8 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:147:20)
E/flutter ( 5471): #9 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
E/flutter ( 5471): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
E/flutter ( 5471): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
E/flutter ( 5471): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
E/flutter ( 5471): #13 _invoke1 (dart:ui/hooks.dart:134:13)
E/flutter ( 5471): #14 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)
I/RequestQueue( 5471): Repeating capture request cancelled.
- Flutter camera suggests using
path_provider
to find application directories, but it doesn't seem to have an option to get the camera roll directory path. - I'm also getting an exception on
CameraController.capture
Please help. Cheers!
CodePudding user response:
Brian, you are seeing this error because you are trying to save your photo to /data/user/0/com.example.mycameraapp/app_flutter
. This is a directory, not a file!
Unfortunately, I don't think Flutter can currently expose this functionality. You will need to first turn off null safety and then you can use another package, like flutter_photokit
for example, to save your photo to camera roll. However, you would need to capture the photo to the device's temporary directory or application directory first and then from there you can transfer the file to a user's camera roll. Here's an example below.
// At the top of your file
import 'package:flutter_photokit/flutter_photokit.dart';
// Function in _CameraAppState
void _captureAndSaveToCameraRoll() async {
String outputFilepath = '$_appDirectoryPath/test.jpg';
// Capture the photo to your directory
await controller.capture(outputFilePath);
// Save the photo to camera roll
FlutterPhotokit.saveToCameraRoll(filePath: outputFilePath);
}
// Inside your build function
floatingActionButton: new FloatingActionButton(
tooltip: 'Increment',
child: new Icon(Icons.camera),
onPressed: _captureAndSaveToCameraRoll,
)