Skip to content

Instantly share code, notes, and snippets.

@S3ak
Last active January 27, 2023 16:44
Show Gist options
  • Save S3ak/4b493b998d7586ea0b4ce0c03a062267 to your computer and use it in GitHub Desktop.
Save S3ak/4b493b998d7586ea0b4ce0c03a062267 to your computer and use it in GitHub Desktop.
Camera module
/* eslint-disable @next/next/no-img-element */
import { Button, Container, Paper, Title, Text, Card } from "@mantine/core";
import { useRef } from "react";
import { setTimeout } from "timers";
/**
* Captures the image using the browsers camera api
* @component */
export default function Capture() {
const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);
const photoRef = useRef<HTMLImageElement>(null);
// TODO: get this from device
let width = 320; // We will scale the photo width to this
let height = 320; // This will be computed based on the input stream
// const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
const constraints = {
audio: false,
video: true,
};
function clearphoto() {
if (!canvasRef.current?.getContext("2d") || !photoRef.current) {
return;
}
const canvas = canvasRef.current;
const context = canvas.getContext("2d");
// FIXME: Do this check earlier
if (!context || typeof canvas === null) {
return;
}
context.fillStyle = "#AAA";
context.fillRect(0, 0, canvas.width, canvas.height);
// TODO: Use jpg format, DRY
const data = canvas.toDataURL("image/png");
// TODO: Use setState
photoRef.current.setAttribute("src", data);
}
function takepicture() {
const canvas = canvasRef.current;
if (
!canvas?.getContext("2d") ||
canvas == null ||
canvas?.getContext("2d") == null ||
!photoRef.current ||
!videoRef.current
) {
return;
}
const context = canvas.getContext("2d");
console.log("Take photo", context);
if (width && height) {
canvas.width = width;
canvas.height = height;
// FIXME: Type checking hell
if (context) context.drawImage(videoRef.current, 0, 0, width, height);
// TODO: Use jpg format, DRY
const data = canvas.toDataURL("image/png");
console.log("data >>>>", data);
// TODO: Create SetImageSrc Func
photoRef.current.setAttribute("src", data);
} else {
clearphoto();
}
}
function handleSuccess(stream: MediaStream) {
const videoTracks = stream.getVideoTracks();
if (!videoRef.current) {
return;
}
console.log("videoRef >>>", videoRef.current);
videoRef.current.srcObject = stream;
videoRef.current.play();
setTimeout(() => {
videoTracks[0].stop();
// TODO: Decide on a timeout, maybe 90 seconds
}, 10 * 1000);
// TODO: Turn off camera when component unmounts
}
function handleError(error: any) {
if (error.name === "OverconstrainedError") {
} else if (error.name === "NotAllowedError") {
console.log(
"Permissions have not been granted to use your camera and " +
"microphone, you need to allow the page access to your devices in " +
"order for the demo to work."
);
}
console.log(`getUserMedia error: ${error.name}`, error);
}
const requestCameriaPermission = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleSuccess(stream);
console.log("stream >>>>", stream);
} catch (err) {
handleError(err);
}
};
return (
<Container>
<Paper>
<Title order={2}>Capture</Title>
<Text>Capture</Text>
<Button onClick={requestCameriaPermission}>Capture</Button>
<Card>
<canvas ref={canvasRef} style={{ display: "none" }} />
<video autoPlay playsInline ref={videoRef} />
<img alt="My photo" ref={photoRef} />
</Card>
<Button onClick={() => takepicture()}>Take Photo</Button>
</Paper>
</Container>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment