Reputation: 393
I'm new to Dart/Flutter and currently using the Flutter Camera Plugin but I am running into a problem with the CameraPreview for when the phone turns to landscape mode. The images stay vertical and don't rotate the 90degrees with the phone.
I have tried countless things including Transform.rotate(), but I can't seem to get the image to both, fill the screen and rotate 90degrees.
The pictures that were taken while the phone was sideways still saved in the correct orientation when I view them, but using the _cameraPreviewWidget.
Upvotes: 13
Views: 14767
Reputation: 1
class _VideoPlayerWidgetState extends State<VideoPlayerWidget> {
VideoPlayerController _videoPlayerController;
ChewieController _chewieController;
@override
void initState() {
super.initState();
initializePlayer();
}
Future<void> initializePlayer() async {
// widget.url put url video file path
_videoPlayerController =
_videoPlayerController = VideoPlayerController.network(widget.url);
await Future.wait([_videoPlayerController.initialize()]);
_chewieController = ChewieController(
videoPlayerController: _videoPlayerController,
autoPlay: true,
looping: true,
);
}
bool useSensor = true;
bool portrait;
@override
Widget build(BuildContext context) {
return NativeDeviceOrientationReader(
builder: (context) {
NativeDeviceOrientation orientation =
NativeDeviceOrientationReader.orientation(context);
portrait = orientation == NativeDeviceOrientation.portraitUp;
if(orientation == NativeDeviceOrientation.landscapeLeft){
SystemChrome.setPreferredOrientations([
!portrait
? DeviceOrientation.landscapeLeft
: DeviceOrientation.portraitUp,
!portrait
? DeviceOrientation.landscapeLeft
: DeviceOrientation.portraitDown,
]);
}else{
SystemChrome.setPreferredOrientations([
!portrait
? DeviceOrientation.landscapeRight
: DeviceOrientation.portraitUp,
!portrait
? DeviceOrientation.landscapeRight
: DeviceOrientation.portraitDown,
]);
}
return _chewieController != null &&
_chewieController.videoPlayerController.value.isInitialized
? Chewie(
controller: _chewieController,
)
: Center(child: CircularProgressIndicator());
},
useSensor: useSensor,
);
}
@override
void dispose() {
_videoPlayerController.dispose();
_chewieController.dispose();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
super.dispose();
}
}
Upvotes: 0
Reputation: 491
In my case, a real Android device in Landscape orientation would show the appropriate camera preview content, but because the device wasn't "allowed" to rotate (due to app manifest/plist settings), it was showing as a strip where the Left to Right wide pixels were showing in a rectangle on the left side going from Bottom to Top, where that rectangle was small in order to fit in that dimension... so most of the screen was white empty space. On emulators, this phenomenon didn't occur (rotation worked as desired). The solution, after much searching and troubleshooting was to put some code in to modify what orientations were allowed, only while the camera preview was being displayed:
//allows any rotation (while camera preview is open)
Future<void> _enableRotation() async {
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
}
// may block rotation; sets orientation back to OS defaults for the app
Future<void> _backToOriginalRotation() async {
await SystemChrome.setPreferredOrientations([]);
}
I used await _enableRotation();
in initializing an ancestor of CameraPreview
and I used await _backToOriginalRotation();
in disposing.
I used WillPopScope
's onWillPop
callback and await Navigator.of(context).maybePop<String>>(filepath);
to close the view when a picture had been captured (and after the image had been saved to temp directory at the path filepath
), so that the Android back button would also run the dispose and rotation code via onWillPop
.
EDIT: After testing on both iOS and Android actual devices, this fix worked on Android phones, but did not work on iPhones. iPhones still displayed the camera preview in a small rotated strip when the device is landscape. This is using camera package version 0.8.1+7
.
EDIT2: After updating the iOS info.plist to allow any device orientation, this approach worked for iPhones too. However, there are still devices and situations where the preview orientation (and thus captured image orientation) are incorrect, leading to about 50% of captured landscape photos being saved sideways (in portrait orientation). Reproduction of the problem seems possible if you start your device in landscape orientation when you open the camera preview and don't rotate your device before capturing (or if device auto-rotate screen setting is off).
Upvotes: 0
Reputation: 799
My solution; using with this libraries; https://pub.dev/packages/image and https://pub.dev/packages/native_device_orientation
Future<void> takeAPicture()async{
pictureShooting=true;
final XFile image=await cameraController!.takePicture();
img.Image? _capturedImage=img.decodeImage(await image.readAsBytes());
final NativeDeviceOrientation currentOrientation=await _nativeDeviceOrientationCommunicator.orientation(useSensor: true);
switch(currentOrientation){
case NativeDeviceOrientation.landscapeRight: _capturedImage=img.copyRotate(_capturedImage!, 90);break;
case NativeDeviceOrientation.landscapeLeft: _capturedImage=img.copyRotate(_capturedImage!, 270);break;
case NativeDeviceOrientation.portraitDown: _capturedImage=img.copyRotate(_capturedImage!, 180);break;
default:
}
takenImage=Uint8List.fromList(img.encodePng(_capturedImage!));
pictureShooting=false;
showImageApprovalScreen=true;
}
Upvotes: 1
Reputation: 313
Adding SystemChrome.setPreferredOrientations() to my initState() & dispose() functions solved this problem for me.
import 'package:flutter/services.dart';
...
@override
void initState() {
super.initState();
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
@override
void dispose() {
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
}
Upvotes: 7
Reputation: 54397
A package call camera_camera https://pub.dev/packages/camera_camera
has do great work and provide great feature you can reference his source code or fork directly.
about rotate issue, please use this package https://pub.dev/packages/native_device_orientation
and wrap body like this
return Scaffold(
body: NativeDeviceOrientationReader(builder: (context) {
NativeDeviceOrientation orientation =
NativeDeviceOrientationReader.orientation(context);
you can reference full code at
https://github.com/marslord/camera/blob/master/lib/cam.dart ,this is not camera_camera package and author use RotateBox
return RotatedBox(
quarterTurns: turns,
child: Transform.scale(
scale: 1 / controller.value.aspectRatio,
child: Center(
child: AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: CameraPreview(controller),
),
),
),
);
camera_camera package use this at line 76
return NativeDeviceOrientationReader(
useSensor: true,
builder: (context) {
NativeDeviceOrientation orientation =
NativeDeviceOrientationReader.orientation(context);
about fit screen issue
camera_camera package do this with below code full code is here https://github.com/gabuldev/camera_camera/blob/master/lib/page/camera.dart
return widget.mode ==
CameraMode.fullscreen
? OverflowBox(
maxHeight: size.height,
maxWidth: size.height *
previewRatio,
child: CameraPreview(
bloc.controllCamera),
)
: AspectRatio(
aspectRatio: bloc
.controllCamera
.value
.aspectRatio,
child: CameraPreview(
bloc.controllCamera),
);
execute result of camera_camera package can found on his github
execute result of https://github.com/marslord/camera
both check with real device and works
official camera plugin example rotate image can work with combine Native_device_orientation
and RotateBox , you can reference https://github.com/marslord/camera/blob/master/lib/cam.dart
but official camera plugin example fit screen issue will need to modify layout code
I would suggest use camera_camera's method, Stack CameraPreview and Button. it looks more like Native Camera App and easy to maintain landscape mode
official camera plugin example rotate image code snippet with combine Native_device_orientation and RotateBox
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('Camera example'),
),
body: NativeDeviceOrientationReader(builder: (context) {
NativeDeviceOrientation orientation =
NativeDeviceOrientationReader.orientation(context);
int turns;
switch (orientation) {
case NativeDeviceOrientation.landscapeLeft:
turns = -1;
break;
case NativeDeviceOrientation.landscapeRight:
turns = 1;
break;
case NativeDeviceOrientation.portraitDown:
turns = 2;
break;
default:
turns = 0;
break;
}
return Column(
children: <Widget>[
Expanded(
child: RotatedBox(
quarterTurns: turns,
child: Transform.scale(
scale: 1 / controller.value.aspectRatio,
child: Container(
child: Padding(
padding: const EdgeInsets.all(1.0),
child: AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: Center(
child: _cameraPreviewWidget(),
),
),
),
Upvotes: 4
Reputation: 2600
When you rotate your phone while using a camera the preview will stay vertical, however when you view the image it will be in landscape, try with the default camera app and it would be the same
You can obviously rotate your UI that is on top of the camera preview when the phone rotates
Upvotes: 1