Skip to content

Instantly share code, notes, and snippets.

@tangoabcdelta
Created August 26, 2022 06:12
Show Gist options
  • Save tangoabcdelta/91593a0147965ffd690c9de120ef4375 to your computer and use it in GitHub Desktop.
Save tangoabcdelta/91593a0147965ffd690c9de120ef4375 to your computer and use it in GitHub Desktop.
BarcodeDetector Experimental Web APIs
html, body {
background: #111;
color: white;
height: 100%;
}
canvas {
display: none;
height: auto;
object-fit: contain;
object-position: center;
width: 300px;
}
pre, canvas {
background: black;
margin: 1rem auto;
}
pre {
box-sizing: border-box;
color: white;
padding: 1rem;
text-align: center;
white-space: pre-wrap;
width: 200px;
}
video {
opacity: 0;
position: fixed;
top: 0;
left: 0;
width: 10px;
height: auto;
}
<canvas></canvas>
<video autoplay playsinline muted></video>
<pre>Click anywhere to start</pre>
console.clear();
const pre = document.querySelector("pre");
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
const video = document.querySelector("video");
async function run() {
canvas.style.display = "block";
pre.innerText = "";
pre.style.display = "none";
const formats = await BarcodeDetector.getSupportedFormats();
const detector = new BarcodeDetector({ formats });
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.onloadedmetadata = () => {
canvas.height = video.videoHeight;
canvas.width = video.videoWidth;
loop();
}
video.srcObject = stream;
const boxes = {};
const codes = {};
function drawBoxes(del = false) {
context.strokeStyle = "lime";
context.lineWidth = 4;
Object.keys(boxes).forEach((key) => {
const { format, rawValue, minX, maxX, minY, maxY } = boxes[key];
context.strokeRect(minX, minY, maxX - minX, maxY - minY);
if (del) delete boxes[key];
});
}
async function loop() {
try {
context.drawImage(video, 0, 0);
const image = context.getImageData(0, 0, canvas.width, canvas.height);
drawBoxes(true);
const barcodes = await detector.detect(image);
let changed = false;
barcodes.forEach(({ boundingBox: { x, y, width, height }, format, rawValue: value }) => {
codes[format] = codes[format] || {};
if (!codes[format][value]) {
changed = true;
}
codes[format][value] = 1;
boxes[value] = boxes[value] || {
format, value,
minX: Infinity, maxX: -Infinity,
minY: Infinity, maxY: -Infinity
};
boxes[value].minX = Math.min(x, boxes[value].minX);
boxes[value].maxX = Math.max(x + width, boxes[value].maxX);
boxes[value].minY = Math.min(y, boxes[value].minY);
boxes[value].maxY = Math.max(y + height, boxes[value].maxY);
});
drawBoxes();
if (changed) {
pre.style.display = "block";
pre.innerHTML = Object.keys(codes).map((type) =>
[type, ...Object.keys(codes[type])].join("\n")
).join("\n");
}
setTimeout(loop, 150);
} catch(e) {
console.error(e);
}
}
}
if ("BarcodeDetector" in window) {
let running = false;
document.body.addEventListener("click", () => {
if (!running) {
running = true;
run();
}
});
} else {
pre.innerText = "BarcodeDetector is not supported by this browser";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment