🐛 IOS wrong camera preview orientation when rendering Camera with `<OrientationLocker orientation={PORTRAIT} />`
The problem
In my case I need to lock camera orientation to portrait only on camera page. Other parts of application can be oriented differently. When user rotates phone to Landscape-Left or Landscape-Right and then navigates to the Camera page with <OrientationLocker orientation={PORTRAIT} /> - the initial preview orientation of camera is wrong (return value of this function is not portrait: https://github.com/mrousavy/react-native-vision-camera/blob/aec24aa982532f9df602f2d3ec22b418d3677f19/package/ios/Core/OrientationManager.swift#L82C5-L82C75)
This causes weird behavior when user physically moves phone up - but the preview moves to the other direction (left or right). After rotating the phone back to portrait - this line https://github.com/mrousavy/react-native-vision-camera/blob/aec24aa982532f9df602f2d3ec22b418d3677f19/package/ios/Core/OrientationManager.swift#L62 is being called and interface orientation changes. After that, the preview orientation starts to work correctly, even when rotating back to Landscape-Left or Landscape-Right.
Workaround
I have applied this patch to fix:
diff --git a/android/README.md b/android/README.md
deleted file mode 100644
index 6eebb68d9f242a118d634455976c94c3936dd56c..0000000000000000000000000000000000000000
diff --git a/ios/Core/OrientationManager.swift b/ios/Core/OrientationManager.swift
index d9a41809ac4624446010261ab74720fe09c3ab9e..61e4f535cae6ac25e8625ad480339cfb823efe51 100644
--- a/ios/Core/OrientationManager.swift
+++ b/ios/Core/OrientationManager.swift
@@ -79,7 +79,7 @@ final class OrientationManager {
The orientation of the preview view.
*/
var previewOrientation: Orientation {
- return sensorOrientation.relativeTo(orientation: interfaceOrientation)
+ return Orientation.portrait
}
/**
diff --git a/ios/README.md b/ios/README.md
deleted file mode 100644
index 1c47fe132d3ab5ef1ed73fdc309ce34b91cf4c31..0000000000000000000000000000000000000000
In my case, all the places that use Camera are combined with <OrientationLocker orientation={PORTRAIT} /> - so this change does not break any other funcionality.
Reproduceable Code
See the fork https://github.com/AlexShukel/react-native-vision-camera
import React, { Fragment, useState } from 'react'
import { Camera, useCameraDevice } from 'react-native-vision-camera'
import { Button, StyleSheet, View } from 'react-native'
import { OrientationLocker, PORTRAIT } from 'react-native-orientation-locker'
export function App(): React.ReactElement | null {
const cameraPermission = Camera.getCameraPermissionStatus()
const microphonePermission = Camera.getMicrophonePermissionStatus()
console.log(`Re-rendering Navigator. Camera: ${cameraPermission} | Microphone: ${microphonePermission}`)
const [open, setOpen] = useState(false)
const device = useCameraDevice('back')
return (
<View style={styles.root}>
<Button
title="open"
onPress={() => {
setOpen(true)
}}
/>
{open && device !== undefined &&
<Fragment>
<OrientationLocker orientation={PORTRAIT} />
<Camera style={StyleSheet.absoluteFill} device={device} isActive outputOrientation="preview" />
</Fragment>
}
</View>
)
}
const styles = StyleSheet.create({
root: {
flex: 1,
},
})
Relevant log output
[ME]: maybeUpdateOrientations: previewOrientation=landscapeRight; lastPreviewOrientation=nil; outputOrientation=landscapeRight; lastOutputOrientation=nil
[ME]: maybeUpdateOrientations: previewOrientation=landscapeRight; lastPreviewOrientation=Optional(VisionCamera.Orientation.landscapeRight); outputOrientation=landscapeRight; lastOutputOrientation=Optional(VisionCamera.Orientation.landscapeRight)
11:37:35.282: [debug] 📸 VisionCamera.interfaceOrientation: [ME]: Interface Orientation changed from landscapeLeft -> portrait
[ME]: maybeUpdateOrientations: previewOrientation=portrait; lastPreviewOrientation=Optional(VisionCamera.Orientation.landscapeRight); outputOrientation=portrait; lastOutputOrientation=Optional(VisionCamera.Orientation.landscapeRight)
Camera Device
{
"id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
"minFocusDistance": 10,
"supportsLowLightBoost": false,
"maxExposure": 8,
"sensorOrientation": "portrait",
"maxZoom": 123.75,
"minZoom": 1,
"name": "Back Camera",
"hasFlash": true,
"minExposure": -8,
"isMultiCam": false,
"hardwareLevel": "full",
"neutralZoom": 1,
"supportsRawCapture": false,
"supportsFocus": true,
"physicalDevices": [
"wide-angle-camera"
],
"position": "back",
"hasTorch": true,
"formats": []
}
Device
iPhone SE (iOS 17.6.1)
VisionCamera Version
4.6.4
Can you reproduce this issue in the VisionCamera Example app?
Yes, I can reproduce the same issue in the Example app here
Additional information
- [ ] I am using Expo
- [ ] I have enabled Frame Processors (react-native-worklets-core)
- [x] I have read the Troubleshooting Guide
- [x] I agree to follow this project's Code of Conduct
- [x] I searched for similar issues in this repository and found none.
Guten Tag, Hans here. 🍻 Thank you for your detailed report! It looks like you are experiencing a valid issue with the camera orientation. You’ve provided a lot of information, and I really appreciate it.
To help further, could you please share any relevant logs from Xcode? This will greatly assist mrousavy in troubleshooting the problem. Proper logs are essential to diagnose such issues effectively.
If you continue to find this issue problematic, please consider sponsoring the project via GitHub Sponsors. It really helps us maintain the project and address issues more promptly.
Vielen Dank!
Note: If you think I made a mistake, please ping
@mrousavyto take a look.