/* eslint-disable no-console */
import React, {useState, useReducer, useRef} from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Slider,
TouchableWithoutFeedback,
Dimensions,
} from 'react-native';
// eslint-disable-next-line import/no-unresolved
import { RNCamera } from 'react-native-camera';
const flashModeOrder = {
off: 'on',
on: 'auto',
auto: 'torch',
torch: 'off',
};
const wbOrder = {
auto: 'sunny',
sunny: 'cloudy',
cloudy: 'shadow',
shadow: 'fluorescent',
fluorescent: 'incandescent',
incandescent: 'auto',
};
const landmarkSize = 2;
const stateReducer = (state, action) => {
switch (action.type) {
case 'toggleFlash':
return { state.flash === flashModeOrder[ state.flash] }
break;
case 'toggleZoom':
return { state.flash === flashModeOrder[ state.flash] }
break;
default:
break;
}
}
const initialState = {
flash: 'off',
zoom: 0,
autoFocus: 'on',
depth: 0,
type: 'back',
whiteBalance: 'auto',
ratio: '16:9',
isRecording: false,
canDetectFaces: false,
canDetectText: false,
canDetectBarcode: false,
faces: [],
textBlocks: [],
barcodes: [],
recordOptions: {
mute: false,
maxDuration: 5,
quality: RNCamera.Constants.VideoQuality['288p'],
},
autoFocusPoint: {
normalized: { x: 0.5, y: 0.5 }, // normalized values required for autoFocusPointOfInterest
drawRectPosition: {
x: Dimensions.get('window').width * 0.5 - 32,
y: Dimensions.get('window').height * 0.5 - 32,
},
},
};
const CameraScreen = () => {
const [state, setState] = useState(initialState);
const [recordOptions, togglerecordOptions] = useReducer(reducer, initialState.recordOptions);
const [autoFocusPoint, touchToFocus] = useReducer(reducer, initialState.autoFocusPoint);
const cameraRef = useRef(null);
toggleFacing =() =>{
setState({
...state,
type: type === 'back' ? 'front' : 'back',
})
}
toggleFlash =() => {
setState({
...state,
flash: flashModeOrder[flash]
})
}
toggleWB =() => {
setState({
...state,
whiteBalance: wbOrder[whiteBalance]
})
}
toggleFocus =() =>{
setState({
...state,
autoFocus: autoFocus === 'on' ? 'off' : 'on'
})
}
touchToFocus =(event) => {
const { pageX, pageY } = event.nativeEvent;
const screenWidth = Dimensions.get('window').width;
const screenHeight = Dimensions.get('window').height;
const isPortrait = screenHeight > screenWidth;
let x = pageX / screenWidth;
let y = pageY / screenHeight;
// Coordinate transform for portrait. See autoFocusPointOfInterest in docs for more info
if (isPortrait) {
x = pageY / screenHeight;
y = -(pageX / screenWidth) + 1;
}
return {
autoFocusPoint: {
normalized: { x, y },
drawRectPosition: { x: pageX, y: pageY },
},
};
}
zoomOut =() =>{
setState({
...state,
zoom: state.zoom - 0.1 < 0 ? 0 : state.zoom - 0.1,
})
}
zoomIn =() => {
setState({
...state,
zoom: state.zoom + 0.1 > 1 ? 1 : state.zoom + 0.1,
});
}
setFocusDepth = (depth) => {
setState({
...state,
depth: depth
});
}
takePicture = async function() {
if (cameraRef) {
const data = await cameraRef.takePictureAsync();
console.warn('takePicture ', data);
}
};
takeVideo = async function() {
if (cameraRef) {
try {
const promise = cameraRef.recordAsync( state.recordOptions);
if (promise) {
setState({
...state,
isRecording: true
});
const data = await promise;
setState({
...state,
isRecording: false
});
console.warn('takeVideo', data);
}
} catch (e) {
console.error(e);
}
}
};
toggle = value => () => {
setState({
...state,
[value]: !prevState[value]
})
};
facesDetected = ({ faces }) => {
setState({
...state,
faces: faces
})
};
renderFace = ({ bounds, faceID, rollAngle, yawAngle }) => (
ID: {faceID}
rollAngle: {rollAngle.toFixed(0)}
yawAngle: {yawAngle.toFixed(0)}
);
renderLandmarksOfFace =(face) => {
const renderLandmark = position =>
position && (
);
return (
{renderLandmark(face.leftEyePosition)}
{renderLandmark(face.rightEyePosition)}
{renderLandmark(face.leftEarPosition)}
{renderLandmark(face.rightEarPosition)}
{renderLandmark(face.leftCheekPosition)}
{renderLandmark(face.rightCheekPosition)}
{renderLandmark(face.leftMouthPosition)}
{renderLandmark(face.mouthPosition)}
{renderLandmark(face.rightMouthPosition)}
{renderLandmark(face.noseBasePosition)}
{renderLandmark(face.bottomMouthPosition)}
);
}
renderFaces = () => (
{ state.faces.map(() => renderFace())}
);
renderLandmarks = () => (
{ state.faces.map(() => renderLandmarksOfFace())}
);
renderTextBlocks = () => (
{ state.textBlocks.map(() => renderTextBlock())}
);
renderTextBlock = ({ bounds, value }) => (
{value}
);
textRecognized = object => {
const { textBlocks } = object;
setState({
...state,
textBlocks: textBlocks
});
};
barcodeRecognized = ({ barcodes }) => {
setState({
...stat,
barcodes
})
};
renderBarcodes = () => (
{ state.barcodes.map( renderBarcode)}
);
renderBarcode = ({ bounds, data, type }) => (
{`${data} ${type}`}
);
renderCamera = () => {
const { canDetectFaces, canDetectText, canDetectBarcode } = state;
const drawFocusRingPosition = {
top: state.autoFocusPoint.drawRectPosition.y - 32,
left: state.autoFocusPoint.drawRectPosition.x - 32,
};
return (
{
cameraRef = ref;
}}
style={{
flex: 1,
justifyContent: 'space-between',
}}
type={ state.type}
flashMode={ state.flash}
autoFocus={ state.autoFocus}
autoFocusPointOfInterest={ state.autoFocusPoint.normalized}
zoom={ state.zoom}
whiteBalance={ state.whiteBalance}
ratio={ state.ratio}
focusDepth={ state.depth}
androidCameraPermissionOptions={{
title: 'Permission to use camera',
message: 'We need your permission to use your camera',
buttonPositive: 'Ok',
buttonNegative: 'Cancel',
}}
faceDetectionLandmarks={
RNCamera.Constants.FaceDetection.Landmarks
? RNCamera.Constants.FaceDetection.Landmarks.all
: undefined
}
onFacesDetected={canDetectFaces ? facesDetected() : null}
onTextRecognized={canDetectText ? textRecognized() : null}
onGoogleVisionBarcodesDetected={canDetectBarcode ? barcodeRecognized() : null}
>
touchToFocus()}>
toggleFacing()}>
FLIP
toggleFlash()}>
FLASH: { state.flash}
toggleWB()}>
WB: { state.whiteBalance}
toggle('canDetectFaces')} style={styles.flipButton}>
{!canDetectFaces ? 'Detect Faces' : 'Detecting Faces'}
toggle('canDetectText')} style={styles.flipButton}>
{!canDetectText ? 'Detect Text' : 'Detecting Text'}
toggle('canDetectBarcode')} style={styles.flipButton}>
{!canDetectBarcode ? 'Detect Barcode' : 'Detecting Barcode'}
setFocusDepth()}
step={0.1}
disabled={ state.autoFocus === 'on'}
/>
{} : () => takeVideo()}
>
{ state.isRecording ? (
☕
) : (
REC
)}
{ state.zoom !== 0 && (
Zoom: { state.zoom}
)}
zoomIn()}
>
+
zoomOut()}
>
-
toggleFocus()}
>
AF : { state.autoFocus}
takePicture()}
>
SNAP
{!!canDetectFaces && renderFaces()}
{!!canDetectFaces && renderLandmarks()}
{!!canDetectText && renderTextBlocks()}
{!!canDetectBarcode && renderBarcodes()}
);
}
return (
{() => renderCamera()}
);
}
export default CameraScreen;
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 10,
backgroundColor: '#000',
},
flipButton: {
flex: 0.3,
height: 40,
marginHorizontal: 2,
marginBottom: 10,
marginTop: 10,
borderRadius: 8,
borderColor: 'white',
borderWidth: 1,
padding: 5,
alignItems: 'center',
justifyContent: 'center',
},
autoFocusBox: {
position: 'absolute',
height: 64,
width: 64,
borderRadius: 12,
borderWidth: 2,
borderColor: 'white',
opacity: 0.4,
},
flipText: {
color: 'white',
fontSize: 15,
},
zoomText: {
position: 'absolute',
bottom: 70,
zIndex: 2,
left: 2,
},
picButton: {
backgroundColor: 'darkseagreen',
},
facesContainer: {
position: 'absolute',
bottom: 0,
right: 0,
left: 0,
top: 0,
},
face: {
padding: 10,
borderWidth: 2,
borderRadius: 2,
position: 'absolute',
borderColor: '#FFD700',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
},
landmark: {
width: landmarkSize,
height: landmarkSize,
position: 'absolute',
backgroundColor: 'red',
},
faceText: {
color: '#FFD700',
fontWeight: 'bold',
textAlign: 'center',
margin: 10,
backgroundColor: 'transparent',
},
text: {
padding: 10,
borderWidth: 2,
borderRadius: 2,
position: 'absolute',
borderColor: '#F00',
justifyContent: 'center',
},
textBlock: {
color: '#F00',
position: 'absolute',
textAlign: 'center',
backgroundColor: 'transparent',
},
});