¿Qué es React Webcam?
React Webcam es una biblioteca de npm que facilita el acceso y la manipulación de la cámara directamente desde tu navegador utilizando Hooks personalizados y componentes de React. Esto te permite crear aplicaciones interactivas que aprovechan la cámara de manera sencilla y eficiente.
Crear un Proyecto de React para Usar React Webcam
Sigue los pasos a continuación para configurar un proyecto de React donde puedas integrar React Webcam.
Usando Vite
Para iniciar un proyecto con Vite, ejecuta el siguiente comando:
npm create vite react-webcam-tutorial -- --template react
Usando Next.js
Si prefieres trabajar con Next.js, puedes crear un proyecto con soporte para TypeScript, TailwindCSS y ESLint utilizando:
npx create-next-app@latest react-webcam-tutorial --typescript --tailwind --eslint
Configuracion de React Webcam
Configuracion de React WebCam:
import Webcam from "react-webcam";
const WebcamComponent = () => <Webcam />;
Hacer Screenshot
"use client";
import { useState } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
facingMode: "user",
};
const WebcamCapture = () => {
const [imageSrc, setImageSrc] = useState(null);
return (
<div className="flex h-screen items-center justify-center bg-black w-full">
<div>
<Webcam
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={videoConstraints}
>
{({ getScreenshot }) => (
<button
className="text-white bg-blue-500 p-2 rounded-md"
onClick={() => {
const imageSrc = getScreenshot();
setImageSrc(imageSrc);
}}
>
Capture photo
</button>
)}
</Webcam>
</div>
{imageSrc && <img src={imageSrc} />}
</div>
);
};
export default WebcamCapture;
Hacer Screenshort usando Ref
"use client";
import { useCallback, useRef, useState } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
facingMode: "user",
};
const WebcamCapture = () => {
const webcamRef = useRef<any>(null);
const [imageSrc, setImageSrc] = useState(null);
const capture = useCallback(() => {
const imageSrc = webcamRef.current.getScreenshot();
setImageSrc(imageSrc);
}, [webcamRef, setImageSrc]);
return (
<div className="flex h-screen items-center justify-center bg-black w-full">
<div>
<Webcam
ref={webcamRef}
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={videoConstraints}
/>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full">
<div onClick={capture}>Capture photo</div>
</button>
</div>
{imageSrc && <img src={imageSrc} alt="captured" />}
</div>
);
};
export default WebcamCapture;
Hacer Screenshort usando Ref (Opcion 2)
"use client";
import { useRef, useState } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
facingMode: "user",
};
const WebcamCapture = () => {
const webcamRef = useRef<any>(null);
const [imageSrc, setImageSrc] = useState(null);
return (
<div className="flex h-screen items-center justify-center bg-black w-full">
<div>
<Webcam
ref={webcamRef}
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={videoConstraints}
/>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full">
<div
onClick={() => {
const imageSrc = webcamRef.current.getScreenshot();
setImageSrc(imageSrc);
}}
>
Capture photo
</div>
</button>
</div>
{imageSrc && <img src={imageSrc} alt="captured" />}
</div>
);
};
export default WebcamCapture;
Camara Frontal y Trasera
"use client";
import { useRef, useState } from "react";
import Webcam, { WebcamProps } from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
// facingMode: "environment",
};
const WebcamCapture = () => {
const webcamRef = useRef<any>(null);
const [imageSrc, setImageSrc] = useState(null);
const [facingMode, setFacingMode] = useState<"user" | "environment">(
"environment"
);
return (
<div className="flex flex-col h-screen items-center justify-center bg-black w-full p-20 md:p-0">
<div>
<Webcam
ref={webcamRef}
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={{
...videoConstraints,
facingMode,
}}
/>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex">
<div
onClick={() => {
const imageSrc = webcamRef.current.getScreenshot();
setImageSrc(imageSrc);
}}
>
Capture photo
</div>
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded-full"
onClick={() => {
setFacingMode(facingMode === "user" ? "environment" : "user");
}}
>
Change Camera
</button>
</div>
{imageSrc && <img src={imageSrc} alt="captured" />}
</div>
);
};
export default WebcamCapture;
Para probarlo vamos a usar ngrok o el Fordward Port de VSCode https://stackoverflow.com/questions/72407599/how-to-flip-webcam-using-react-js
Grabar Video con MediaRecorder
"use client";
import { useCallback, useRef, useState } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
};
const WebcamCapture = () => {
const webcamRef = useRef<any>(null);
const [imageSrc, setImageSrc] = useState(null);
const [facingMode, setFacingMode] = useState<"user" | "environment">(
"environment"
);
const [capturing, setCapturing] = useState(false);
const [recordedChunks, setRecordedChunks] = useState([]);
const mediaRecorderRef = useRef<any>(null);
const handleStartCaptureClick = useCallback(() => {
setCapturing(true);
mediaRecorderRef.current = new MediaRecorder(webcamRef.current.stream, {
mimeType: "video/webm",
});
mediaRecorderRef.current.addEventListener(
"dataavailable",
handleDataAvailable
);
mediaRecorderRef.current.start();
}, [webcamRef, setCapturing, mediaRecorderRef]);
const handleDataAvailable = useCallback(
({ data }: any) => {
if (data.size > 0) {
setRecordedChunks((prev) => prev.concat(data));
}
},
[setRecordedChunks]
);
const handleStopCaptureClick = useCallback(() => {
mediaRecorderRef.current.stop();
setCapturing(false);
}, [mediaRecorderRef, webcamRef, setCapturing]);
const handleDownload = useCallback(() => {
if (recordedChunks.length) {
const blob = new Blob(recordedChunks, {
type: "video/webm",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "react-webcam-stream-capture.webm";
a.click();
window.URL.revokeObjectURL(url);
setRecordedChunks([]);
}
}, [recordedChunks]);
return (
<div className="flex flex-col h-screen items-center justify-center bg-black w-full p-20 md:p-0">
<div>
<Webcam
ref={webcamRef}
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={{
...videoConstraints,
facingMode,
}}
/>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex">
<div
onClick={() => {
const imageSrc = webcamRef.current.getScreenshot();
setImageSrc(imageSrc);
}}
>
Capture photo
</div>
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded-full"
onClick={() => {
setFacingMode(facingMode === "user" ? "environment" : "user");
}}
>
Change Camera
</button>
{capturing ? (
<button
onClick={handleStopCaptureClick}
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-full flex"
>
Stop Capture
</button>
) : (
<button
onClick={handleStartCaptureClick}
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-full flex"
>
Start Capture
</button>
)}
</div>
{imageSrc && <img src={imageSrc} alt="captured" />}
<div className="flex">
{recordedChunks.length > 0 && (
<video
controls
style={{
marginTop: 20,
width: 720,
height: 360,
}}
>
<source
src={URL.createObjectURL(
new Blob(recordedChunks, { type: "video/webm" })
)}
type="video/webm"
/>
</video>
)}
{recordedChunks.length > 0 && (
<div className="">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex"
onClick={handleDownload}
>
Download
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex"
onClick={() => {
setRecordedChunks([]);
}}
>
Clear
</button>
</div>
)}
</div>
</div>
);
};
export default WebcamCapture;
Listar todos los dispositivos Moviles
Para listar todos los dispositvos
"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import Webcam from "react-webcam";
const videoConstraints = {
width: 1280,
height: 720,
};
const WebcamCapture = () => {
const webcamRef = useRef<any>(null);
const [imageSrc, setImageSrc] = useState(null);
const [facingMode, setFacingMode] = useState<"user" | "environment">(
"environment"
);
const [capturing, setCapturing] = useState(false);
const [recordedChunks, setRecordedChunks] = useState([]);
const mediaRecorderRef = useRef<any>(null);
const [deviceId, setDeviceId] = useState({});
const [devices, setDevices] = useState([]);
const handleDevices = useCallback(
(mediaDevices) =>
setDevices(mediaDevices.filter(({ kind }) => kind === "videoinput")),
[setDevices]
);
useEffect(() => {
navigator.mediaDevices.enumerateDevices().then(handleDevices);
}, [handleDevices]);
const handleStartCaptureClick = useCallback(() => {
setCapturing(true);
mediaRecorderRef.current = new MediaRecorder(webcamRef.current.stream, {
mimeType: "video/webm",
});
mediaRecorderRef.current.addEventListener(
"dataavailable",
handleDataAvailable
);
mediaRecorderRef.current.start();
}, [webcamRef, setCapturing, mediaRecorderRef]);
const handleDataAvailable = useCallback(
({ data }: any) => {
if (data.size > 0) {
setRecordedChunks((prev) => prev.concat(data));
}
},
[setRecordedChunks]
);
const handleStopCaptureClick = useCallback(() => {
mediaRecorderRef.current.stop();
setCapturing(false);
}, [mediaRecorderRef, webcamRef, setCapturing]);
const handleDownload = useCallback(() => {
if (recordedChunks.length) {
const blob = new Blob(recordedChunks, {
type: "video/webm",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = url;
a.download = "react-webcam-stream-capture.webm";
a.click();
window.URL.revokeObjectURL(url);
setRecordedChunks([]);
}
}, [recordedChunks]);
return (
<div className="flex flex-col h-screen items-center justify-center bg-black w-full p-20 md:p-0">
<div>
<Webcam
ref={webcamRef}
audio={false}
height={360}
screenshotFormat="image/jpeg"
width={720}
videoConstraints={{
...videoConstraints,
facingMode,
}}
/>
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex">
<div
onClick={() => {
const imageSrc = webcamRef.current.getScreenshot();
setImageSrc(imageSrc);
}}
>
Capture photo
</div>
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-2 rounded-full"
onClick={() => {
setFacingMode(facingMode === "user" ? "environment" : "user");
}}
>
Change Camera
</button>
{capturing ? (
<button
onClick={handleStopCaptureClick}
className="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded-full flex"
>
Stop Capture
</button>
) : (
<div>
<button
onClick={handleStartCaptureClick}
className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded-full flex"
>
Start Capture
</button>
{imageSrc && (
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex"
onClick={() => {
setImageSrc(null);
}}
>
Clear
</button>
)}
</div>
)}
</div>
{imageSrc && <img src={imageSrc} alt="captured" />}
<div className="flex">
{recordedChunks.length > 0 && (
<video
controls
style={{
marginTop: 20,
width: 720,
height: 360,
}}
>
<source
src={URL.createObjectURL(
new Blob(recordedChunks, { type: "video/webm" })
)}
type="video/webm"
/>
</video>
)}
{recordedChunks.length > 0 && (
<div className="">
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex"
onClick={handleDownload}
>
Download
</button>
<button
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full flex"
onClick={() => {
setRecordedChunks([]);
}}
>
Clear
</button>
</div>
)}
</div>
<div className="text-white">
{/* {devices.map((device, key) => (
<div>{device.label || `Device ${key + 1}`}</div>
))} */}
<select
value={deviceId}
onChange={(e) => setDeviceId(e.target.value)}
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded-full"
>
{devices.map((device, key) => (
<option key={key} value={device.deviceId}>
{device.label || `Device ${key + 1}`}
</option>
))}
</select>
</div>
</div>
);
};
export default WebcamCapture;