作るもの
こんなものを作る必要がありました
これを作ってみます
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.jscamwin
という変数にウインドウを入れています。
今やるとエラーが出ます
ステップ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.jsget_qr
を受け取ったらコンソールにログ出力しています。
これで実行してみてください
npm start
ShellScriptウインドウをqrコードの上に置いて、クリックするとコンソールに出力があると思います。
GitHub Gistに乗せておきました