(143) スマホのWebブラウザでISBNを読み取る。

投稿者: | 2023年12月16日

69 views

1. やりたいこと

前回の投稿 (142) JavaScriptでISBN書籍情報を取得・表示する。 では、テキストボックス内に入力した ISBNコードを使って Google Books API に問合せ、取得した書籍情報を画面上に表示する JavaScriptプログラムを作った。

今回はこれを更に改造し、
Webブラウザ上の操作でスマホのカメラを起動し、
 → カメラ映像中の ISBNコードを自動で判読し、
  → その値をテキストボックスに入力する

という処理を追加したい。

これが実装できると、
Webブラウザ上でスマホカメラを使って ISBNコードを読み取り、
Google Books APIで取得した書籍情報をWebブラウザ上に表示する

までを一気通貫で出来るようになる。

2. やってみる

動作確認した環境は以下の通り。
・Android: Chrome
・iPhone, iPad: Chrome, Safari
※Webブラウザの設定で、カメラへのアクセスを拒否している場合、設定変更が必要!

実装済みのページはこちら。
https://www.dogrow.net/hp/sample/00143/

1) 使用するバーコードリーダーライブラリ

今回は Quagga バーコードリーダーを利用させていただく。
公式サイト: https://serratus.github.io/quaggaJS/
GitHub: https://github.com/serratus/quaggaJS

今回は、GitHubからダウンロードしたソースの中から quagga.min.js を使わせていただく。

2) 画面仕様

3) 実装&動作確認したプログラムソースコード

(1) index.html

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Blog #143</title>
  <link rel="stylesheet" href="style.css" />
  <script src="quagga.min.js"></script>
  <script src="script.js"></script>
</head>
<body>
  <input id="btnStartCamera" class="btn" type="button" value="カメラ起動" />
  <input id="btnStartScan"   class="btn" type="button" value="ISBNスキャン" disabled="true" />
  <p id="ISBNShow"></p>
  <div id="CameraView"><div id="ScanFrame"></div></div>
  <div id="BookInfo"></div>
</body>
</html>

(2) style.css

*{               /* 全体 */
  margin: 0;
  box-sizing: border-box;
}
.btn{            /* ボタン */
  font-size: 2rem;
  width: 100%;
}
#ScanFrame{      /* スキャン領域の枠線 */
  position: absolute;
  display: none;
  top:     30%;
  left:    10%;
  height:  20%;
  width:   80%;
  border:  5px #ff0 solid;
  z-index: 1;
}
#CameraView{     /* カメラ映像表示欄 */
  position: relative;
  display: none;
  top:     0;
  left:    0;
  width:   100%;
  height:  100%;
}
#ISBNShow{       /* ISBNコード表示欄 */
  margin: 1rem;
  font-size:  1.5rem;
  text-align: center;
}
#BookInfo{       /* 書籍情報表示欄 */
  border:2px solid #F00;
}
/*
以下の要素は、Quaggaが自動的に埋め込んでいる。
これらの要素の表示幅が画面幅をオーバーしている。→ 表示幅を制限したい。
*/
canvas, video {
  width:  100% !important;
  height: auto !important;
}
canvas{
  position: absolute;
}

(3) script.js

プログラムソースコード中にコメントを記述したので、ここでの解説は省略する。

// DOM生成完了通知イベントハンドラを登録する。
document.addEventListener("DOMContentLoaded", function() {
  const divCameraView  = document.getElementById('CameraView');
  const divScanFrame   = document.getElementById('ScanFrame');
  const divBookInfo    = document.getElementById('BookInfo');
  const divshowISBN    = document.getElementById('ISBNShow');
  const btnStartCamera = document.getElementById('btnStartCamera');
  const btnStartScan   = document.getElementById('btnStartScan');

  //////////////////////////////////////////////////////////////////////////////
  // [カメラ起動]ボタン押下時のイベントハンドラを登録する。
  btnStartCamera.addEventListener('click', function() {
    this.disabled = true;                   // [カメラ起動]ボタンを無効化
    btnStartScan.disabled = false;          // [ISBNスキャン]ボタンを有効化
    divCameraView.style.display = 'block';  // カメラ映像表示欄 表示ON
    divScanFrame.style.display  = 'block';  // スキャン枠 表示ON
    divBookInfo.innerText = '';             // 書籍情報欄をクリア
    divshowISBN.innerText = '';             // ISBNコード表示欄をクリア
    activateCamera();                       // カメラ起動
  });

  //////////////////////////////////////////////////////////////////////////////
  // [ISBNスキャン]ボタン押下時のイベントハンドラを登録する。
  btnStartScan.addEventListener('click', function() {
    this.disabled = true;               // [ISBNスキャン]ボタンを無効化
    startScanning();                    // スキャン開始
  });

  //////////////////////////////////////////////////////////////////////////////
  // 関数:カメラ起動
  function activateCamera() {
    // init( {成功時の関数}, {失敗時の関数} )
    Quagga.init({                       // Quagga初期化
      inputStream: {
        name: 'MyScanProc',
        type: 'LiveStream',
        target: divCameraView,          // カメラ映像の表示領域を指定
        constraints: {
          facingMode: 'environment',    // スマホの背面カメラを使用
          width:  { min: 640, ideal: 1280, max: 1920 },   // スキャン時の画像解像度(H方向)を指定
          height: { min: 480, ideal:  720, max: 1080 }    // スキャン時の画像解像度(V方向)を指定
        },
        area: {                         // スキャン領域を指定 ※親要素の矩形範囲を基準に指定する。
          top:    '30%',                // 画面上部からの距離
          right:  '10%',                // 画面右端からの距離
          left:   '10%',                // 画面左端からの距離
          bottom: '50%'                 // 画面下部からの距離
        }
      },
      decoder: {
        readers: ['ean_reader']         // 読み取り対象のバーコードは EAN (EAN-13等)を指定
      },
      locate: false                     // バーコードの自動検出を無効化
                                        // ※上でarea指定しているので自動検出は無効でよい。
    }, function(err) {    // init()の第2引数 (=失敗時の関数)
      if(err){
        console.log(err);
        return;
      }
    });
    // バーコード検出完了時のイベントハンドラを登録する。
    Quagga.onDetected(onDetectedCallback);
  }

  //////////////////////////////////////////////////////////////////////////////
  // 関数:バーコードのスキャン完了通知イベントハンドラ
  function onDetectedCallback(result) {
    Quagga.stop();                            // スキャンを停止する。
    Quagga.offDetected(onDetectedCallback);   // バーコード検出完了時のイベントハンドラを削除する。
    var isbn = result.codeResult.code;        // 読み出したISBNコードを取得する。
    divshowISBN.innerText = isbn;             // ISBNコードの表示欄に表示する。
    btnStartCamera.disabled = false;          // [カメラ起動]ボタンを有効化
    divScanFrame.style.display  = 'none';     // スキャン枠 表示OFF
    divCameraView.style.display = 'none';     // カメラ映像表示欄 表示OFF
    startISBNQuery();                         // Google Books APIにISBN問合せを実行する。
  }

  //////////////////////////////////////////////////////////////////////////////
  // 関数:バーコードのスキャンを開始
  function startScanning() {
    Quagga.start();
  }

  //////////////////////////////////////////////////////////////////////////////
  // 関数:Google Books APIにISBN問合せ
  function startISBNQuery(){
    var isbn = divshowISBN.innerText;         // ISBNコード表示欄から値を取得する。
    // Google Books Web APIを使って指定したISBNに対応する書籍情報を取得する。
    fetch(`https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}`)
    .then(resp => resp.json())                // 連結#1:受信データをデコードして JSONオブジェクトを生成
    .then(data => {                           // 連結#2:JSONオブジェクトを受け取り
      console.log(data);
      // 書籍データの解析と表示
      if(data.items && data.items.length > 0){
        var book = data.items[0].volumeInfo;
        // 書籍情報を表示する。
        divBookInfo.innerHTML = `
          タイトル: ${book.title}<br />
          著者:     ${book.authors}<br />
          出版社:   ${book.publisher}
        `;
      }else{
        divBookInfo.innerHTML = `${isbn}の書籍情報が見つかりませんでした。`;
      }
    })
    .catch(error => {
      console.error('Error fetching data:', error);
    });
  }
});

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)