jsQRとElectronでウインドウの下にあるqrコードを取得する

作るもの

こんなものを作る必要がありました

こうゆう感じ

これを作ってみます

Electron

タイトルにあったelectronというのはNode.js(JavaScriptのブラウザがなくても動く派生版みたいなもの)のデスクトップアプリのフレームワークで

  • Visual Studio Code
  • Facebook Messenger
  • Twitch
  • Slack
  • InVision

とかのアプリもこれで作られてます。by公式ページ

これで作ります

npm i -D electron@latest jsqr
ShellScript

をやっといてください

次にpackage.jsonのscriptsの中に

"start": "electron ."
JSON

と加えてください

ステップ1 ウインドウを作る

ウインドウを作ります

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');

app.whenReady().then(function () {
    const camwin = new BrowserWindow({
        width: 300,
        height: 300,
        opacity: 0.55,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
        },
        alwaysOnTop: true
    });
    camwin.loadFile(path.join(__dirname, 'qr_scan.html'));
});
index.js

camwinという変数にウインドウを入れています。

今やるとエラーが出ます

ステップ2 HTMLを作る

htmlを書くだけでデスクトップアプリになります

意味深なvideoとcanvasがあります

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>QRをスキャン</title>
</head>
<body title="クリックして決定">
    <div style="border: solid 3px black; width: 280px; height: 250px;"></div>
    <video id="video" style="display: none;" autoplay></video>
    <canvas style="display: none; width: 300px; height: 300px;" id="cam"></canvas>
</body>
</html>
qr_scan.html

表示すると枠が出てきます。

ステップ3 一旦実行してみる

index.jsの8-10行を //コメント にしてください

npm start
ShellScript

をシェルで実行してください

すると透けたウインドウが出ます

control + cを押して止めたら、コメントをもとに戻します

ステップ4 移動を検知して伝える

index.jsの14行目に

camwin.on('move', function (_event) {
    camwin.webContents.send('qr_window_move', camwin.getPosition());
});
index.js:14-16

と追記してください

これはウインドウが動かされたことを検知して、それを別のところに送信するというものです

ステップ5 ”別の所”で動いたということを受け取り、処理する

index.jsの9行目で”別の所”を指定しています。

ここで指定したファイルでは、アプリのwebページにも、Node.jsにもアクセスできるようになります。

ここで画面の映像を取得して、QRコードを読み取るということです

const { ipcRenderer } = require('electron');
const { default: jsQR } = require('jsqr');
let qr_code = ''
window.addEventListener('DOMContentLoaded', function () {
    const canvas = document.getElementById('cam');
    const video = document.getElementById('video');
    const ctx = canvas.getContext('2d');
    navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
            mandatory: {
                chromeMediaSource: 'desktop'
            }
        }
    }).then(async function (stream) {
        video.srcObject = stream;
    });
    ipcRenderer.on('qr_window_move', function (_event, pos) {
        document.body.style.backgroundColor = ''
        qr_code = ''
        ctx.drawImage(video, pos[0], pos[1], 300, 300, 0, 0, canvas.width, canvas.height);
        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        code = jsQR(imageData.data, canvas.width, canvas.height);
        if (code) {
            document.body.style.backgroundColor = 'aqua'
            qr_code = code.data
        }
    });
    document.addEventListener('click', function () {
        if (qr_code != '') {
            ipcRenderer.send('get_qr', qr_code);
            window.close();
        }
    })
});
preload.js

一個ずつ解説します

1,2行目ではイベントを受け取るために必要なElectronのipcRendererとQRコードを読み取るために必要なjsQRをインポートしています

8から17行目で、デスクトップ映像を取得し、あの謎のvideoに流してます。

18行目でイベントを受け取っています。”qr_window_move”はindex.jsにもあります。引数posはウインドウの場所の配列です

19行目はqrコードが見つかったときのハイライトを消しているだけです。

**21行目** これが肝で, videoからウインドウの部分だけを切り抜いてcanvasに描画しています
ウインドウの位置からウインドウの幅、高さ分広げたものを、canvasのてっぺんからcanvasの一番下までに描画するようにしています

そしてそこからImageDataを取得してqrが見つかったらハイライトさせてQRコードのデータを別の変数に移しています

30行目はクリックされてqrコードがあったらメインプロセスに送っています

ステップ6

メインプロセスでqrコードを受け取る

index.jsに次のように追記してください

ipcMain.on('get_qr', function (_event, qr) {
    console.log(qr)
});
index.js

get_qrを受け取ったらコンソールにログ出力しています。

これで実行してみてください

npm start
ShellScript

ウインドウをqrコードの上に置いて、クリックするとコンソールに出力があると思います。

GitHub Gistに乗せておきました

https://github.com/Koro-soft/qr-reader-electron

コメントする

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


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください