Delay on the capture of an image with React Native Camera / Expo Camera, set 'processing message'?

Viewed 1083

I have a huge delay in my app from when a user takes a photo to when android processes the image.

The issue of delay in Expo with android camera has been answered here: Delay on the capture of an image - React Native Camera / Expo Camera.

I am trying to see if, as well as see skipProcessing on takePictureAsync, is there a way to set a callback for on processing? I would like to let the user know something is happening, or they may try to take another photo (the camera stays open until the image has been processed, which is not ideal).

Here is my code:

export default class CameraComponent extends Component{
  constructor(props) {
    super(props)
  }

  render() {
    <Camera
      ref={(ref) => {
        this.camera = ref;
      }}
      type={Camera.Constants.Type.back}
    >
      <TouchableOpacity
        onPress={this.takePicture}
      >
        <View>
          <FontAwesome
            name="camera"
          />
        </View>
      </TouchableOpacity>
    </Camera>;
  }

  takePicture = async () => {
    const photo = await this.camera.takePictureAsync({
      skipProcessing: true,
    });

    this.props.navigation.navigate("CameraConfirm", {
      img_url: photo.img_url,
      img_base64: photo.img_base64,
    });
  }
}

I can't see anything in the docs, is there maybe a way around in React Native? I tried setting state, but that still happens after takePictureAsync so has no effect.

1 Answers

I found one workaround which uses camera2API and onPictureSaved. The docs say there could be issues with camera2API, although I did not see anything weird going on (as yet).

The code now looks like this:

export default class CameraComponent extends Component{
  constructor(props) {
    super(props)

    this.state = {
      is_photo_taken: false,
    };
  }

  render() {
    <Camera
      ref={(ref) => {
        this.camera = ref;
      }}
      type={Camera.Constants.Type.back}
      // add styling to show/hide camera:
      style={{
        display: this.state.is_photo_taken ? "none" : null,
      }}
      useCamera2Api={true} // add this line
    >
      <TouchableOpacity
        onPress={this.takePicture}
      >
        <View>
          <FontAwesome
            name="camera"
          />
        </View>
      </TouchableOpacity>
    </Camera>;

    // add loading element with conditional show/hide:
    <Text
      style={{
        display: !this.state.is_photo_taken ? "none" : null,
      }}
    >
      Loading image...
    </Text>
  }

  takePicture = async () => {
    const photo = await this.camera.takePictureAsync({
      onPictureSaved: this.setState({ is_photo_taken: true }), // add this line
      // remove skipProcessing
    });

    this.props.navigation.navigate("CameraConfirm", {
      img_url: photo.img_url,
      img_base64: photo.img_base64,
    });
  }
}

Also, since onPictureSaved is now being used, it means that skipProcesssing can now be omitted, if not needed.

I used show/hide instead of ternaries or && around the entire block to avoid losing the camera element from the page. If the camera element were to be lost as soon as a photo was taken, then it could not continue and process the image.

I hope this helps someone.

Related