Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable torch flash for camera in Flutter?

Tags:

flutter

I am trying to take pictures with torch flash with the camera in Flutter. How do you add an option to use torch flash when taking a picture?

I use the following camera package: https://pub.dev/packages/camera#-installing-tab- for the camera. I have tried both the https://pub.dev/packages/lamp and https://pub.dev/packages/torch packages for turning on the torch and make it flash. It seems to me that there is no built-in torch feature in the camera package, so I tried using a separate torch package that.

TakePictureScreen widget:

class TakePictureScreenState extends State<TakePictureScreen> {
  CameraController _controller;
  Future<void> _initializeControllerFuture;
  double displayWidth = 1;
  double displayHeight = 1;
  bool showFlashButton;
  bool isFlashActivated;

  @override
  void initState() {
    super.initState();
    showFlashButton = false;
    isFlashActivated = false;
    switchShowLampButton();
    _controller = CameraController(widget.camera, ResolutionPreset.high);
    _initializeControllerFuture = _controller.initialize();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    displayWidth = MediaQuery.of(context).size.width;
    displayHeight = MediaQuery.of(context).size.height;
    return WillPopScope(
      child: Scaffold(
        appBar: AppBar(backgroundColor: Color(0xFF276272)),
        body: FutureBuilder<void>(
          future: _initializeControllerFuture,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.done) {
              return CameraPreview(_controller);
            } else {
              // Otherwise, display a loading indicator
              return Center(child: CircularProgressIndicator());
            }
          },
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Flexible(
              child: buildCameraButton(),
            ),
            Flexible(
              child: buildFlashButton(),
            )
          ],
        ),
      ),
      onWillPop: onPop,
    );
  }

  Future<bool> onPop() async {
    Navigator.pop(this.context, null);
    return false;
  }

  Future cameraButtonPressed() async {
    try {
      await _initializeControllerFuture;

      // Construct the path where the image should be saved using the path
      // package.
      final path = join(
        // In this example, 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
      Future<bool> savePhotoOnPop = Navigator.push(
        this.context,
        MaterialPageRoute(
          builder: (context) => DisplayPictureScreen(imagePath: path),
        ),
      );

      savePhotoOnPop.then((savePhoto) {
        if (savePhoto) {
          var file = File(path);
          var fileBytesFuture = file.readAsBytes();
          fileBytesFuture.then((fileBytes) {
            Navigator.pop(this.context, fileBytes);
          });
        }
      });
    } catch (e) {
      print(e);
    }
  }

  void flashButtonPressed() async {
    await Lamp.turnOn(intensity: 1.0);
    setState(() {
      isFlashActivated = !isFlashActivated;
    });
  }

  Widget buildCameraButton() {
    return Container(
      margin: EdgeInsets.only(bottom: displayHeight * 0.01),
      width: displayWidth * 0.175,
      height: displayWidth * 0.175,
      child: RawMaterialButton(
        shape: CircleBorder(),
        fillColor: Color(0xff10846D),
        onPressed: cameraButtonPressed,
        child: Icon(
          Icons.camera_alt,
          color: Colors.white,
          size: displayWidth * 0.1,
        ),
      ),
    );
  }

  Widget buildFlashButton() {
    if (showFlashButton)
      return Container(
        width: displayWidth * 0.175,
        height: displayWidth * 0.175,
        child: RawMaterialButton(
          shape: CircleBorder(),
          fillColor: Color(0xff10846D),
          onPressed: flashButtonPressed,
          child: Icon(
            isFlashActivated ? Icons.flash_on : Icons.flash_off,
            color: isFlashActivated ? Colors.white : Color(0xFF999999),
            size: displayWidth * 0.1,
          ),
        ),
      );
    else
      return SizedBox(height: 0);
  }

  void switchShowLampButton() {
    Lamp.hasLamp.then((hasLamp) {
      setState(() {
        showFlashButton = hasLamp;
      });
    });
  }
}

When flashButtonPressed() is called, I expect the torch on the phone to be turned on.

There are two different results depending on if I use the Lamp- or Torch package:

  • Lamp package: No exception or error, but the torch is never turned on and nothring happens.

  • Torch package: I get the following error "Torch for camera "0" is not available due to an existing camera user".

So it seems like there is a conflict between using the torch and the camera at the same time. But since I haven't seen any built-in option in the camera package for using the torch when taking a picture, I don't know how to solve this.

Thanks!

like image 475
EggBender Avatar asked Aug 20 '19 10:08

EggBender


Video Answer


1 Answers

lamp is only supported till API 20 (Kitkat), use torch dependency instead.

Here is an example using a torch dependency

class CameraHomeScreen extends StatefulWidget {
  final List<CameraDescription> cameras;

  CameraHomeScreen(this.cameras);

  @override
  State<StatefulWidget> createState() {
    return _CameraHomeScreenState();
  }
}

class _CameraHomeScreenState extends State<CameraHomeScreen> {
  String imagePath;
  bool _toggleCamera = false;
  bool _toggleFlash = false;
  String _icFlash = "assets/icons/ic_flash_off.png";
  String _lensDirection = "CameraLensDirection.back";
  CameraController controller;

  @override
  void initState() {
    try {
      onCameraSelected(widget.cameras[0]);
    } catch (e) {
      print(e.toString());
    }
    super.initState();
  }

  @override
  void dispose() {
    controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (widget.cameras.isEmpty) {
      return Container(
        alignment: Alignment.center,
        padding: EdgeInsets.all(16.0),
        child: Text(
          'No Camera Found',
          style: TextStyle(
            fontSize: 16.0,
            color: Colors.white,
          ),
        ),
      );
    }

    if (!controller.value.isInitialized) {
      return Container();
    }

    return Transform.scale(
      scale: 1 / controller.value.aspectRatio,
      child: Center(
        child: AspectRatio(
          aspectRatio: controller.value.aspectRatio,
          child: Container(
            child: Stack(
              children: <Widget>[
                CameraPreview(controller),
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    width: MediaQuery.of(context).size.width,
                    height: 100.0,
                    color: Colors.transparent,
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: <Widget>[
                        _lensDirection == "CameraLensDirection.back" ? Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () async {
                              bool hasTorch = await Torch.hasTorch;
                              if (hasTorch) {
                                if (!_toggleFlash) {
                                  Torch.turnOn();
                                  setState(() {
                                    _icFlash = "assets/icons/ic_flash_on.png";
                                    _toggleFlash = true;
                                  });
                                } else {
                                  Torch.turnOff();
                                  setState(() {
                                    _icFlash = "assets/icons/ic_flash_off.png";
                                    _toggleFlash = false;
                                  });
                                }
                              }
                            },
                            child: Container(
                              child: Image.asset(
                                _icFlash,
                                width: 15.0,
                                height: 15.0,
                              ),
                            ),
                          ),
                        ) : Container(
                          width: 15.0,
                          height: 15.0,
                        ),
                        Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () {
                              _captureImage();
                            },
                            child: Container(
                              child: Image.asset(
                                'assets/icons/ic_shutter.png',
                                width: 50.0,
                                height: 50.0,
                              ),
                            ),
                          ),
                        ),
                        Material(
                          color: Colors.transparent,
                          child: InkWell(
                            borderRadius:
                                BorderRadius.all(Radius.circular(50.0)),
                            onTap: () {
                              if (!_toggleCamera) {
                                onCameraSelected(widget.cameras[1]);
                                setState(() {
                                  _toggleCamera = true;
                                });
                              } else {
                                onCameraSelected(widget.cameras[0]);
                                setState(() {
                                  _toggleCamera = false;
                                });
                              }
                            },
                            child: Container(
                              child: Image.asset(
                                'assets/icons/ic_switch_camera.png',
                                width: 18.0,
                                height: 18.0,
                              ),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  void onCameraSelected(CameraDescription cameraDescription) async {
    if (controller != null) await controller.dispose();
    controller = CameraController(cameraDescription, ResolutionPreset.medium);
    controller.addListener(() {
      if (mounted) setState(() {
        _icFlash = "assets/icons/ic_flash_off.png";
        _toggleFlash = false;
        _lensDirection = cameraDescription.lensDirection.toString();
      });
      if (controller.value.hasError) {
        showMessage('Camera Error: ${controller.value.errorDescription}');
      }
    });

    try {
      await controller.initialize();
    } on CameraException catch (e) {
      showException(e);
    }

    if (mounted) setState(() {});
  }

  String timestamp() => new DateTime.now().millisecondsSinceEpoch.toString();

  void _captureImage() {
    takePicture().then((String filePath) {
      if (mounted) {
        setState(() {
          imagePath = filePath;
        });
        if (filePath != null) {
          showMessage('Picture saved to $filePath');
          setCameraResult();
        }
      }
    });
  }

  void setCameraResult() {
//    Navigator.pop(context, imagePath);
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => Preview(path: imagePath)),
    );
  }

  Future<String> takePicture() async {
    if (!controller.value.isInitialized) {
      showMessage('Error: select a camera first.');
      return null;
    }
    final Directory extDir = await getApplicationDocumentsDirectory();
    final String dirPath = '${extDir.path}/FlutterDevs/Camera/Images';
    await new Directory(dirPath).create(recursive: true);
    final String filePath = '$dirPath/${timestamp()}.jpg';

    if (controller.value.isTakingPicture) {
      // A capture is already pending, do nothing.
      return null;
    }

    try {
      await controller.takePicture(filePath);
    } on CameraException catch (e) {
      showException(e);
      return null;
    }
    return filePath;
  }

  void showException(CameraException e) {
    logError(e.code, e.description);
    showMessage('Error: ${e.code}\n${e.description}');
  }

  void showMessage(String message) {
    print(message);
  }

  void logError(String code, String message) =>
      print('Error: $code\nMessage: $message');
}
like image 132
Bittu Patel Avatar answered Oct 15 '22 10:10

Bittu Patel