Created
February 28, 2020 01:58
-
-
Save sneznaovca/9162cba070346fe6ab838556136872f0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useCallback, useLayoutEffect} from 'react'; | |
import Quagga from '@ericblade/quagga2'; | |
import QrCodeReader from '@ericblade/quagga2-reader-qr'; | |
Quagga.registerReader('qrcode', QrCodeReader); | |
function getMedian(arr) { | |
arr.sort((a, b) => a - b); | |
const half = Math.floor(arr.length / 2); | |
if (arr.length % 2 === 1) { | |
return arr[half]; | |
} | |
return (arr[half - 1] + arr[half]) / 2; | |
} | |
function getMedianOfCodeErrors(decodedCodes) { | |
const errors = decodedCodes.filter(x => x.error !== undefined).map(x => x.error); | |
const medianOfErrors = getMedian(errors); | |
return medianOfErrors; | |
} | |
const defaultConstraints = { | |
width: 640, | |
height: 480, | |
}; | |
const defaultLocatorSettings = { | |
patchSize: 'medium', | |
halfSample: true, | |
}; | |
const validateBarcode = (code) => { | |
if (code.length != 11) { | |
return false; | |
} | |
return true; | |
}; | |
const defaultDecoders = ['code_128_reader', 'qrcode']; | |
const ScannerCore = ({ | |
onDetected, | |
scannerRef, | |
onScannerReady, | |
cameraId, | |
facingMode, | |
constraints = defaultConstraints, | |
locator = defaultLocatorSettings, | |
numOfWorkers = navigator.hardwareConcurrency || 0, | |
decoders = defaultDecoders, | |
locate = true, | |
}) => { | |
const errorCheck = useCallback((result) => { | |
if (!onDetected) { | |
return; | |
} | |
const err = getMedianOfCodeErrors(result.codeResult.decodedCodes); | |
// if Quagga is at least 75% certain that it read correctly, then accept the code. | |
if (err < 0.25) { | |
onDetected(result); | |
} | |
}, [onDetected]); | |
const handleProcessed = (result) => { | |
const drawingCtx = Quagga.canvas.ctx.overlay; | |
const drawingCanvas = Quagga.canvas.dom.overlay; | |
drawingCtx.font = "24px Arial"; | |
drawingCtx.fillStyle = 'green'; | |
if (result) { | |
if (result.boxes) { | |
drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute('width')), parseInt(drawingCanvas.getAttribute('height'))); | |
result.boxes.filter((box) => box !== result.box).forEach((box) => { | |
Quagga.ImageDebug.drawPath(box, {x: 0, y: 1}, drawingCtx, {color: 'purple', lineWidth: 2}); | |
}); | |
} | |
if (result.box) { | |
Quagga.ImageDebug.drawPath(result.box, {x: 0, y: 1}, drawingCtx, {color: 'blue', lineWidth: 2}); | |
} | |
if (result.codeResult && result.codeResult.code) { | |
const validated = validateBarcode(result.codeResult.code); | |
Quagga.ImageDebug.drawPath(result.line, { | |
x: 'x', | |
y: 'y' | |
}, drawingCtx, {color: validated ? 'green' : 'red', lineWidth: 3}); | |
drawingCtx.font = "24px Arial"; | |
drawingCtx.fillStyle = validated ? 'green' : 'red'; | |
drawingCtx.fillText(`${result.codeResult.code} valid: ${validated}`, 10, 50); | |
drawingCtx.fillText(result.codeResult.code, 10, 20); | |
if (validated) { | |
onDetected(result); | |
} | |
} | |
} | |
}; | |
useLayoutEffect(() => { | |
Quagga.init({ | |
inputStream: { | |
type: 'LiveStream', | |
constraints: { | |
...constraints, | |
...(cameraId && {deviceId: cameraId}), | |
...(!cameraId && {facingMode}), | |
}, | |
target: scannerRef.current, | |
}, | |
locator, | |
numOfWorkers, | |
readers: decoders, | |
locate, | |
}, (err) => { | |
Quagga.onProcessed(handleProcessed); | |
if (err) { | |
return console.log('Error starting Quagga:', err); | |
} | |
if (scannerRef && scannerRef.current) { | |
Quagga.start(); | |
if (onScannerReady) { | |
onScannerReady(); | |
} | |
} | |
}); | |
Quagga.onDetected(errorCheck); | |
return () => { | |
Quagga.offDetected(errorCheck); | |
Quagga.offProcessed(handleProcessed); | |
Quagga.stop(); | |
}; | |
}, [cameraId, onDetected, onScannerReady, scannerRef, errorCheck, constraints, locator, decoders, locate]); | |
return null; | |
} | |
export default ScannerCore; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment