title: React native save photo with the square of the face recognition
body: <p><img src="https://camo.githubusercontent.com/630a13d530d3b7385f4127d4b74ac0b2adef466d/68747470733a2f2f692e696d6775722e636f6d2f35717a6d6b6c562e6a7067" alt=""></p>
  
  <p>How can I make sure that I can save the picture with the square of the face recognition?</p>
  
  <p>I would like to make sure that when the user takes the picture, and in the photo are recognized faces, as seen in the image.
  The photo is saved with a detail, ie the square that is used for facial facial recognition, for example.</p>
  
  <p>Link: <a href="https://snack.expo.io/HJzPls-EV" rel="nofollow noreferrer">Expo</a></p>
  
  <p>Code:</p>
  
  <pre><code>import {
    Constants,
    Camera,
    FileSystem,
    Permissions,
    BarCodeScanner,
  } from 'expo';
  import React from 'react';
  import {
    Alert,
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
    Slider,
    Platform,
    ImageBackground,
  } from 'react-native';
  import GalleryScreen from './GalleryScreen';
  import isIPhoneX from 'react-native-is-iphonex';
  
  import {
    Ionicons,
    MaterialIcons,
    Foundation,
    MaterialCommunityIcons,
    Octicons,
  } from '@expo/vector-icons';
  
  const landmarkSize = 2;
  
  const flashModeOrder = {
    off: 'on',
    on: 'auto',
    auto: 'torch',
    torch: 'off',
  };
  
  const flashIcons = {
    off: 'flash-off',
    on: 'flash-on',
    auto: 'flash-auto',
    torch: 'highlight',
  };
  
  const wbOrder = {
    auto: 'sunny',
    sunny: 'cloudy',
    cloudy: 'shadow',
    shadow: 'fluorescent',
    fluorescent: 'incandescent',
    incandescent: 'auto',
  };
  
  const wbIcons = {
    auto: 'wb-auto',
    sunny: 'wb-sunny',
    cloudy: 'wb-cloudy',
    shadow: 'beach-access',
    fluorescent: 'wb-iridescent',
    incandescent: 'wb-incandescent',
  };
  
  export default class CameraScreen extends React.Component {
    state = {
      flash: 'off',
      zoom: 0,
      autoFocus: 'on',
      type: 'back',
      whiteBalance: 'auto',
      ratio: '16:9',
      ratios: [],
      barcodeScanning: false,
      faceDetecting: true,
      faces: [],
      newPhotos: false,
      permissionsGranted: false,
      pictureSize: undefined,
      pictureSizes: [],
      pictureSizeId: 0,
      showGallery: false,
      showMoreOptions: false,
    };
  
    async componentWillMount() {
      const { status } = await Permissions.askAsync(Permissions.CAMERA);
      this.setState({ permissionsGranted: status === 'granted' });
    }
  
    componentDidMount() {
      FileSystem.makeDirectoryAsync(
        FileSystem.documentDirectory + 'photos'
      ).catch(e =&gt; {
        console.log(e, 'Directory exists');
      });
    }
  
    getRatios = async () =&gt; {
      const ratios = await this.camera.getSupportedRatios();
      return ratios;
    };
  
    toggleView = () =&gt;
      this.setState({ showGallery: !this.state.showGallery, newPhotos: false });
  
    toggleMoreOptions = () =&gt;
      this.setState({ showMoreOptions: !this.state.showMoreOptions });
  
    toggleFacing = () =&gt;
      this.setState({ type: this.state.type === 'back' ? 'front' : 'back' });
  
    toggleFlash = () =&gt;
      this.setState({ flash: flashModeOrder[this.state.flash] });
  
    setRatio = ratio =&gt; this.setState({ ratio });
  
    toggleWB = () =&gt;
      this.setState({ whiteBalance: wbOrder[this.state.whiteBalance] });
  
    toggleFocus = () =&gt;
      this.setState({ autoFocus: this.state.autoFocus === 'on' ? 'off' : 'on' });
  
    zoomOut = () =&gt;
      this.setState({
        zoom: this.state.zoom - 0.1 &lt; 0 ? 0 : this.state.zoom - 0.1,
      });
  
    zoomIn = () =&gt;
      this.setState({
        zoom: this.state.zoom + 0.1 &gt; 1 ? 1 : this.state.zoom + 0.1,
      });
  
    setFocusDepth = depth =&gt; this.setState({ depth });
  
    toggleBarcodeScanning = () =&gt;
      this.setState({ barcodeScanning: !this.state.barcodeScanning });
  
    toggleFaceDetection = () =&gt;
      this.setState({ faceDetecting: !this.state.faceDetecting });
  
    takePicture = () =&gt; {
      if (this.camera) {
        this.camera.takePictureAsync({ onPictureSaved: this.onPictureSaved });
      }
    };
  
    handleMountError = ({ message }) =&gt; console.error(message);
  
    onPictureSaved = async photo =&gt; {
      await FileSystem.moveAsync({
        from: photo.uri,
        to: `${FileSystem.documentDirectory}photos/${Date.now()}.jpg`,
      });
      this.setState({ newPhotos: true });
    };
  
    onBarCodeScanned = code =&gt; {
      this.setState(
        { barcodeScanning: !this.state.barcodeScanning },
        Alert.alert(`Barcode found: ${code.data}`)
      );
    };
  
    onFacesDetected = ({ faces }) =&gt; this.setState({ faces });
    onFaceDetectionError = state =&gt; console.warn('Faces detection error:', state);
  
    collectPictureSizes = async () =&gt; {
      if (this.camera) {
        const pictureSizes = await this.camera.getAvailablePictureSizesAsync(
          this.state.ratio
        );
        let pictureSizeId = 0;
        if (Platform.OS === 'ios') {
          pictureSizeId = pictureSizes.indexOf('High');
        } else {
          // returned array is sorted in ascending order - default size is the largest one
          pictureSizeId = pictureSizes.length - 1;
        }
        this.setState({
          pictureSizes,
          pictureSizeId,
          pictureSize: pictureSizes[pictureSizeId],
        });
      }
    };
  
    previousPictureSize = () =&gt; this.changePictureSize(1);
    nextPictureSize = () =&gt; this.changePictureSize(-1);
  
    changePictureSize = direction =&gt; {
      let newId = this.state.pictureSizeId + direction;
      const length = this.state.pictureSizes.length;
      if (newId &gt;= length) {
        newId = 0;
      } else if (newId &lt; 0) {
        newId = length - 1;
      }
      this.setState({
        pictureSize: this.state.pictureSizes[newId],
        pictureSizeId: newId,
      });
    };
  
    renderGallery() {
      return &lt;GalleryScreen onPress={this.toggleView.bind(this)} /&gt;;
    }
  
    renderFace({ bounds, faceID, rollAngle, yawAngle }) {
      return (
        &lt;View
          key={faceID}
          transform={[
            { perspective: 600 },
            { rotateZ: `${rollAngle.toFixed(0)}deg` },
            { rotateY: `${yawAngle.toFixed(0)}deg` },
          ]}
          style={[
            styles.face,
            {
              ...bounds.size,
              left: bounds.origin.x,
              top: bounds.origin.y,
            },
          ]}&gt;
          &lt;Text style={styles.faceText}&gt;ID: {faceID}&lt;/Text&gt;
          &lt;Text style={styles.faceText}&gt;rollAngle: {rollAngle.toFixed(0)}&lt;/Text&gt;
          &lt;Text style={styles.faceText}&gt;yawAngle: {yawAngle.toFixed(0)}&lt;/Text&gt;
        &lt;/View&gt;
      );
    }
  
    renderLandmarksOfFace(face) {
      const renderLandmark = position =&gt;
        position &amp;&amp; (
          &lt;View
            style={[
              styles.landmark,
              {
                left: position.x - landmarkSize / 2,
                top: position.y - landmarkSize / 2,
              },
            ]}
          /&gt;
        );
      return (
        &lt;View key={`landmarks-${face.faceID}`}&gt;
          {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)}
        &lt;/View&gt;
      );
    }
  
    renderFaces = () =&gt; (
      &lt;View style={styles.facesContainer} pointerEvents="none"&gt;
        {this.state.faces.map(this.renderFace)}
      &lt;/View&gt;
    );
  
    renderLandmarks = () =&gt; (
      &lt;View style={styles.facesContainer} pointerEvents="none"&gt;
        {this.state.faces.map(this.renderLandmarksOfFace)}
      &lt;/View&gt;
    );
  
    renderNoPermissions = () =&gt; (
      &lt;View style={styles.noPermissions}&gt;
        &lt;Text style={{ color: 'white' }}&gt;
          Camera permissions not granted - cannot open camera preview.
        &lt;/Text&gt;
      &lt;/View&gt;
    );
  
    renderTopBar = () =&gt; (
      &lt;View style={styles.topBar}&gt;
        &lt;TouchableOpacity style={styles.toggleButton} onPress={this.toggleFacing}&gt;
          &lt;Ionicons name="ios-reverse-camera" size={32} color="white" /&gt;
        &lt;/TouchableOpacity&gt;
        &lt;TouchableOpacity style={styles.toggleButton} onPress={this.toggleFlash}&gt;
          &lt;MaterialIcons
            name={flashIcons[this.state.flash]}
            size={32}
            color="white"
          /&gt;
        &lt;/TouchableOpacity&gt;
        &lt;TouchableOpacity style={styles.toggleButton} onPress={this.toggleWB}&gt;
          &lt;MaterialIcons
            name={wbIcons[this.state.whiteBalance]}
            size={32}
            color="white"
          /&gt;
        &lt;/TouchableOpacity&gt;
        &lt;TouchableOpacity style={styles.toggleButton} onPress={this.toggleFocus}&gt;
          &lt;Text
            style={[
              styles.autoFocusLabel,
              { color: this.state.autoFocus === 'on' ? 'white' : '#6b6b6b' },
            ]}&gt;
            AF
          &lt;/Text&gt;
        &lt;/TouchableOpacity&gt;
      &lt;/View&gt;
    );
  
    renderBottomBar = () =&gt; (
      &lt;View style={styles.bottomBar}&gt;
        &lt;TouchableOpacity
          style={styles.bottomButton}
          onPress={this.toggleMoreOptions}&gt;
          &lt;Octicons name="kebab-horizontal" size={30} color="white" /&gt;
        &lt;/TouchableOpacity&gt;
        &lt;View style={{ flex: 0.4 }}&gt;
          &lt;TouchableOpacity
            onPress={this.takePicture}
            style={{ alignSelf: 'center' }}&gt;
            &lt;Ionicons name="ios-radio-button-on" size={70} color="white" /&gt;
          &lt;/TouchableOpacity&gt;
        &lt;/View&gt;
        &lt;TouchableOpacity style={styles.bottomButton} onPress={this.toggleView}&gt;
          &lt;View&gt;
            &lt;Foundation name="thumbnails" size={30} color="white" /&gt;
            {this.state.newPhotos &amp;&amp; &lt;View style={styles.newPhotosDot} /&gt;}
          &lt;/View&gt;
        &lt;/TouchableOpacity&gt;
      &lt;/View&gt;
    );
  
    renderMoreOptions = () =&gt; (
      &lt;View style={styles.options}&gt;
        &lt;View style={styles.detectors}&gt;
          &lt;TouchableOpacity onPress={this.toggleFaceDetection}&gt;
            &lt;MaterialIcons
              name="tag-faces"
              size={32}
              color={this.state.faceDetecting ? 'white' : '#858585'}
            /&gt;
          &lt;/TouchableOpacity&gt;
          &lt;TouchableOpacity onPress={this.toggleBarcodeScanning}&gt;
            &lt;MaterialCommunityIcons
              name="barcode-scan"
              size={32}
              color={this.state.barcodeScanning ? 'white' : '#858585'}
            /&gt;
          &lt;/TouchableOpacity&gt;
        &lt;/View&gt;
  
        &lt;View style={styles.pictureSizeContainer}&gt;
          &lt;Text style={styles.pictureQualityLabel}&gt;Picture quality&lt;/Text&gt;
          &lt;View style={styles.pictureSizeChooser}&gt;
            &lt;TouchableOpacity
              onPress={this.previousPictureSize}
              style={{ padding: 6 }}&gt;
              &lt;Ionicons name="md-arrow-dropleft" size={14} color="white" /&gt;
            &lt;/TouchableOpacity&gt;
            &lt;View style={styles.pictureSizeLabel}&gt;
              &lt;Text style={{ color: 'white' }}&gt;{this.state.pictureSize}&lt;/Text&gt;
            &lt;/View&gt;
            &lt;TouchableOpacity
              onPress={this.nextPictureSize}
              style={{ padding: 6 }}&gt;
              &lt;Ionicons name="md-arrow-dropright" size={14} color="white" /&gt;
            &lt;/TouchableOpacity&gt;
          &lt;/View&gt;
        &lt;/View&gt;
      &lt;/View&gt;
    );
  
    renderCamera = () =&gt; (
      &lt;View style={{ flex: 1 }}&gt;
        &lt;Camera
          ref={ref =&gt; {
            this.camera = ref;
          }}
          style={styles.camera}
          onCameraReady={this.collectPictureSizes}
          type={this.state.type}
          flashMode={this.state.flash}
          autoFocus={this.state.autoFocus}
          zoom={this.state.zoom}
          whiteBalance={this.state.whiteBalance}
          ratio={this.state.ratio}
          pictureSize={this.state.pictureSize}
          onMountError={this.handleMountError}
          onFacesDetected={
            this.state.faceDetecting ? this.onFacesDetected : undefined
          }
          onFaceDetectionError={this.onFaceDetectionError}
          barCodeScannerSettings={{
            barCodeTypes: [
              BarCodeScanner.Constants.BarCodeType.qr,
              BarCodeScanner.Constants.BarCodeType.pdf417,
            ],
          }}
          onBarCodeScanned={
            this.state.barcodeScanning ? this.onBarCodeScanned : undefined
          }&gt;
          {this.renderTopBar()}
          {this.renderBottomBar()}
        &lt;/Camera&gt;
        {this.state.faceDetecting &amp;&amp; this.renderFaces()}
        {this.state.faceDetecting &amp;&amp; this.renderLandmarks()}
        {this.state.showMoreOptions &amp;&amp; this.renderMoreOptions()}
      &lt;/View&gt;
    );
  
    render() {
      const cameraScreenContent = this.state.permissionsGranted
        ? this.renderCamera()
        : this.renderNoPermissions();
      const content = this.state.showGallery
        ? this.renderGallery()
        : cameraScreenContent;
      return &lt;View style={styles.container}&gt;{content}&lt;/View&gt;;
    }
  }
  
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#000',
    },
    camera: {
      flex: 1,
      justifyContent: 'space-between',
    },
    topBar: {
      flex: 0.2,
      backgroundColor: 'transparent',
      flexDirection: 'row',
      justifyContent: 'space-around',
      paddingTop: Constants.statusBarHeight / 2,
    },
    bottomBar: {
      paddingBottom: isIPhoneX ? 25 : 5,
      backgroundColor: 'transparent',
      alignSelf: 'flex-end',
      justifyContent: 'space-between',
      flex: 0.12,
      flexDirection: 'row',
    },
    noPermissions: {
      flex: 1,
      alignItems: 'center',
      justifyContent: 'center',
      padding: 10,
    },
    gallery: {
      flex: 1,
      flexDirection: 'row',
      flexWrap: 'wrap',
    },
    toggleButton: {
      flex: 0.25,
      height: 40,
      marginHorizontal: 2,
      marginBottom: 10,
      marginTop: 20,
      padding: 5,
      alignItems: 'center',
      justifyContent: 'center',
    },
    autoFocusLabel: {
      fontSize: 20,
      fontWeight: 'bold',
    },
    bottomButton: {
      flex: 0.3,
      height: 58,
      justifyContent: 'center',
      alignItems: 'center',
    },
    newPhotosDot: {
      position: 'absolute',
      top: 0,
      right: -5,
      width: 8,
      height: 8,
      borderRadius: 4,
      backgroundColor: '#4630EB',
    },
    options: {
      position: 'absolute',
      bottom: 80,
      left: 30,
      width: 200,
      height: 160,
      backgroundColor: '#000000BA',
      borderRadius: 4,
      padding: 10,
    },
    detectors: {
      flex: 0.5,
      justifyContent: 'space-around',
      alignItems: 'center',
      flexDirection: 'row',
    },
    pictureQualityLabel: {
      fontSize: 10,
      marginVertical: 3,
      color: 'white',
    },
    pictureSizeContainer: {
      flex: 0.5,
      alignItems: 'center',
      paddingTop: 10,
    },
    pictureSizeChooser: {
      alignItems: 'center',
      justifyContent: 'space-between',
      flexDirection: 'row',
    },
    pictureSizeLabel: {
      flex: 1,
      alignItems: 'center',
      justifyContent: 'center',
    },
    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',
    },
    row: {
      flexDirection: 'row',
    },
  });
  </code></pre>