UNPKG

vision-camera-mrz-scanner

Version:

VisionCamera Frame Processor Plugin to detect and read MRZ data from passports using MLKit Text Recognition.

264 lines (249 loc) 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactNative = require("react-native"); var _reactNativeReanimated = require("react-native-reanimated"); var _reactNativeVisionCamera = require("react-native-vision-camera"); var _visionCameraMrzScanner = require("vision-camera-mrz-scanner"); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const MRZCamera = _ref => { let { enableBoundingBox, boundingBoxStyle, boundingBoxHorizontalPadding, boundingBoxVerticalPadding, style, skipButtonEnabled: photoSkipButtonEnabled, skipButton: photoSkipButton, onSkipPressed: photoSkipOnPress, skipButtonStyle: photoSkipButtonStyle, cameraProps, onData, scanSuccess, skipButtonText, cameraDirection, isActiveCamera } = _ref; //***************************************************************************************** // setting up the state //***************************************************************************************** // Permissions const [hasPermission, setHasPermission] = _react.default.useState(false); // camera states const devices = (0, _reactNativeVisionCamera.useCameraDevices)(); const direction = cameraDirection ?? 'back'; const device = devices[direction]; const camera = (0, _react.useRef)(null); const { height: screenHeight, width: screenWidth } = (0, _reactNative.useWindowDimensions)(); const [isActive, setIsActive] = (0, _react.useState)(true); const [feedbackText, setFeedbackText] = (0, _react.useState)(''); const [ocrElements, setOcrElements] = (0, _react.useState)([]); const [frameDimensions, setFrameDimensions] = (0, _react.useState)(); const landscapeMode = screenWidth > screenHeight; const [pixelRatio, setPixelRatio] = _react.default.useState(1); //***************************************************************************************** // Comp Logic //***************************************************************************************** // const xRatio = frame.width / WINDOW_WIDTH; // const yRatio = frame.height / WINDOW_HEIGHT; /* A cleanup function that is called when the component is unmounted. */ (0, _react.useEffect)(() => { return () => { setIsActive(false); }; }, []); // which format should we use const formats = (0, _react.useMemo)(() => device === null || device === void 0 ? void 0 : device.formats.sort(_visionCameraMrzScanner.sortFormatsByResolution), [device === null || device === void 0 ? void 0 : device.formats]); //figure our what happens if it is undefined? const [format, setFormat] = (0, _react.useState)(formats && formats.length > 0 ? formats[0] : undefined); /** * Prevents sending copious amounts of scans */ const handleScan = (0, _react.useCallback)((data, frame) => { const isRotated = !landscapeMode; setFrameDimensions(isRotated ? { width: frame.height, height: frame.width } : { width: frame.width, height: frame.height }); if (data && data.result && data.result.blocks && data.result.blocks.length === 0) { setFeedbackText(''); } /* Scanning the text from the image and then setting the state of the component. */ if (data && data.result && data.result.blocks && data.result.blocks.length > 0) { let updatedOCRElements = []; data.result.blocks.forEach(block => { if (block.frame.width / screenWidth < 0.8) { setFeedbackText('Hold Still'); } else { setFeedbackText('Scanning...'); } updatedOCRElements.push({ ...block.frame }); }); let lines = []; data.result.blocks.forEach(block => { lines.push(block.text); }); if (lines.length > 0 && isActive && onData) { setOcrElements(updatedOCRElements); onData(lines); } else { setOcrElements([]); } } }, [isActive, landscapeMode, onData, screenWidth]); /* Setting the format to the first format in the formats array. */ (0, _react.useEffect)(() => { setFormat(formats && formats.length > 0 ? formats[0] : undefined); // eslint-disable-next-line react-hooks/exhaustive-deps }, [device]); /* Using the useFrameProcessor hook to process the video frames. */ const frameProcessor = (0, _reactNativeVisionCamera.useFrameProcessor)(frame => { 'worklet'; if (!scanSuccess) { const ocrData = (0, _visionCameraMrzScanner.scanMRZ)(frame); (0, _reactNativeReanimated.runOnJS)(handleScan)(ocrData, frame); } }, [handleScan]); (0, _react.useEffect)(() => { (async () => { const status = await _reactNativeVisionCamera.Camera.requestCameraPermission(); setHasPermission(status === 'authorized'); })(); }, []); /* Using the useMemo hook to create a style object. */ const boundingStyle = (0, _react.useMemo)(() => ({ position: 'absolute', top: 0, left: 0, width: screenWidth, height: screenHeight }), [screenWidth, screenHeight]); const bounds = ocrElements[ocrElements.length - 1]; //***************************************************************************************** // stylesheet //***************************************************************************************** const styles = _reactNative.StyleSheet.create({ fixToText: { flexDirection: 'row', justifyContent: 'space-between' }, skipButtonContainer: { position: 'absolute', bottom: screenHeight * 0.05, width: screenWidth, alignItems: 'center', justifyContent: 'center', flexDirection: 'row' }, feedbackContainer: { position: 'absolute', top: screenHeight * 0.3, width: screenWidth, alignItems: 'center' }, feedbackText: { backgroundColor: 'white', color: 'black', fontSize: 18, paddingRight: 8, paddingLeft: 8, textAlign: 'center' }, boundingBox: { borderRadius: 5, borderWidth: 3, borderColor: 'yellow', position: 'absolute', left: bounds ? bounds.x * pixelRatio : 0, top: bounds ? bounds.y * pixelRatio : 0, height: bounds ? bounds.height : 35, width: bounds ? bounds.width : 35 } }); //***************************************************************************************** // Components //***************************************************************************************** return /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: style }, device && hasPermission ? /*#__PURE__*/_react.default.createElement(_reactNativeVisionCamera.Camera, { style: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.style) ?? _reactNative.StyleSheet.absoluteFill, device: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.device) ?? device, torch: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.torch, isActive: isActiveCamera ? isActiveCamera : cameraProps !== null && cameraProps !== void 0 && cameraProps.isActive ? cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.isActive : isActive, ref: camera, photo: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.photo, video: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.video, audio: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.audio, zoom: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.zoom, enableZoomGesture: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.enableZoomGesture, preset: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.preset, format: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.format) ?? format, fps: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.fps) ?? 10, hdr: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.hdr, lowLightBoost: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.lowLightBoost, colorSpace: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.colorSpace, videoStabilizationMode: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.videoStabilizationMode, enableDepthData: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.enableDepthData, enablePortraitEffectsMatteDelivery: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.enablePortraitEffectsMatteDelivery, enableHighQualityPhotos: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.enableHighQualityPhotos, onError: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.onError, onInitialized: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.onInitialized, onFrameProcessorPerformanceSuggestionAvailable: cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.onFrameProcessorPerformanceSuggestionAvailable, frameProcessor: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.frameProcessor) ?? frameProcessor, frameProcessorFps: (cameraProps === null || cameraProps === void 0 ? void 0 : cameraProps.frameProcessorFps) ?? 30, onLayout: event => { setPixelRatio(event.nativeEvent.layout.width / _reactNative.PixelRatio.getPixelSizeForLayoutSize(event.nativeEvent.layout.width)); } }) : undefined, enableBoundingBox && ocrElements.length > 0 ? /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: boundingStyle, testID: "faceDetectionBoxView" }, frameDimensions && (() => { const { adjustRect } = (0, _visionCameraMrzScanner.boundingBoxAdjustToView)(frameDimensions, { width: landscapeMode ? screenHeight : screenWidth, height: landscapeMode ? screenWidth : screenHeight }, landscapeMode, boundingBoxVerticalPadding, boundingBoxHorizontalPadding); return ocrElements ? ocrElements.map((i, index) => { const { left, ...others } = adjustRect(i); return /*#__PURE__*/_react.default.createElement(_reactNative.View, { key: index, style: [styles.boundingBox, { ...others, left: left }, boundingBoxStyle] }); }) : undefined; })()) : null, photoSkipButton ? /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.fixToText] }, photoSkipButtonEnabled ? photoSkipButton ? /*#__PURE__*/_react.default.createElement(_reactNative.TouchableOpacity, { onPress: photoSkipOnPress }, photoSkipButton) : /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: [styles.skipButtonContainer, photoSkipButtonStyle] }, /*#__PURE__*/_react.default.createElement(_reactNative.Button, { title: skipButtonText ? skipButtonText : 'Skip', onPress: photoSkipOnPress })) : undefined) : undefined, feedbackText ? /*#__PURE__*/_react.default.createElement(_reactNative.View, { style: styles.feedbackContainer }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, { style: styles.feedbackText }, feedbackText)) : null); }; var _default = MRZCamera; exports.default = _default; //# sourceMappingURL=MRZCamera.js.map