UNPKG

react-native-vision-camera

Version:

VisionCamera is the fastest and most powerful Camera for react-native.

137 lines (136 loc) 6.01 kB
import React, { useImperativeHandle, useMemo, useRef } from 'react'; import { callback } from 'react-native-nitro-modules'; import { useExposureUpdater } from '../hooks/internal/useExposureUpdater'; import { useGestureControllers } from '../hooks/internal/useGestureControllers'; import { useTorchModeUpdater } from '../hooks/internal/useTorchModeUpdater'; import { useZoomUpdater } from '../hooks/internal/useZoomUpdater'; import { useCamera } from '../hooks/useCamera'; import { usePreviewOutput } from '../hooks/usePreviewOutput'; import { NativePreviewView } from './NativePreviewView'; function getAnimatableNumberInitialValue(value) { if (value == null) return undefined; else if (typeof value === 'number') return value; else return value.get(); } function CameraImpl({ implementationMode, resizeMode, onPreviewStarted, onPreviewStopped, outputs = [], zoom, exposure, torchMode, enableNativeZoomGesture = false, enableNativeTapToFocusGesture = false, ref, ...props }) { // 1. Create `PreviewOutput` for the Camera const previewOutput = usePreviewOutput(); // 3. Create session/controller and add the preview output const controller = useCamera({ ...props, outputs: [previewOutput, ...outputs], getInitialExposureBias: () => getAnimatableNumberInitialValue(exposure), getInitialZoom: () => getAnimatableNumberInitialValue(zoom), }); // 4. Create `ref` for `PreviewView` const previewViewRef = useRef(null); const setHybridRef = useMemo(() => callback((r) => { previewViewRef.current = r; }), []); // 5. Create a ref that exposes some funcs on the Controller and the PreviewView. useImperativeHandle(ref, () => ({ startZoomAnimation(zoom, rate) { if (controller == null) throw new Error(`Camera is not yet ready!`); return controller.startZoomAnimation(zoom, rate); }, cancelZoomAnimation() { if (controller == null) throw new Error(`Camera is not yet ready!`); return controller.cancelZoomAnimation(); }, async focusTo(viewPoint, options = {}) { if (controller == null) throw new Error(`Camera is not yet ready!`); if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); const meteringPoint = previewViewRef.current.createMeteringPoint(viewPoint.x, viewPoint.y); await controller.focusTo(meteringPoint, options); }, async resetFocus() { if (controller == null) throw new Error(`Camera is not yet ready!`); await controller.resetFocus(); }, createMeteringPoint(x, y, size) { if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); return previewViewRef.current.createMeteringPoint(x, y, size); }, takeSnapshot() { if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); return previewViewRef.current.takeSnapshot(); }, convertCameraPointToViewPoint(cameraPoint) { if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); return previewViewRef.current.convertCameraPointToViewPoint(cameraPoint); }, convertViewPointToCameraPoint(viewPoint) { if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); return previewViewRef.current.convertViewPointToCameraPoint(viewPoint); }, convertScannedObjectCoordinatesToViewCoordinates(scannedObject) { if (previewViewRef.current == null) throw new Error(`Camera Preview is not yet ready!`); return previewViewRef.current.convertScannedObjectCoordinatesToViewCoordinates(scannedObject); }, get preview() { return previewViewRef.current ?? undefined; }, get controller() { return controller; }, }), [controller]); // 6. Update CameraController props useZoomUpdater(controller, zoom); useExposureUpdater(controller, exposure); useTorchModeUpdater(controller, torchMode); // 7. Attach any native gesture controllers if (enableNativeZoomGesture && zoom != null) { throw new Error(`\`zoom\` must not be set if \`enableNativeZoomGesture\` is enabled!`); } const gestureControllers = useGestureControllers({ controller: controller, enableNativeZoomGesture: enableNativeZoomGesture, enableNativeTapToFocusGesture: enableNativeTapToFocusGesture, }); // 8. Render view return (React.createElement(NativePreviewView, { ...props, implementationMode: implementationMode, resizeMode: resizeMode, gestureControllers: gestureControllers, // TODO: Memoize? onPreviewStarted: callback(onPreviewStarted), onPreviewStopped: callback(onPreviewStopped), hybridRef: setHybridRef, previewOutput: previewOutput })); } /** * The `<Camera />` component. * * This is a convenience wrapper around {@linkcode useCamera | useCamera(...)} * that adds a {@linkcode PreviewView}, wraps methods in a {@linkcode CameraRef}, * and supports updating {@linkcode CameraViewProps.zoom | zoom} and * {@linkcode CameraViewProps.exposure | exposure} via * Reanimated {@linkcode SharedValue}s. * * @example * ```tsx * function App() { * const camera = useRef<CameraRef>(null) * const device = useCameraDevice('back') * const photoOutput = usePhotoOutput() * * return ( * <Camera * style={StyleSheet.absoluteFill} * ref={camera} * device={device} * outputs={[photoOutput]} * isActive={true} * /> * ) * } * ``` */ export const Camera = React.memo(CameraImpl);