You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
2.8 KiB
109 lines
2.8 KiB
|
3 years ago
|
import {DropImageFetchError} from "./errors.js";
|
||
|
|
import {eventOn} from "callforth";
|
||
|
|
|
||
|
|
const adaptOldFormat = detectedCodes => {
|
||
|
|
if (detectedCodes.length > 0) {
|
||
|
|
const [firstCode] = detectedCodes;
|
||
|
|
|
||
|
|
const [
|
||
|
|
topLeftCorner,
|
||
|
|
topRightCorner,
|
||
|
|
bottomRightCorner,
|
||
|
|
bottomLeftCorner
|
||
|
|
] = firstCode.cornerPoints
|
||
|
|
|
||
|
|
return {
|
||
|
|
content: firstCode.rawValue,
|
||
|
|
location: {
|
||
|
|
topLeftCorner,
|
||
|
|
topRightCorner,
|
||
|
|
bottomRightCorner,
|
||
|
|
bottomLeftCorner,
|
||
|
|
|
||
|
|
// not supported by native API:
|
||
|
|
topLeftFinderPattern: {},
|
||
|
|
topRightFinderPattern: {},
|
||
|
|
bottomLeftFinderPattern: {}
|
||
|
|
},
|
||
|
|
imageData: null
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
return {
|
||
|
|
content: null,
|
||
|
|
location: null,
|
||
|
|
imageData: null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Continuously extracts frames from camera stream and tries to read
|
||
|
|
* potentially pictured QR codes.
|
||
|
|
*/
|
||
|
|
export const keepScanning = (videoElement, options) => {
|
||
|
|
const barcodeDetector = new BarcodeDetector({formats: ["qr_code"]});
|
||
|
|
|
||
|
|
const {detectHandler, locateHandler, minDelay} = options;
|
||
|
|
|
||
|
|
const processFrame = state => async timeNow => {
|
||
|
|
if (videoElement.readyState > 1) {
|
||
|
|
const {lastScanned, contentBefore, locationBefore} = state
|
||
|
|
|
||
|
|
if (timeNow - lastScanned >= minDelay) {
|
||
|
|
const detectedCodes = await barcodeDetector.detect(videoElement);
|
||
|
|
const {content, location, imageData} = adaptOldFormat(detectedCodes)
|
||
|
|
|
||
|
|
if (content !== null && content !== contentBefore) {
|
||
|
|
detectHandler({content, location, imageData});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (location !== null || locationBefore !== null) {
|
||
|
|
locateHandler(detectedCodes);
|
||
|
|
}
|
||
|
|
|
||
|
|
window.requestAnimationFrame(processFrame({
|
||
|
|
lastScanned: timeNow,
|
||
|
|
contentBefore: content ?? contentBefore,
|
||
|
|
locationBefore: location
|
||
|
|
}))
|
||
|
|
} else {
|
||
|
|
window.requestAnimationFrame(processFrame(state))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
processFrame({
|
||
|
|
contentBefore: null,
|
||
|
|
locationBefore: null,
|
||
|
|
lastScanned: performance.now()
|
||
|
|
})();
|
||
|
|
};
|
||
|
|
|
||
|
|
const imageElementFromUrl = async url => {
|
||
|
|
if (url.startsWith("http") && url.includes(location.host) === false) {
|
||
|
|
throw new DropImageFetchError();
|
||
|
|
}
|
||
|
|
|
||
|
|
const image = document.createElement("img");
|
||
|
|
image.src = url;
|
||
|
|
|
||
|
|
await eventOn(image, "load");
|
||
|
|
|
||
|
|
return image;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const processFile = async file => {
|
||
|
|
const barcodeDetector = new BarcodeDetector({formats: ["qr_code"]})
|
||
|
|
const detectedCodes = await barcodeDetector.detect(file)
|
||
|
|
|
||
|
|
return adaptOldFormat(detectedCodes)
|
||
|
|
}
|
||
|
|
|
||
|
|
export const processUrl = async url => {
|
||
|
|
const barcodeDetector = new BarcodeDetector({formats: ["qr_code"]})
|
||
|
|
const image = await imageElementFromUrl(url);
|
||
|
|
const detectedCodes = await barcodeDetector.detect(image)
|
||
|
|
|
||
|
|
return adaptOldFormat(detectedCodes)
|
||
|
|
}
|