19

I am getting dark images from flutter Camera Plugin.

Camera Preview is showing correctly but after taking the picture it becomes too dark.

I searched and what i found that it's about the FPS and exposure of the camera.

How can I solve this problem?

I need to show camera preview and take pictures in my app.

Please don't tell me to use image_picker package.

Device : Redmi note 4

Android OS : 7.0

Here is the Image

dark image

Here is the code


import 'dart:async';
import 'dart:io';

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' show join;
import 'package:path_provider/path_provider.dart';

Future<void> main() async {
  // Obtain a list of the available cameras on the device.
  final cameras = await availableCameras();

  // Get a specific camera from the list of available cameras.
  final firstCamera = cameras.first;

  runApp(
    MaterialApp(
      theme: ThemeData.dark(),
      home: TakePictureScreen(
        // Pass the appropriate camera to the TakePictureScreen widget.
        camera: firstCamera,
      ),
    ),
  );
}

// A screen that allows users to take a picture using a given camera.
class TakePictureScreen extends StatefulWidget {
  final CameraDescription camera;

  const TakePictureScreen({
    Key key,
    @required this.camera,
  }) : super(key: key);

  @override
  TakePictureScreenState createState() => TakePictureScreenState();
}

class TakePictureScreenState extends State<TakePictureScreen> {
  CameraController _controller;
  Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    // To display the current output from the Camera,
    // create a CameraController.
    _controller = CameraController(
      // Get a specific camera from the list of available cameras.
      widget.camera,
      // Define the resolution to use.
      ResolutionPreset.medium,
    );

    // Next, initialize the controller. This returns a Future.
    _initializeControllerFuture = _controller.initialize();
  }

  @override
  void dispose() {
    // Dispose of the controller when the widget is disposed.
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Take a picture')),
      // Wait until the controller is initialized before displaying the
      // camera preview. Use a FutureBuilder to display a loading spinner
      // until the controller has finished initializing.
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            // If the Future is complete, display the preview.
            return CameraPreview(_controller);
          } else {
            // Otherwise, display a loading indicator.
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.camera_alt),
        // Provide an onPressed callback.
        onPressed: () async {
          // Take the Picture in a try / catch block. If anything goes wrong,
          // catch the error.
          try {
            // Ensure that the camera is initialized.
            await _initializeControllerFuture;

            // Construct the path where the image should be saved using the
            // pattern package.
            final path = join(
              // Store the picture in the temp directory.
              // Find the temp directory using the `path_provider` plugin.
              (await getTemporaryDirectory()).path,
              '${DateTime.now()}.png',
            );

            // Attempt to take a picture and log where it's been saved.
            await _controller.takePicture(path);

            // If the picture was taken, display it on a new screen.
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => DisplayPictureScreen(imagePath: path),
              ),
            );
          } catch (e) {
            // If an error occurs, log the error to the console.
            print(e);
          }
        },
      ),
    );
  }
}

// A widget that displays the picture taken by the user.
class DisplayPictureScreen extends StatelessWidget {
  final String imagePath;

  const DisplayPictureScreen({Key key, this.imagePath}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Display the Picture')),
      // The image is stored as a file on the device. Use the `Image.file`
      // constructor with the given path to display the image.
      body: Image.file(File(imagePath)),
    );
  }
}

shubham chhimpa
  • 263
  • 3
  • 10
  • I'd love to help you but I've tried your code and on my OnePlus 6T (with Android 10) the photos come out fine, not dark like the example you shared. I can't reproduce your issue. What other packages for the camera have you used, do they all have the same issue? – J. S. Jan 04 '20 at 19:49
  • 2
    Did you ever read my comment? You bountied this question but didn't even reply to the one comment you received. – J. S. Jan 09 '20 at 19:33
  • i think it's camera problem , if it not try to use image_picker packagehttps://pub.dev/packages/image_picker – Omar Sherif Jan 27 '20 at 12:25
  • @OmarSherif read the post carefully... i said don't tell me to use image_picker package. There is nothing wrong in my camera... – shubham chhimpa Jan 30 '20 at 08:52
  • I tried it on a Pixel 3, photo also came out fine like Joao mentioned. However, this may be specific to certain devices, https://github.com/flutter/flutter/issues/19038 & https://github.com/flutter/flutter/issues/26079 Can you also post your issue there? Thanks! – TWL Feb 12 '20 at 18:34
  • Try adding await Thread.sleep(500); in between initialize and takepicture – Ratnadeep Bhattacharyya Feb 20 '20 at 05:30
  • @RatnadeepBhattacharyya i tried it already its not working for me.. did it worked for you? – shubham chhimpa Mar 04 '20 at 06:07
  • @RatnadeepBhattacharyya nup – shubham chhimpa May 14 '20 at 07:00
  • What if you use platform specific code and follow the answer in this post: https://stackoverflow.com/questions/49691541/how-to-change-camera-exposure-on-android – Brandon Pillay Jan 09 '21 at 09:41

3 Answers3

1

Just put delay before take picture.

Future.delayed(const Duration(milliseconds: 500), () {
_controller.takePicture(path);
});
Lordkkjmix
  • 19
  • 2
1

I think it's not about a delay, images are dark if exposure is not handled. Also exposure requires focus pre captures to work and are not handled in official plugin now.

You can use this plugin : CamerAwesome

Official plugin has been quite abandonned. This plugin includes flash, zoom, auto focus, exposure... and no initialisation required. It uses value notifier to change data directly in preview like this :

  // init Notifiers
  ValueNotifier<CameraFlashes> _switchFlash = ValueNotifier(CameraFlashes.NONE);
  ValueNotifier<Sensors> _sensor = ValueNotifier(Sensors.BACK);
  ValueNotifier<Size> _photoSize = ValueNotifier(null);

  @override
  Widget build(BuildContext context) {
    return CameraAwesome(
      onPermissionsResult: (bool result) { }
      selectDefaultSize: (List<Size> availableSizes) => Size(1920, 1080),
      onCameraStarted: () { },
      onOrientationChanged: (CameraOrientations newOrientation) { },
      zoom: 0.64,
      sensor: _sensor,
      photoSize: _photoSize,
      switchFlashMode: _switchFlash,
      orientation: DeviceOrientation.portraitUp,
      fitted: true,
    );
  };
Dharman
  • 30,962
  • 25
  • 85
  • 135
mcfly
  • 774
  • 1
  • 8
  • 18
1

A hack that works for me, with camera plugin: take the picture twice. The first one buys time for the second one to have the proper exposure and focus.

final image = await controller.takePicture(); // is not used
final image2 = await controller.takePicture(); 
lajosbacs
  • 43
  • 9