demo_cam_reader.html 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>zxing-cpp/wasm live demo</title>
  5. <link rel="shortcut icon" href="#" />
  6. <script src="zxing_reader.js"></script>
  7. </head>
  8. <body style="text-align: center">
  9. <h2>zxing-cpp/wasm live demo</h2>
  10. <p>
  11. This is a simple demo of the wasm wrapper of <a href="https://github.com/zxing-cpp/zxing-cpp">zxing-cpp</a>
  12. scanning for barcodes in a live video stream.
  13. </p>
  14. Camera:
  15. <select id="cameraSelector">
  16. <option value="user">Front Camera</option>
  17. <option value="environment">Back Camera</option>
  18. </select>
  19. &nbsp;&nbsp;
  20. Format:
  21. <select id="format">
  22. <option value="" selected="">Any</option>
  23. <option value="Aztec">Aztec</option>
  24. <option value="Code39">Codabar</option>
  25. <option value="CODE_39">Code39</option>
  26. <option value="Code93">Code93</option>
  27. <option value="Code128">Code128</option>
  28. <option value="DataMatrix">DataMatrix</option>
  29. <option value="DataBar">DataBar</option>
  30. <option value="DataBarExpanded">DataBarExpanded</option>
  31. <option value="DataBarLimited">DataBarLimited</option>
  32. <option value="DXFilmEdge">DXFilmEdge</option>
  33. <option value="EAN8">EAN-8</option>
  34. <option value="EAN13">EAN-13</option>
  35. <option value="ITF">ITF</option>
  36. <option value="PDF417">PDF417</option>
  37. <option value="QRCode">QRCode</option>
  38. <option value="MicroQRCode">Micro QRCode</option>
  39. <option value="RMQRCode">rMQR Code</option>
  40. <option value="UPCA">UPC-A</option>
  41. <option value="UPCE">UPC-E</option>
  42. <option value="LinearCodes">Linear Codes</option>
  43. <option value="MatrixCodes">Matrix Codes</option>
  44. </select>
  45. &nbsp;&nbsp;
  46. Mode:
  47. <select id="mode">
  48. <option value="true" selected="">Normal</option>
  49. <option value="false">Fast</option>
  50. </select>
  51. <br /><br />
  52. <canvas id="canvas" width="640" height="480"></canvas>
  53. <br /><br />
  54. <div id="result"></div>
  55. <script>
  56. var zxing = ZXing().then(function (instance) {
  57. zxing = instance; // this line is supposedly not required but with current emsdk it is :-/
  58. });
  59. const cameraSelector = document.getElementById("cameraSelector");
  60. const format = document.getElementById("format");
  61. const mode = document.getElementById("mode");
  62. const canvas = document.getElementById("canvas");
  63. const resultElement = document.getElementById("result");
  64. const ctx = canvas.getContext("2d", { willReadFrequently: true });
  65. const video = document.createElement("video");
  66. video.setAttribute("id", "video");
  67. video.setAttribute("width", canvas.width);
  68. video.setAttribute("height", canvas.height);
  69. video.setAttribute("autoplay", "");
  70. function readBarcodeFromCanvas(canvas, format, mode) {
  71. var imgWidth = canvas.width;
  72. var imgHeight = canvas.height;
  73. var imageData = canvas.getContext('2d').getImageData(0, 0, imgWidth, imgHeight);
  74. var sourceBuffer = imageData.data;
  75. if (zxing != null) {
  76. var buffer = zxing._malloc(sourceBuffer.byteLength);
  77. zxing.HEAPU8.set(sourceBuffer, buffer);
  78. var result = zxing.readBarcodeFromPixmap(buffer, imgWidth, imgHeight, mode, format);
  79. zxing._free(buffer);
  80. return result;
  81. } else {
  82. return { error: "ZXing not yet initialized" };
  83. }
  84. }
  85. function drawResult(code) {
  86. ctx.beginPath();
  87. ctx.lineWidth = 4;
  88. ctx.strokeStyle = "red";
  89. // ctx.textAlign = "center";
  90. // ctx.fillStyle = "#green"
  91. // ctx.font = "25px Arial";
  92. // ctx.fontWeight = "bold";
  93. with (code.position) {
  94. ctx.moveTo(topLeft.x, topLeft.y);
  95. ctx.lineTo(topRight.x, topRight.y);
  96. ctx.lineTo(bottomRight.x, bottomRight.y);
  97. ctx.lineTo(bottomLeft.x, bottomLeft.y);
  98. ctx.lineTo(topLeft.x, topLeft.y);
  99. ctx.stroke();
  100. // ctx.fillText(code.text, (topLeft.x + bottomRight.x) / 2, (topLeft.y + bottomRight.y) / 2);
  101. }
  102. }
  103. function escapeTags(htmlStr) {
  104. return htmlStr.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
  105. }
  106. const processFrame = function () {
  107. ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
  108. const code = readBarcodeFromCanvas(canvas, format.value, mode.value === 'true');
  109. if (code.format) {
  110. resultElement.innerText = code.format + ": " + escapeTags(code.text);
  111. drawResult(code)
  112. } else {
  113. resultElement.innerText = "No barcode found";
  114. }
  115. requestAnimationFrame(processFrame);
  116. };
  117. const updateVideoStream = function (deviceId) {
  118. // To ensure the camera switch, it is advisable to free up the media resources
  119. if (video.srcObject) video.srcObject.getTracks().forEach(track => track.stop());
  120. navigator.mediaDevices
  121. .getUserMedia({ video: { facingMode: deviceId }, audio: false })
  122. .then(function (stream) {
  123. video.srcObject = stream;
  124. video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
  125. video.play();
  126. processFrame();
  127. })
  128. .catch(function (error) {
  129. console.error("Error accessing camera:", error);
  130. });
  131. };
  132. cameraSelector.addEventListener("change", function () {
  133. updateVideoStream(this.value);
  134. });
  135. updateVideoStream();
  136. </script>
  137. </body>
  138. </html>