141 lines
3.3 KiB
TypeScript
141 lines
3.3 KiB
TypeScript
import Quagga, {
|
|
QuaggaJSCodeReader,
|
|
QuaggaJSResultObject,
|
|
} from "@ericblade/quagga2";
|
|
import { useState, useCallback, useEffect } from "react";
|
|
import { getMedianOfCodeErrors } from "./getMedianOfCodeErrors";
|
|
import { drawQuaggaProcessing } from "./drawQuaggaProcessing";
|
|
|
|
const constraints = {
|
|
width: 640,
|
|
height: 480,
|
|
};
|
|
|
|
const locator = {
|
|
patchSize: "medium",
|
|
halfSample: true,
|
|
willReadFrequently: true,
|
|
};
|
|
|
|
const readers: QuaggaJSCodeReader[] = ["ean_reader"];
|
|
|
|
export const useScanner = ({
|
|
onDetected,
|
|
}: {
|
|
onDetected?: (result: string) => void;
|
|
}): {
|
|
setScannerRef: (ref: HTMLDivElement | null) => void;
|
|
scannerError: string | undefined;
|
|
} => {
|
|
const [scannerError, setScannerError] = useState<string | undefined>();
|
|
|
|
const [scannerRef, setScannerRef] = useState<HTMLDivElement | null>(null);
|
|
|
|
const errorCheck = useCallback(
|
|
(result: QuaggaJSResultObject) => {
|
|
if (!onDetected) {
|
|
return;
|
|
}
|
|
const err = getMedianOfCodeErrors(result);
|
|
|
|
if (!err) {
|
|
return;
|
|
}
|
|
|
|
if (err < 0.1 && result.codeResult.code) {
|
|
onDetected(result.codeResult.code);
|
|
}
|
|
},
|
|
[onDetected]
|
|
);
|
|
|
|
const getCameraId = useCallback(async () => {
|
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
video: { facingMode: "environment" },
|
|
});
|
|
|
|
if (
|
|
stream &&
|
|
stream.getVideoTracks().length &&
|
|
stream.getVideoTracks()[0].getSettings().deviceId
|
|
) {
|
|
return stream.getVideoTracks()[0].getSettings().deviceId;
|
|
}
|
|
|
|
const devices = await navigator.mediaDevices
|
|
.enumerateDevices()
|
|
.then((ds) => ds.filter((d) => d.kind === "videoinput"));
|
|
|
|
const back = devices.filter((d) =>
|
|
d.label.toLowerCase().includes("back")
|
|
)[0];
|
|
|
|
return !back ? devices[0].deviceId : back.deviceId;
|
|
}, []);
|
|
|
|
const initQuagga = useCallback(async () => {
|
|
try {
|
|
const cameraId = await getCameraId();
|
|
|
|
if (!scannerRef || !cameraId) {
|
|
console.log("fehlt", scannerRef, cameraId);
|
|
return;
|
|
}
|
|
await Quagga.init(
|
|
{
|
|
inputStream: {
|
|
type: "LiveStream",
|
|
constraints: {
|
|
...constraints,
|
|
...(cameraId && { deviceId: cameraId }),
|
|
},
|
|
target: scannerRef,
|
|
willReadFrequently: true,
|
|
},
|
|
locator,
|
|
decoder: { readers },
|
|
locate: true,
|
|
},
|
|
async (err) => {
|
|
Quagga.onProcessed(drawQuaggaProcessing);
|
|
|
|
if (err) {
|
|
return console.error("Error starting Quagga:", err);
|
|
}
|
|
if (scannerRef) {
|
|
Quagga.start();
|
|
}
|
|
}
|
|
);
|
|
Quagga.onDetected(errorCheck);
|
|
} catch (e: unknown) {
|
|
setScannerError(JSON.stringify(e));
|
|
}
|
|
}, [errorCheck, getCameraId, scannerRef]);
|
|
|
|
const stopQuagga = useCallback(async () => {
|
|
await Quagga.CameraAccess.release();
|
|
await Quagga.stop();
|
|
Quagga.offDetected(errorCheck);
|
|
Quagga.offProcessed(drawQuaggaProcessing);
|
|
}, [errorCheck]);
|
|
|
|
useEffect(() => {
|
|
const init = () => {
|
|
initQuagga();
|
|
};
|
|
const disable = () => {
|
|
stopQuagga();
|
|
};
|
|
|
|
if (scannerRef) {
|
|
init();
|
|
}
|
|
return disable();
|
|
}, [stopQuagga, initQuagga, scannerRef]);
|
|
|
|
return {
|
|
setScannerRef,
|
|
scannerError,
|
|
};
|
|
};
|