react-native-vision-camera
react-native-vision-camera copied to clipboard
🐛 Adding border around Camera's direct parent causes offset preview
What's happening?
Using [email protected] on an iPhone 13 Mini, adding a border to the direct parent of a Camera component causes the preview to be offset and slightly smaller than it should be, despite the Camera having a style of StyleSheet.absolutefill (see first screenshot). Setting borderWidth: 0 prevents the issue (see second screenshot). I believe the offset size is related to the borderWidth, since doubling the borderWith seems to double the offset (see third screenshot). This only happens on my iPhone 13 Mini, not on my Android S10, leading me to believe that this is an iOS-only issue. I did not face this same issue when I was on 2.15.4, but only started hitting it when I recently upgraded from 2.15.4 to 3.3.1.
Here's a workaround for others hitting this issue (see fourth screenshot). Just add an additional View component without a border as the direct child of your bordered component, and as direct parent of the Camera.
<View style={{ borderWidth: 8, borderColor: 'red', ... }}>
{/* Add the view below as a workaround */}
<View style={StyleSheet.absoluteFill}>
<Camera ... />
</View>
</View>
With borderWidth: 8:
With borderWidth: 0:
With borderWidth: 16:
With borderWith: 8 and workaround:
Reproduceable Code
// Modifying the 3.3.1 example app CameraPage.ts line 172
// https://github.com/mrousavy/react-native-vision-camera/blob/a498144fd5786c6dba1d78730d362e0f675cbaf7/package/example/src/CameraPage.tsx#L172
// The 2 Views are added, the ReanimatedCamera is unchanged, aside from disabling the fpsGraph
// Note that in order to get the 3.3.1 example app to build, I needed to comment out the line 289 in CameraView+AVCaptureSession.swift
// https://github.com/mrousavy/react-native-vision-camera/blob/a498144fd5786c6dba1d78730d362e0f675cbaf7/package/ios/CameraView%2BAVCaptureSession.swift#L289
<View style={{ flex: 1, justifyContent: 'center' }}>
<View style={{ alignSelf: 'center', borderWidth: 8, borderColor: 'red', height: 150, width: 150 }}>
<ReanimatedCamera ... />
</View>
</View>
Relevant log output
No relevant log outputs or errors, just a style issue
Camera Device
{
"maxZoom": 121.875,
"minZoom": 1,
"hasTorch": true,
"isMultiCam": false,
"hardwareLevel": "full",
"position": "back",
"physicalDevices": [
"wide-angle-camera"
],
"supportsRawCapture": false,
"supportsFocus": true,
"neutralZoom": 1,
"name": "Back Camera",
"hasFlash": true,
"id": "com.apple.avfoundation.avcapturedevice.built-in_video:0",
"supportsLowLightBoost": false,
"sensorOrientation": "portrait",
"formats": []
}
Device
iPhone 13 Mini (iOS 16.6.1)
VisionCamera Version
3.3.1
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.
Regarding the note below from my code in the Reproduceable Code section:
// Note that in order to get the 3.3.1 example app to build, I needed to comment out the line 289 in CameraView+AVCaptureSession.swift
// https://github.com/mrousavy/react-native-vision-camera/blob/a498144fd5786c6dba1d78730d362e0f675cbaf7/package/ios/CameraView%2BAVCaptureSession.swift#L289
I believe that this build failure is likely unrelated to this bug report, but for completeness, here's the error message:
'NSInvalidArgumentException', reason: '*** -[AVCaptureFigVideoDevice setAutomaticallyEnablesLowLightBoostWhenAvailable:] Not supported - use -isLowLightBoostSupported'
Lol this is an interesting issue
I have a similar issue with 3.6.4 on an iPhone XS Max
Page Structure:
It's a flexbox layout - the header and controls are 75 pixels high and the camera is 100% with flexShrink = 1, so I expect it to occupy the full space between the header above and controls below:
Camera Function
Stylesheet
Result: the magenta background is the camera background
If I change the Camera Function as follows, wrapping the camera in two containers (AbsoluteFill is needed on the camera and the immediate parent):
The display is as expected:
@davidredshaw I had the same issue and was able to fix it by wrapping the Camera component in a View with flex 1. Try changing it to
<View style={{flex: 1, backgroundColor: 'green`}}>
<Camera style={{flex:1}} ... />
</View>
Hey - I think this issue has been fixed in VisionCamera 4.0.0. 🥳
Please try V4 and let me know if you still experience this issue;
- if not, please consider 💖 sponsoring me on GitHub 💖 to support the development of VisionCamera and thank me for my time spent on fixing bugs and building new features.
- if you still see this issue, please comment and we can re-open this. But please update your native logs with the native (Xcode/Android Studio) logs from running VisionCamera V4 so I can investigate this.
Hey Marc- congrats on the v4 release, and thanks for all of your great work on this library!
After upgrading my app from [email protected] to [email protected], I can confirm that the general issue of borders causing an offset camera preview remains, although the details of the issue and workaround have changed.
I would recommend reopening this issue.
On iOS with v4, the extra-view workaround mentioned above still works fine. Without the workaround, the preview offset still occurs (see screenshot 1 below).
On Android with v4, I'm now seeing similar offset preview issues (see screenshot 2 below). Recall that in v3 this seemed like an iOS-only issue. Interestingly, the offset on Android is in the opposite direction as on iOS. On iOS the camera preview is offset to the bottom right, but on Android it is offset to the top left (compare screenshots 1 and 2 below)
Furthermore, the extra-view workaround mentioned above wasn't sufficient on Android. Instead I now need to wait for the Camera to be initialized before setting the absoluteFill style.
I tried to see if the waiting-workaround would be enough to prevent the issue on iOS too, but it still needed the extra-view workaround. Fortunately, the new combined workaround seems to be working on both iOS and Android. I tested this on an iPhone 13 mini and a Samsung Galaxy S10.
New workaround for v4
function MyBorderedCamera() {
const [cameraInitialized, setCameraInitialized] = useState(false);
// ...
return (
<View style={{ borderWidth: 8, borderColor: 'purple', ... }}>
{/* Add the View below as a workaround on iOS */}
<View style={StyleSheet.absoluteFill}>
<Camera
// ...
// Wait for the camera to be initialized as a workaround on Android
onInitialized={() => setCameraInitialized(true)}
style={cameraInitialized && StyleSheet.absoluteFill}
/>
</View>
</View>
);
}