2

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.

Leon Segal
  • 679
  • 7
  • 28

2 Answers2

1

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.

Leon Segal
  • 679
  • 7
  • 28
  • This solution helped me to solve my problem. In my case after clicking the capture / photo button i am showing a loader in place of the button until the image is processed and displayed – Sourav Dey Sep 14 '21 at 21:11
0

we're working on this and as some of you noticed the issue is not that obvious to solve. skipProcessing would indeed make the process significantly faster but it has problems with the image orientation. We're trying to find a way to get both.

camera.takePictureAsync({ skipProcessing: true });