12

Iam using CameraPreview for measuring height of an object,But the issue was i cant able to set cameraPreview height full screen..

I have tried Positioned widget, it fills the screen but the image was stretched. I have tried Transform Widget, but height does not fills fullscreen, white space is coming.Image is not stretched.

Mycode:

final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;

return Stack(
            children: <Widget>[
              Transform.scale(
                scale: controller.value.aspectRatio/deviceRatio,
                child: new AspectRatio(
                  aspectRatio: controller.value.aspectRatio,
                  child: new CameraPreview(controller),
                ),
              ),);

Kindly help me to fit CameraPreview "FULLSCREEN" without image streching..

enter image description here

Navin Kumar
  • 3,393
  • 3
  • 21
  • 46

9 Answers9

35

CameraValue.aspectRatio returns width / height rather than height / width since 0.7.0, and CameraPreview handles AspectRatio itself now, so imo the working code snippet would be as follows:

/// only work inside WidgetsApp or MaterialApp, which introduces a MediaQuery
final scale = 1 / (controller.value.aspectRatio * MediaQuery.of(context).size.aspectRatio);
return Transform.scale(
  scale: scale,
  alignment: Alignment.topCenter,
  child: CameraPreview(controller),
);

update:

After scale by Transform the preview may paint off screen-size limit when used in a TransitionRoute. (When hosted in a CupertinoPageRoute a drag gesture will clearly show this).

So I think it would be a good idea to clip the preview to make it exactly matching the screen size.

final mediaSize = MediaQuery.of(context).size;
final scale = 1 / (controller.value.aspectRatio * mediaSize.aspectRatio);
return ClipRect(
  clipper: _MediaSizeClipper(mediaSize),
  child: Transform.scale(
    scale: scale,
    alignment: Alignment.topCenter,
    child: CameraPreview(controller),
  ),
);
class _MediaSizeClipper extends CustomClipper<Rect> {
  final Size mediaSize;
  const _MediaSizeClipper(this.mediaSize);
  @override
  Rect getClip(Size size) {
    return Rect.fromLTWH(0, 0, mediaSize.width, mediaSize.height);
  }
  @override
  bool shouldReclip(CustomClipper<Rect> oldClipper) {
    return true;
  }
}
wangpan
  • 461
  • 4
  • 5
  • This should be the accepted answer. Actually it makes sense to clip the preview size from the camera to the devices screen size. Non of all the methods I have seen actually followed the idea of clipping to the screen size. non actually worked for me but this. Thanks man. – Emmanuel Edwards Jan 29 '22 at 21:53
6

Issue has been solved by wrapping Centre widget in Transform widget

final size = MediaQuery.of(context).size;
final deviceRatio = size.width / size.height;
return Stack(
            children: <Widget>[
              Center(
                child:Transform.scale(
                      scale: controller.value.aspectRatio/deviceRatio,
                      child: new AspectRatio(
                       aspectRatio: controller.value.aspectRatio,
                       child: new CameraPreview(controller),
                       ),
                   ),),);
Navin Kumar
  • 3,393
  • 3
  • 21
  • 46
  • 1
    hi, can you please edit your answer so it looks the same as you wrote in this article in section "Display CameraPreview": https://medium.com/@navinkumar0118/take-a-picture-using-flutter-camera-a9c11d282632 – rexxar Apr 14 '20 at 07:57
  • 3
    Tested According to Article and above Code Snippet, Image get stretched and major image portion is not showing at all. – Skandar Munir Aug 15 '21 at 03:37
6

Try wrapping the CameraPreview in a FittedBox with BoxFit.cover and make sure the parent container equals the space you want to fill.

@override
Widget build(BuildContext context) {
  final size = MediaQuery.of(context).size;

  return Scaffold(
      body: cameraController == null
          ? const Text("Loading Camera...")
          : Container(
              width: size.width,
              height: size.height,
              child: FittedBox(
                fit: BoxFit.cover,
                child: Container(
                    width: 100, // the actual width is not important here
                    child: CameraPreview(cameraController!)),
              )));
}
Luciano van der Veekens
  • 6,307
  • 4
  • 26
  • 30
4

You can fix this by wrapping the CameraPreview inside a LayoutBuilder and a SizedBox based on the constraints of the LayoutBuilder like:

      LayoutBuilder(
        builder: (context, constraints) {
          return SizedBox(
            width: constraints.maxWidth,
            height: constraints.maxHeight,
            child: CameraPreview(controller),
          );
        },
      ),

it will work like a charm

3

just use:

 var isPortrait =
            MediaQuery.of(context).orientation == Orientation.portrait;
        Size mediaSize = MediaQuery.of(context).size;
        return SizedBox(
          width: mediaSize.width,
          height: mediaSize.height,
          child: FittedBox(
            fit: BoxFit.cover,
            child: SizedBox(
                width: isPortrait
                    ? _controller!.value.previewSize!.height
                    : _controller!.value.previewSize!.width,
                height: isPortrait
                    ? _controller!.value.previewSize!.width
                    : _controller!.value.previewSize!.height,
                child: CameraPreview(_controller!)),
          ),
        );
Jagie
  • 2,190
  • 3
  • 27
  • 25
1

Unfortunately both Wangpan and Navin Kumar's answers did not work for me. But the following solution did work for me.

I have two state widget fields: The cameraControllerKey, used to make a reference to the Container holding the CameraPreview. The cameraPreviewScale used to store the size of the original cameraPreview.

In my build method I first let the CameraView build its UI and set the scale to 1, meaning that I just let it draw itself as it comes (so not full screen... Yet). Also note that i set the key to my GlobalKey cameraControllerKey. In the addPostFrameCallback method I calculate the scale based on the Container view size that holds the CameraPreview and the actual screenSize. I hope it helps for you, happy fluttering.

///field in widget state
var cameraControllerKey = GlobalKey();
double? cameraPreviewScale;


/// In build method
if(cameraPreviewScale==null){
  WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
    final screenSize = MediaQuery.of(context).size;
    final previewSize = cameraControllerKey.currentContext!.size!;
    setState(() {
      cameraPreviewScale = screenSize.width / previewSize.width;    
    });
  });
}

return Scaffold(
key: _scaffoldKey,
body: 
  Stack(
    fit: StackFit.loose,
    children: [
      Center(
        child: Container(
            key: cameraControllerKey,
            child: Transform.scale(
                alignment: Alignment.center,
                scale: cameraPreviewScale ?? 1,
                child: CameraPreview(cameraController!))),
      ),
    ],
  )
);
EvertvdBraak
  • 1,033
  • 1
  • 12
  • 20
  • check to see if this works on devices without 16:9 aspect ratio, because it doesn't fill the screen on my iphone 13 pro with a 19.5:9 aspect ratio. – greenzebra Apr 14 '22 at 19:16
0
final mediaSize = MediaQuery.of(context).size;
return Transform.scale(
scale: 1 /
(cameraController.value.aspectRatio  * mediaSize.aspectRatio),
alignment: Alignment.center,
child: CameraPreview(cameraController),);
  • 7
    Welcome to Stack Overflow. Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please [edit] your question and explain how it answers the specific question being asked. See [answer]. – ChrisGPT was on strike Sep 09 '21 at 18:20
-1

I following the demo from the https://flutter.dev/docs/cookbook/plugins/picture-using-camera

and I do not customize the AspectRatio of the CameraPreview (actually I did but it not working).

The way I solve it is very simple.

return Stack(
  children: [
    Container(
        width: double.infinity,
        height: double.infinity,
        child: CameraPreview(_cameraController))
  ],
);

I am using the attributes width and height of Container widget to make the CameraPreview stretch as fullsceen.

Cuong Vo
  • 648
  • 9
  • 12
-2

This code works for Flutter version 2.8 and above

return Stack(
  children: [
    Positioned(
      top: 0,
      bottom: 0,
      child: CameraPreview(_cameraController!),
    ),
  ],
);