【问题标题】:Saving photo in Flutter (esp. to camera roll)在 Flutter 中保存照片(尤其是到相机胶卷)
【发布时间】:2018-09-22 16:04:15
【问题描述】:

我不知道如何保存到相机胶卷(相当于 React Native 的 CameraRoll saveToCameraRoll()。

  1. Flutter camera推荐使用path_provider获取应用目录,但是好像没有获取相机胶卷目录路径的选项。

  2. 我在CameraController.capture 上遇到异常

相关更改(并且只有相关更改,以差异的形式)在这里:https://gist.github.com/briankung/45f9d8438baab59ddcd3b6f3fe811d99

我的整个main.dart 在下面便于复制(搜索QUESTION: 以找到相关部分):

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,
      ),
    );
  }
}

日志信息如下:

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 --version
Flutter 0.2.8 • channel beta • https://github.com/flutter/flutter.git
Framework • revision b397406561 (10 days ago) • 2018-04-02 13:53:20 -0700
Engine • revision c903c217a1
Tools • Dart 2.0.0-dev.43.0.flutter-52afcba357

// pubspec.yaml

camera:
  dependency: "direct main"
  description:
    name: camera
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.1.2"
path_provider:
  dependency: "direct main"
  description:
    name: path_provider
    url: "https://pub.dartlang.org"
  source: hosted
  version: "0.4.0"

【问题讨论】:

    标签: file camera dart save flutter


    【解决方案1】:

    您可以使用来自pub.dev/packages/gallery_saver 的 gallery_saver,它将视频和图像保存在适用于 Android 和 iOS 的图库/照片中。

    你只需要提供一个文件或url的临时路径,它会保存本地文件和网络文件。

    它是这样使用的:

    GallerySaver.saveVideo(String path);
    GallerySaver.saveImage(String path);
    

    在成功保存案例文件时,这两个函数都返回 true,而在其他任何情况下都返回 false。

    我的团队开发了这个插件。

    【讨论】:

    • 欢迎来到 SO,感谢您编辑您的初始答案。请不要忘记透露您与该项目有关联,因为在该页面上它列出了一些 Jelena 作为包的作者。
    • 那我怎样才能得到输出路径呢?
    【解决方案2】:

    不幸的是,我不认为 Flutter 目前公开了这个功能。

    您最好的选择可能是编写一个插件或使用Platform Channels 来执行此操作。您可以像在this example 中那样使用临时目录,然后将路径传递给 android,您可以在其中读取文件并将其插入到图库中,如下所示:

    MediaStore.Images.Media.insertImage(
          getContentResolver(), 
          yourBitmap, 
          yourTitle , 
          yourDescription
    );`
    

    如果您在 Flutter 存储库之一中创建功能请求并且有人决定他们会通过为您编写插件来帮助您,您可能会很幸运。

    【讨论】:

    • 是的 - 它失败了,因为您将根目录作为写入图片的路径传递到 (/data/user/0/com.example.mycameraapp/app_flutter)。您应该传入一个文件名,例如/data/user/0/com.example.mycameraapp/app_flutter/savedpicture1.jpg
    • @rmtmckenzie 在 iOS 中实现将图像存储在相机胶卷中的任何想法,我被困了一个多星期。
    • 嗨@AravindhKumar - 你必须使用meothodChannel 以iOS 可以理解的格式发送数据,创建一个UIImage,然后使用UIImageWriteToSavedPhotosAlbum 保存它。创建 UIImage 取决于您尝试从颤振发送的内容。希望有帮助=)。但如果没有,你可能会更幸运地提出一个新问题。
    • 我确实在这里提出了这个问题link 寻求帮助以实现它,在我的代码中,我正在调用 cameracontroller.takePicture(filePath);所以我想我这里没有像 UIImage 这样的图像,或者我不知道如何使用它。这是我的sample camera view source code。
    • @AravindhKumar 我刚刚为此创建了flutter_photokit插件!看看:pub.dartlang.org/packages/flutter_photokit
    【解决方案3】:

    您遇到的错误是因为您试图将照片保存到/data/user/0/com.example.mycameraapp/app_flutter,这是一个目录,而不是一个文件。

    您可以在 iOS 上使用flutter_photokit 包将照片/视频保存到用户的相机胶卷/自定义相册中。您需要将照片捕获到设备的临时目录或应用程序目录,然后您可以从那里将文件传输到用户的相机胶卷。示例的相关部分如下所示:

    // At the top
    import 'package:flutter_photokit/flutter_photokit.dart';
    
    // Function in _CameraAppState
    void _captureAndSaveToCameraRoll() async {
      String outputFilePath = '$_appDirectoryPath/test.jpg';
      // Capture the photo to the app directory
      await controller.capture(outputFilePath);
      // Save the photo to the user's camera roll
      FlutterPhotokit.saveToCameraRoll(filePath: outputFilePath);
    }
    
    ...
    
    // In your build function
    floatingActionButton: new FloatingActionButton(
      tooltip: 'Increment',
      child: new Icon(Icons.camera),
      onPressed: _captureAndSaveToCameraRoll,
    )
    

    免责声明:我是这个插件的作者。

    【讨论】:

    • 你的插件已经过时了,不能再使用了!请检查您的拉取请求!
    猜你喜欢
    • 2014-09-04
    • 2012-07-22
    • 2012-05-01
    • 1970-01-01
    • 2013-04-03
    • 2013-07-18
    • 1970-01-01
    • 2013-07-22
    • 2014-04-21
    相关资源
    最近更新 更多