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.
159 lines
5.0 KiB
159 lines
5.0 KiB
<!DOCTYPE html> |
|
<html> |
|
|
|
<head> |
|
<title>zxing-cpp/wasm live demo</title> |
|
<link rel="shortcut icon" href="#" /> |
|
<script src="zxing_reader.js"></script> |
|
</head> |
|
|
|
<body style="text-align: center"> |
|
<h2>zxing-cpp/wasm live demo</h2> |
|
<p> |
|
This is a simple demo of the wasm wrapper of <a href="https://github.com/zxing-cpp/zxing-cpp">zxing-cpp</a> |
|
scanning for barcodes in a live video stream. |
|
</p> |
|
|
|
Camera: |
|
<select id="cameraSelector"> |
|
<option value="user">Front Camera</option> |
|
<option value="environment">Back Camera</option> |
|
</select> |
|
|
|
|
|
Format: |
|
<select id="format"> |
|
<option value="" selected="">Any</option> |
|
<option value="Aztec">Aztec</option> |
|
<option value="Code39">Codabar</option> |
|
<option value="CODE_39">Code39</option> |
|
<option value="Code93">Code93</option> |
|
<option value="Code128">Code128</option> |
|
<option value="DataMatrix">DataMatrix</option> |
|
<option value="DataBar">DataBar</option> |
|
<option value="DataBarExpanded">DataBarExpanded</option> |
|
<option value="DataBarLimited">DataBarLimited</option> |
|
<option value="DXFilmEdge">DXFilmEdge</option> |
|
<option value="EAN8">EAN-8</option> |
|
<option value="EAN13">EAN-13</option> |
|
<option value="ITF">ITF</option> |
|
<option value="PDF417">PDF417</option> |
|
<option value="QRCode">QRCode</option> |
|
<option value="MicroQRCode">Micro QRCode</option> |
|
<option value="RMQRCode">rMQR Code</option> |
|
<option value="UPCA">UPC-A</option> |
|
<option value="UPCE">UPC-E</option> |
|
<option value="LinearCodes">Linear Codes</option> |
|
<option value="MatrixCodes">Matrix Codes</option> |
|
</select> |
|
|
|
|
|
Mode: |
|
<select id="mode"> |
|
<option value="true" selected="">Normal</option> |
|
<option value="false">Fast</option> |
|
</select> |
|
<br /><br /> |
|
|
|
<canvas id="canvas" width="640" height="480"></canvas> |
|
<br /><br /> |
|
|
|
<div id="result"></div> |
|
|
|
<script> |
|
var zxing = ZXing().then(function (instance) { |
|
zxing = instance; // this line is supposedly not required but with current emsdk it is :-/ |
|
}); |
|
|
|
const cameraSelector = document.getElementById("cameraSelector"); |
|
const format = document.getElementById("format"); |
|
const mode = document.getElementById("mode"); |
|
const canvas = document.getElementById("canvas"); |
|
const resultElement = document.getElementById("result"); |
|
|
|
const ctx = canvas.getContext("2d", { willReadFrequently: true }); |
|
const video = document.createElement("video"); |
|
video.setAttribute("id", "video"); |
|
video.setAttribute("width", canvas.width); |
|
video.setAttribute("height", canvas.height); |
|
video.setAttribute("autoplay", ""); |
|
|
|
function readBarcodeFromCanvas(canvas, format, mode) { |
|
var imgWidth = canvas.width; |
|
var imgHeight = canvas.height; |
|
var imageData = canvas.getContext('2d').getImageData(0, 0, imgWidth, imgHeight); |
|
var sourceBuffer = imageData.data; |
|
|
|
if (zxing != null) { |
|
var buffer = zxing._malloc(sourceBuffer.byteLength); |
|
zxing.HEAPU8.set(sourceBuffer, buffer); |
|
var result = zxing.readBarcodeFromPixmap(buffer, imgWidth, imgHeight, mode, format); |
|
zxing._free(buffer); |
|
return result; |
|
} else { |
|
return { error: "ZXing not yet initialized" }; |
|
} |
|
} |
|
|
|
function drawResult(code) { |
|
ctx.beginPath(); |
|
ctx.lineWidth = 4; |
|
ctx.strokeStyle = "red"; |
|
// ctx.textAlign = "center"; |
|
// ctx.fillStyle = "#green" |
|
// ctx.font = "25px Arial"; |
|
// ctx.fontWeight = "bold"; |
|
with (code.position) { |
|
ctx.moveTo(topLeft.x, topLeft.y); |
|
ctx.lineTo(topRight.x, topRight.y); |
|
ctx.lineTo(bottomRight.x, bottomRight.y); |
|
ctx.lineTo(bottomLeft.x, bottomLeft.y); |
|
ctx.lineTo(topLeft.x, topLeft.y); |
|
ctx.stroke(); |
|
// ctx.fillText(code.text, (topLeft.x + bottomRight.x) / 2, (topLeft.y + bottomRight.y) / 2); |
|
} |
|
} |
|
|
|
function escapeTags(htmlStr) { |
|
return htmlStr.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); |
|
} |
|
|
|
const processFrame = function () { |
|
ctx.drawImage(video, 0, 0, canvas.width, canvas.height); |
|
|
|
const code = readBarcodeFromCanvas(canvas, format.value, mode.value === 'true'); |
|
if (code.format) { |
|
resultElement.innerText = code.format + ": " + escapeTags(code.text); |
|
drawResult(code) |
|
} else { |
|
resultElement.innerText = "No barcode found"; |
|
} |
|
requestAnimationFrame(processFrame); |
|
}; |
|
|
|
const updateVideoStream = function (deviceId) { |
|
// To ensure the camera switch, it is advisable to free up the media resources |
|
if (video.srcObject) video.srcObject.getTracks().forEach(track => track.stop()); |
|
|
|
navigator.mediaDevices |
|
.getUserMedia({ video: { facingMode: deviceId }, audio: false }) |
|
.then(function (stream) { |
|
video.srcObject = stream; |
|
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen |
|
video.play(); |
|
processFrame(); |
|
}) |
|
.catch(function (error) { |
|
console.error("Error accessing camera:", error); |
|
}); |
|
}; |
|
|
|
cameraSelector.addEventListener("change", function () { |
|
updateVideoStream(this.value); |
|
}); |
|
|
|
updateVideoStream(); |
|
</script> |
|
</body> |
|
|
|
</html>
|
|
|