Search code examples
javascriptreactjscameraprogressive-web-appswebcam

using device camera for capturing image in reactjs


can I access the device camera and take a photo in ReactJs? The goal is to create a component that allows the camera to take pictures with the click of a button. According to my studies, I should use mediaDevices, but I am looking for a sample code in ReactJs. Please provide me with a sample code, or if you have experience implementing this, please guide me.


Solution

  • I have prepared a sample code that can be used as a component. This code snippet is applicable to devices that also have two cameras. If you want to take a video instead of a photo, you can also enable the audio feature in the outputs.

    import React from "react";
    
    class App extends React.Component {
      constructor() {
        super();
    
        this.cameraNumber = 0;
    
        this.state = {
          imageDataURL: null,
        };
      }
    
      initializeMedia = async () => {
        this.setState({ imageDataURL: null });
    
        if (!("mediaDevices" in navigator)) {
          navigator.mediaDevices = {};
        }
    
        if (!("getUserMedia" in navigator.mediaDevices)) {
          navigator.mediaDevices.getUserMedia = function (constraints) {
            var getUserMedia =
              navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
    
            if (!getUserMedia) {
              return Promise.reject(new Error("getUserMedia Not Implemented"));
            }
    
            return new Promise((resolve, reject) => {
              getUserMedia.call(navigator, constraints, resolve, reject);
            });
          };
        }
    
        //Get the details of video inputs of the device
        const videoInputs = await this.getListOfVideoInputs();
    
        //The device has a camera
        if (videoInputs.length) {
          navigator.mediaDevices
            .getUserMedia({
              video: {
                deviceId: {
                  exact: videoInputs[this.cameraNumber].deviceId,
                },
              },
            })
            .then((stream) => {
              this.player.srcObject = stream;
            })
            .catch((error) => {
              console.error(error);
            });
        } else {
          alert("The device does not have a camera");
        }
      };
    
      capturePicture = () => {
        var canvas = document.createElement("canvas");
        canvas.width = this.player.videoWidth;
        canvas.height = this.player.videoHeight;
        var contex = canvas.getContext("2d");
        contex.drawImage(this.player, 0, 0, canvas.width, canvas.height);
        this.player.srcObject.getVideoTracks().forEach((track) => {
          track.stop();
        });
    
        console.log(canvas.toDataURL());
        this.setState({ imageDataURL: canvas.toDataURL() });
      };
    
      switchCamera = async () => {
        const listOfVideoInputs = await this.getListOfVideoInputs();
    
        // The device has more than one camera
        if (listOfVideoInputs.length > 1) {
          if (this.player.srcObject) {
            this.player.srcObject.getVideoTracks().forEach((track) => {
              track.stop();
            });
          }
    
          // switch to second camera
          if (this.cameraNumber === 0) {
            this.cameraNumber = 1;
          }
          // switch to first camera
          else if (this.cameraNumber === 1) {
            this.cameraNumber = 0;
          }
    
          // Restart based on camera input
          this.initializeMedia();
        } else if (listOfVideoInputs.length === 1) {
          alert("The device has only one camera");
        } else {
          alert("The device does not have a camera");
        }
      };
    
      getListOfVideoInputs = async () => {
        // Get the details of audio and video output of the device
        const enumerateDevices = await navigator.mediaDevices.enumerateDevices();
    
        //Filter video outputs (for devices with multiple cameras)
        return enumerateDevices.filter((device) => device.kind === "videoinput");
      };
    
      render() {
        const playerORImage = Boolean(this.state.imageDataURL) ? (
          <img src={this.state.imageDataURL} alt="cameraPic" />
        ) : (
          <video
            ref={(refrence) => {
              this.player = refrence;
            }}
            autoPlay
          ></video>
        );
    
        return (
          <div className="App">
            {playerORImage}
            <button onClick={this.initializeMedia}>Take Photo</button>
            <button onClick={this.capturePicture}>Capture</button>
            <button onClick={this.switchCamera}>Switch</button>
          </div>
        );
      }
    }
    
    export default App;