Search code examples
iosfluttercamera

Flutter Camera Package: Stream/Picture from Camera is -90° rotated


I am using the official Flutter (Flutter 1.22.6 • channel stable) camera Plugin (https://pub.dev/packages/camera) within 2 Flutter apps. The stripped-down code sniped is used in both apps (pure copy & paste).

However, results in both apps are different in terms of their orientation. The problem is not to provide the user a correct output on the screen. This is possible with either CameraPreview or RotatedBox. I am using the buildPreview() method from the CameraController to see "What the camera sees" (at least I hope it does).

What is needed is to record a picture from the CameraController-Stream in the correct orientation (straight up) to process it with some AI SDKs. Or as a workaround some easy and lightweight way to turn it 90 degree as an Uint8List. What is not possible is to do it just with some meta-data.

Should be worth mentioning the more complex app (where the rotation is wrong) has two restrictions:

  • In the iOS project under General there is no Device Orientation selected and a bit below "Requires full screen" is checked.
  • The app is initialized in the main-Method with await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);

What I already tried without success:

  • Making the orientation and "Requires full screen" configuration the same in both apps.
  • Setting the SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); in the initState
  • Use await controller.lockCaptureOrientation(DeviceOrientation.portraitUp);
  • Removed any camera plugins restrictions from the iOS Podfile

I have no clue why there is this difference. Any thoughts what I should try out or this is would be amazing!

Correct orientation - pure example App Incorrect orientation - integrated into a more complex App but same source-code like the example one.

import 'dart:async';
import 'dart:typed_data';

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Timer timer;
  CameraController controller;
  CameraImage image;
  Future<CameraController> init;

  @override
  void initState() {
    init = initialize();
    super.initState();
  }

  Future<CameraController> initialize() async {
    var cameras = await availableCameras();
    controller = CameraController(cameras[0], ResolutionPreset.medium);
    await controller.initialize();
    controller.startImageStream((image) {
      this.image = image;
    });
    timer = Timer.periodic(Duration(seconds: 5), (timer) async {
      print('start scanning');
    });
    return controller;
  }

  Future<void> outText(CameraImage image) async {
    Uint8List bytes = image.planes[0].bytes;
    // AI magic...
    return;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: FutureBuilder<CameraController>(
          future: init,
          builder: (context, snapshot) {
            if (snapshot.hasData)
              return Center(
                  child: snapshot.hasData
                      ? SizedBox(child: snapshot.data.buildPreview())
                      : CircularProgressIndicator());
            else
              return SizedBox.shrink();
          },
        ),
      ),
    );
  }
}

Solution

  • After a few more hours the only difference is the camera plugin version between both results.

    It looks like a bug that happens with camera: ^0.7.0 and later.

    To get the correct result the workaround would be to use: camera: ^0.6.4+5 or earlier.

    A bug is opened there: https://github.com/flutter/flutter/issues/76210