Symbolのアドレスを読み取る簡易QRコードスキャナを作成する

ブロックチェーン上のトークンはアドレスと呼ばれる文字列でやり取りされます。
ただ、このアドレスは非常に長いために目で見て覚えるのは困難です。
視認性の高いネームスペースが普及するにはまだ少し時間がかかるかもしれません。

今回はイベントなどで相手方のアドレスを簡単に読み取れる簡易QRコードスキャナをブラウザ上で実装してみましょう。


まず検証環境を構築します。

https://qiita.com/nem_takanobu/items/e88d5ea76cd609e76bbf


今回Webカメラを使用するので、ブラウザのセキュリティ対策のためhttps対応のノードに接続してください。

##### QRコードライブラリのインポート

```js
(script = document.createElement('script')).src = 'https://xembook.github.io/sigann/jsQR.js';
document.getElementsByTagName('head')[0].appendChild(script);
```

githubのxembook/sigannレポジトリにjsQRを置いていますのでインポートしてください。

##### スキャナスクリプトの実行

```js
var isMovieScanning = false;
var video = document.createElement("video");
var canvasElement= document.createElement('canvas');
var canvas = canvasElement.getContext("2d");

document.getElementsByTagName('body')[0].appendChild(canvasElement);

function drawLine(begin, end, color) {
    canvas.beginPath();
    canvas.moveTo(begin.x, begin.y);
    canvas.lineTo(end.x, end.y);
    canvas.lineWidth = 4;
    canvas.strokeStyle = color;
    canvas.stroke();
}

function tick() {
    if(!isMovieScanning){return;}
    if (video.readyState === video.HAVE_ENOUGH_DATA) {
        canvasElement.hidden = false;
        canvasElement.width  = video.videoWidth;
        canvasElement.height = video.videoHeight;
        getCode(video);
    }
    requestAnimationFrame(tick);
}

function getCode(src){

    canvas.drawImage(src, 0, 0, canvasElement.width, canvasElement.height);
    var imageData = canvas.getImageData(0, 0, canvasElement.width, canvasElement.height);
    var code = jsQR(imageData.data, imageData.width, imageData.height, {inversionAttempts: "dontInvert"});

    if (code) {
        stopVideo();
        drawLine(code.location.topLeftCorner        , code.location.topRightCorner      ,"#FF3B58");
        drawLine(code.location.topRightCorner       , code.location.bottomRightCorner   ,"#FF3B58");
        drawLine(code.location.bottomRightCorner    , code.location.bottomLeftCorner    ,"#FF3B58");
        drawLine(code.location.bottomLeftCorner     , code.location.topLeftCorner       ,"#FF3B58");
        parseData(code);
    }
}

function startVideo(){

    isMovieScanning = true;
    navigator.mediaDevices.getUserMedia({
        video: {
            facingMode: "environment"
        }
    })
    .then(function(stream) {
        video.srcObject = stream;
        window.localStream = stream;
        video.setAttribute("playsinline", true);
        video.play();
        requestAnimationFrame(tick);
    });
}

function stopVideo(){
    isMovieScanning = false;
    if(window.localStream != undefined){
        window.localStream.getTracks().forEach( (track) => {
            track.stop();
        });
    }
}

function clearRect(){
    canvas.clearRect(0, 0, canvasElement.width, canvasElement.height);
}

function parseData(code){
    json = JSON.parse(code.data);
    address = sym.Address.createFromRawAddress(json.data.address.address);
    console.log(address)
}

startVideo();
```

最後の行のstartVideo();を実行するとQRスキャナがブラウザ上で立ち上がります。
お手元のSymbolアドレスのQRコードをかざしてみてください。



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29187/e4dd0d85-ddb2-46d8-948e-76d9bb03088f.png)

はい、取れました。
止めるときはstopVideo();で止まります。


# さいごに

これをウェブサービスとしてビジネスするにはセキュリティ的にいろいろと問題点はあります。
しかし、サーバに載せずにローカルのHTMLファイルで完結してしまうので、ちょっとしたイベントにPCを持ち出して使用する程度であれば、QRコードスキャナはもう誰にでも作れるところまで来ていることを感じていただければ幸いです。