最近、いろいろと調べながら対応したので、メモしておきます。
今回やったこと
- ブラウザ上でバーコードスキャン機能を実装
- モーダル画面を表示するとカメラをオンにしてスキャン開始
- モーダル画面を閉じるとスキャン終了してカメラをオフ
- モーダル画面を開いたボタンに応じて、スキャン結果の返却先を変更
- VB.NET (.NET Framework)環境で実装
使用したライブラリやフレームワーク
- QuaggaJS
- バーコードスキャン機能を提供してくれるライブラリ
- QRコードには非対応
- BootStrap 5
- 画面全体のスタイル調整
- モーダル画面の表示にも活用
ソース
HTML部分(一部抜粋):sample.aspx
<!doctype html> <html lang="ja"> <head runat="server"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>バーコードスキャンテスト</title> <%--BootstrapのCSS読み込み--%> <link rel="stylesheet" type="text/css" href="../../Css/Bootstrap/bootstrap.min.css" /> <%--画面のCSS読み込み--%> <link rel="stylesheet" type="text/css" href="../../Css/Sample/sample.css" /> <%--jQuery読み込み--%> <script src="../../Script/jQuery/jquery-3.6.0.min.js"></script> </head> <body> <%--検索条件--%> <div id="KensakuArea" class="container"> <div class="row"> <div class="col-auto"> <table> <tr> <%--バーコード①--%> <td> <%--モーダルウィンドウの結果を設定するためにIDモードをStaticにしている--%> <asp:TextBox ID="txtBarcode1" runat="server" ClientIDMode="Static" placeholder="バーコード①" CssClass="form-control form-control-sm"/> </td> <td> <%--バーコードスキャン用モーダル画面の表示--%> <%--ASPタグを利用するとPostBackが生じてモーダル画面が表示後即座に消えてるため、あえて通常のタグを利用している--%> <button type="button" style="width:30px; margin:0px; padding:0px; border:none;" data-bs-toggle="modal" data-bs-target="#staticBackdrop" data-textboxid="txtBarcode1"> <img src="../../Img/camera.png" style="width: 30px;"/> </button> </td> <%--バーコード②--%> <td> <%--モーダルウィンドウの結果を設定するためにIDモードをStaticにしている--%> <asp:TextBox ID="txtBarcode2" runat="server" CssClass="form-control form-control-sm" ClientIDMode="Static"/> </td> <td> <%--バーコードスキャン用モーダル画面の表示--%> <%--ASPタグを利用するとPostBackが生じてモーダル画面が表示後即座に消えてるため、あえて通常のタグを利用している--%> <button type="button" style="width:30px; margin:0px; padding:0px; border:none;" data-bs-toggle="modal" data-bs-target="#staticBackdrop" data-textboxid="txtBarcode2"> <img src="../../Img/camera.png" style="width: 30px;"/> </button> </td> </tr> </table> </div> <%--モーダルウィンドウ(開始)--%> <div class="modal fade" id="staticBackdrop" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"> <div class="modal-dialog modal-lg modal-fullscreen-lg-down"> <div class="modal-content"> <%--タイトル--%> <div class="modal-header"> <H4 class="modal-title" id="staticBackdropLabel">バーコードスキャン</H4> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <%--読み取り部--%> <div class="modal-body text-center" style="margin: 0px auto;"> <%--呼び出し元から渡された引数を保持するHiiden項目--%> <div style="visibility:visible;"> <input type="hidden" id="targetTextBoxID"> </div> <div> <input type="text" id="scanResult" placeholder="読み取り結果"> </div> <%--photo-area部分にカメラの映像を表示--%> <div id="photo-area" class="viewport"></div> </div> <%--フッター--%> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">キャンセル</button> <button type="button" id="btnDone" class="btn btn-primary">決定</button> </div> </div> </div> </div> <%--モーダルウィンドウ(終了)--%> </div> </div> <%--QuaggaJS読み込み--%> <script type="text/javascript" src="../../Script/QuaggaJS/quagga.js"></script> <%--画面用のScript読み込み--%> <script type="text/javascript" src="../../Script/Sample/sample.js"></script> <%--BootstrapのScript読み込み--%> <script src="../../Script/Bootstrap/bootstrap.bundle.min.js"></script> </body> </html>
CSSファイル(sample.css)
/********************************* * バーコード用モーダル * canvasやvideo等のHTML上にないタグはQuaggaJSから生成される *********************************/ #photo-area.viewport canvas, video { margin: 10px auto; } #photo-area.viewport canvas.drawingBuffer, video.drawingBuffer { margin-left: -640px; }
JSファイル(sample.js)
//=================================================================================== // モーダル画面の表示・親画面への値返却 //=================================================================================== // モーダル画面を開いた時の処理 $('#staticBackdrop').on('show.bs.modal', function (event) { // モーダルを開いたボタンを取得 var button = $(event.relatedTarget); // data-textboxidの値取得 var targetTextBoxID = button.data('textboxid'); // モーダルを取得 var modal = $(this); // 受け取った値をspanタグのとこに保持 modal.find('.modal-body #targetTextBoxID').text(targetTextBoxID); // スキャン開始 console.log("start"); startScanner(); }); // モーダルの「×」や「キャンセル」ボタンを押した時の処理 $('#staticBackdrop').on('hidden.bs.modal', function (event) { // モーダル閉じる $('#staticBackdrop').modal('hide'); // スキャン終了 console.log("stop"); Quagga.stop(); }); // モーダルの「決定」ボタンを押した時の処理 $("#btnDoneScan").on('click', function () { // モーダル閉じる $('#staticBackdrop').modal('hide'); // モーダル画面で設定した値を取得し変数に保存 var scanResultVal = $('#scanResult').val(); var targetTextBoxID = $('#targetTextBoxID').text(); // 変数保存済みの読み込み結果をクリア $('#scanResult').val(""); // 呼び出し元のボタンに応じたテキストボックスに設定 switch (targetTextBoxID) { case 'txtBarcode1': $("#txtBarcode2").val(scanResultVal); break; case 'txtBarcode2': $("#txtBarcode2").val(scanResultVal); } // スキャン終了 console.log("stop"); Quagga.stop(); }); //=================================================================================== // バーコード用 //=================================================================================== const startScanner = () => { Quagga.init({ // 設定 inputStream: { name: "Live", type: "LiveStream", target: document.querySelector('#photo-area'), constraints: { decodeBarCodeRate: 3, successTimeout: 500, codeRepetition: true, tryVertical: true, frameRate: 15, width: 640, height: 480, facingMode: "environment" } }, // デコードタイプ(複数指定可能) decoder: { readers: [ "code_39_reader" ] } }, function (err) { if (err) { console.log(err); return; } console.log("Initialization finished. Ready to start"); Quagga.start(); // Set flag to is running _scannerIsRunning = true; }); /** * Quagga.onProcessed(callback) * 処理が完了した後にフレームごとに呼び出される関数callback(data)を登録。 **/ Quagga.onProcessed(function (result) { var drawingCtx = Quagga.canvas.ctx.overlay, drawingCanvas = Quagga.canvas.dom.overlay; if (result) { // console.log("processing"); // 検出中の緑の線の枠 if (result.boxes) { //drawingCtx.clearRect(0, 0, parseInt(drawingCanvas.getAttribute("width")), parseInt(drawingCanvas.getAttribute("height"))); drawingCtx.clearRect(0, 0, drawingCanvas.width, drawingCanvas.height); result.boxes.filter(function (box) { return box !== result.box; }).forEach(function (box) { Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, drawingCtx, { color: "green", lineWidth: 2 }); }); } // 検出に成功した瞬間の青い線の枠 if (result.box) { console.log("success"); Quagga.ImageDebug.drawPath(result.box, { x: 0, y: 1 }, drawingCtx, { color: "#00F", lineWidth: 2 } ); } // 検出に成功した瞬間の水平の赤い線 if (result.codeResult && result.codeResult.code) { Quagga.ImageDebug.drawPath(result.line, { x: 'x', y: 'y' }, drawingCtx, { color: 'red', lineWidth: 3 } ); } } }); //barcode read call back Quagga.onDetected(function (result) { // 取得時の画像を表示 var resultImg = document.querySelector(".resultImg"); //resultImg.setAttribute("src", this.Quagga.canvas.dom.image.toDataURL()); var resultCode = result.codeResult.code; // モーダルテキストボックスに表示 $('#scanResult').val(resultCode); console.log("stop"); Quagga.stop(); }); }
参考サイト
QuaggaJSの使い方について
メッチャ参考になりました。
ameblo.jp
コメント