I'm having an issue with ZXing-js. Its returning a ChecksumException no matter what QR Code I put into it. So its detecting the QRCode but throws an Exception. The following is my vuejs 2.0 code. Please help.
Almost all if this code works. Its just the reading of the QR code part that doesn't
import { BarcodeFormat, DecodeHintType, NotFoundException, ChecksumException, FormatException } from '@zxing/library';
const ZXing = require('@zxing/browser');
Vue.component('qr_scanner_modal',{
prop: [
'videoSource'
],
data: function ()
{
return {
qr_error: null,
qrcanvas: null,
context: null,
qrvideo: null,
hints: null,
formats: null,
videoSource: {},
qr: null,
selected_source: null,
polling: null,
localMediaStream: null,
scanLineDirect: 'down',
scanlineOffset: 0,
qr_title: "",
visible: false,
focused: true,
qr_result: ""
};
},
mixins: [ focusMixin ],
created: function ()
{
EventBus.$on('trigger-qrcode-scanner', (qrTitle) => this.show(qrTitle));
},
mounted: function ()
{
let self = this;
this.$root.$on('bv::modal::show', () => this.$nextTick(() => this.mountQRReader()));
},
methods: {
mountQRReader: function ()
{
const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX/*, ...*/];
hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(DecodeHintType.TRY_HARDER, true);
hints.set(DecodeHintType.CHARACTER_SET, 'UTF-8');
hints.set(DecodeHintType.ALSO_INVERTED, true);
this.qr = new ZXing.BrowserQRCodeReader(hints);
this.qrcanvas = this.$refs['qrcanvas'];
this.qrcanvas.width = 400;
this.qrcanvas.height = 400;
// this.qrcanvas = this.$refs;
console.log(this.$refs['qrcanvas']);
this.context = this.$refs['qrcanvas'].getContext('2d');
this.qrvideo = this.$refs['qrvideo'];
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices)
{
this.qr_error = "This browser does not support MediaStreamTrack. Try Chrome.";
console.log("enumerateDevices() not supported.");
}
else
{
this.qr_error = null;
}
let self = this;
navigator.mediaDevices
.enumerateDevices()
.then(function (sourceInfos)
{
let videosource = [];
for (var index = 0; index !== sourceInfos.length; index++)
{
var sourceInfo = sourceInfos[index];
if (sourceInfo.kind === 'videoinput')
{
videosource.push({
id: sourceInfo.deviceId,
name: sourceInfo.label || 'Camera ' + index
});
console.log(sourceInfo);
console.log(videosource);
}
}
self.videoSource = videosource;
})
.catch(function (err)
{
console.log(err.name + ": " + err.message);
});
},
show: function (qrTitle)
{
console.log("Show modal called.");
this.qr_title = qrTitle + " - QR / Magstripe Reader";
this.$bvModal.show('qr_code_scanner');
},
dismiss: function()
{
this.stopScan();
this.$bvModal.hide('qr_code_scanner');
},
selectSource: function (source)
{
this.selected_source = source;
let constraints = {
audio: false,
video: {
facingMode: "environment",
sourceId: source
}
};
navigator.getUserMedia(constraints, this.startScan, this.scanError);
},
read: function (value)
{
console.log('read callback called.');
console.log(value);
if (value !== null && value !== undefined)
{
this.qr_result = value.text;
EventBus.$emit('qr_code_returned', value.text);
this.stopScan();
return;
}
},
startScan: function (stream)
{
this.qrvideo.srcObject = stream;
this.localMediaStream = stream;
this.qrvideo.play();
this.polling = setInterval(this.scan, 400);
},
scanError: function (err)
{
if (err)
{
this.qr_error = err;
}
},
stopScan: function ()
{
clearInterval(this.polling);
if (this.localMediaStream)
{
let track = this.localMediaStream.getVideoTracks();
track[0].stop();
}
},
transposeRect: function (width, height)
{
const rectWidth = width * 0.8;
const rectHeight = height * 0.8;
const xPos = (width - rectWidth) / 2;
const yPos = (height - rectHeight) / 2;
this.context.beginPath();
this.context.strokeStyle = 'red';
this.context.lineWidth = '3';
this.context.rect( xPos,
yPos,
rectWidth,
rectHeight);
this.context.stroke();
this.drawScanLine(yPos,
xPos,
xPos + rectWidth,
yPos + rectHeight);
},
drawScanLine: function (top, left, right, bottom)
{
if (this.scanLineDirect === 'down')
{
this.scanlineOffset = this.scanlineOffset + 4;
}
if (this.scanLineDirect === 'up')
{
this.scanlineOffset = this.scanlineOffset - 4;
}
if (top + this.scanlineOffset > bottom)
{
this.scanLineDirect = 'up';
this.scanlineOffset = this.scanlineOffset - 4;
}
if (top + this.scanlineOffset < top)
{
this.scanLineDirect = 'down';
this.scanlineOffset = this.scanlineOffset + 4;
}
this.context.beginPath();
this.context.strokeStyle = 'red';
this.context.lineWidth = '3';
this.context.moveTo(left, top + this.scanlineOffset);
this.context.lineTo(right, top + this.scanlineOffset);
this.context.closePath();
this.context.stroke();
},
scan: async function ()
{
try
{
if (this.localMediaStream)
{
console.log("Scanning Video Feed.");
const width = this.qrcanvas.getAttribute('width');
const height = this.qrcanvas.getAttribute('height');
this.context.drawImage(this.qrvideo, 0, 0, width, height);
console.log("width: " + width);
console.log("height: " + height);
const code = await this.qr.decodeFromCanvas(this.qrcanvas);
// const code = await this.qr.decode(this.qrcanvas);
this.read(code);
this.transposeRect(width, height);
}
}
catch(err)
{
if (err instanceof NotFoundException) {
console.log('No QR code found.')
}
if (err instanceof ChecksumException) {
console.log('A code was found, but it\'s read value was not valid.')
}
if (err instanceof FormatException) {
console.log('A code was found, but it was in a invalid format.')
}
}
}
},
template: `
<b-modal id="qr_code_scanner"
v-bind:title="qr_title"
v-bind:videoSource='videoSource'
hide-footer >
<div class="alert alert-danger" v-show="qr_error != null">
{{qr_error}}
</div>
<div>
<a href='#' v-for="source in videoSource" v-on:click='selectSource(source.id)' class='btn btn-primary'>@{{source.name}}</a>
</div>
<div class="large-centered col-lg-12 col-md-12 col-sm-12" style="overflow: hidden;">
<input type="text" ref="qr_result" name='qr_result' v-focus="focused" v-model='qr_result' class="form-control" />
<video id="qrvideo" ref="qrvideo" controls="false" style="display: none;"></video>
<canvas id="qrcanvas" ref='qrcanvas' style="overflow: hidden;" width="400" height="400"></canvas>
</div>
<div class="modal-footer">
<a href='#' v-on:click='dismiss()' class='btn btn-primary'>Cancel</a>
</div>
</b-modal>
`
});
I'm expecting it to return a QR Code.