UNPKG

react-vision-camera

Version:

Camera component for React. We can use this component for computer vision tasks like barcode scanning, text recognition, etc.

200 lines (199 loc) 7.9 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const react_1 = __importDefault(require("react")); const VisionCamera = (props) => { const devices = react_1.default.useRef(null); const localStream = react_1.default.useRef(null); const camera = react_1.default.useRef(null); const mounted = react_1.default.useRef(false); react_1.default.useEffect(() => { const init = () => __awaiter(void 0, void 0, void 0, function* () { if (!devices.current) { yield loadDevices(); // load the camera devices list when the component is mounted } if (props.isActive === true) { playWithDesired(); } mounted.current = true; }); init(); }, []); react_1.default.useEffect(() => { if (mounted.current === true) { if (props.isActive === true) { playWithDesired(); } else { stop(); } } }, [props.isActive]); react_1.default.useEffect(() => { console.log("pause"); console.log(props.isPause); if (mounted.current === true) { if (camera.current && props.isActive === true) { if (props.isPause === true) { camera.current.pause(); } else { camera.current.play(); } } } }, [props.isPause]); react_1.default.useEffect(() => { if (props.isActive === true && localStream.current && mounted.current === true) { playWithDesired(); } }, [props.desiredCamera, props.desiredResolution, props.facingMode]); const playWithDesired = () => __awaiter(void 0, void 0, void 0, function* () { if (!devices.current) { yield loadDevices(); // load the camera devices list if it hasn't been loaded } let desiredDevice = getDesiredDevice(devices.current); if (desiredDevice) { let options = {}; options.deviceId = desiredDevice; if (props.desiredResolution) { options.desiredResolution = props.desiredResolution; } if (props.facingMode) { options.facingMode = props.facingMode; } play(options); } else { throw new Error("No camera detected"); } }); const getDesiredDevice = (devices) => { var count = 0; var desiredIndex = 0; for (var i = 0; i < devices.length; i++) { var device = devices[i]; var label = device.label || `Camera ${count++}`; if (props.desiredCamera) { if (label.toLowerCase().indexOf(props.desiredCamera.toLowerCase()) != -1) { desiredIndex = i; break; } } } if (devices.length > 0) { return devices[desiredIndex].deviceId; // return the device id } else { return null; } }; const play = (options) => { stop(); // close before play var constraints = {}; if (options.deviceId) { constraints = { video: { deviceId: options.deviceId }, audio: false }; } else { constraints = { video: { width: 1280, height: 720 }, audio: false }; } if (options.facingMode) { delete constraints["video"]["deviceId"]; constraints["video"]["facingMode"] = { exact: options.facingMode }; } if (options.desiredResolution) { constraints["video"]["width"] = options.desiredResolution.width; constraints["video"]["height"] = options.desiredResolution.height; } navigator.mediaDevices.getUserMedia(constraints).then(function (stream) { localStream.current = stream; // Attach local stream to video element camera.current.srcObject = stream; }).catch(function (err) { if (options.facingMode) { // facing mode not supported on desktop Chrome delete options["facingMode"]; play(options); } else { console.error('getUserMediaError', err, err.stack); } }); }; const stop = () => { try { if (localStream.current) { const stream = localStream.current; const tracks = stream.getTracks(); for (let index = 0; index < tracks.length; index++) { const track = tracks[index]; track.stop(); } if (props.onClosed) { props.onClosed(); } } } catch (e) { console.log(e); } }; const loadDevices = () => __awaiter(void 0, void 0, void 0, function* () { const constraints = { video: true, audio: false }; const stream = yield navigator.mediaDevices.getUserMedia(constraints); // ask for permission const mediaDevices = yield navigator.mediaDevices.enumerateDevices(); let cameraDevices = []; for (let i = 0; i < mediaDevices.length; i++) { let device = mediaDevices[i]; if (device.kind == 'videoinput') { // filter out audio devices cameraDevices.push(device); } } devices.current = cameraDevices; const tracks = stream.getTracks(); for (let i = 0; i < tracks.length; i++) { const track = tracks[i]; track.stop(); // stop the opened camera } if (props.onDeviceListLoaded) { props.onDeviceListLoaded(cameraDevices); } }); const onCameraOpened = () => { console.log("onCameraOpened"); if (props.onOpened) { props.onOpened(camera.current, getCurrentCameraLabel()); } }; const getCurrentCameraLabel = () => { try { if (localStream.current) { const stream = localStream.current; return stream.getTracks()[0].label; } } catch (error) { return ""; } }; return (react_1.default.createElement("div", { style: { position: "relative", width: "100%", height: "100%", left: 0, top: 0 } }, react_1.default.createElement("video", { style: { position: "absolute", objectFit: "cover", width: "100%", height: "100%", left: 0, top: 0 }, ref: camera, muted: true, autoPlay: true, playsInline: true, onLoadedData: onCameraOpened }), props.children)); }; exports.default = VisionCamera;