Socket
Socket
Sign inDemoInstall

qr-scanner

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

qr-scanner - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

15

package.json
{
"name": "qr-scanner",
"version": "1.0.0",
"version": "1.1.0",
"description": "A javascript QR scanner library",

@@ -19,4 +19,3 @@ "main": "qr-scanner.min.js",

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "gulp"
"build": "rollup --config"
},

@@ -33,2 +32,5 @@ "repository": {

"javascript",
"lightweight",
"small",
"fast",
"web"

@@ -43,7 +45,8 @@ ],

"devDependencies": {
"@ampproject/rollup-plugin-closure-compiler": "^0.8.5",
"google-closure-compiler": "^20171112.0.0",
"gulp": "^4.0.0",
"gulp-concat": "^2.6.1",
"gulp-sourcemaps": "^2.6.1"
"jsqr-es6": "^1.2.0-1",
"rollup": "^1.1.2",
"rollup-plugin-sourcemaps": "^0.4.2"
}
}

27

qr-scanner.min.js

@@ -1,17 +0,12 @@

'use strict';export default class QrScanner{static hasCamera(){return navigator.mediaDevices.enumerateDevices().then((devices)=>devices.some((device)=>device.kind==="videoinput")).catch(()=>false)}constructor(video,onDecode,canvasSize=QrScanner.DEFAULT_CANVAS_SIZE){this.$video=video;this.$canvas=document.createElement("canvas");this._onDecode=onDecode;this._active=false;this._paused=false;this.$canvas.width=canvasSize;this.$canvas.height=canvasSize;this._sourceRect={x:0,y:0,width:canvasSize,height:canvasSize};
this._onCanPlay=this._onCanPlay.bind(this);this._onPlay=this._onPlay.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);this.$video.addEventListener("canplay",this._onCanPlay);this.$video.addEventListener("play",this._onPlay);document.addEventListener("visibilitychange",this._onVisibilityChange);this._qrWorker=new Worker(QrScanner.WORKER_PATH)}destroy(){this.$video.removeEventListener("canplay",this._onCanPlay);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",
this._onVisibilityChange);this.stop();this._qrWorker.postMessage({type:"close"})}start(){if(this._active&&!this._paused)return Promise.resolve();if(window.location.protocol!=="https:")console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=true;this._paused=false;if(document.hidden)return Promise.resolve();clearTimeout(this._offTimeout);this._offTimeout=null;if(this.$video.srcObject){this.$video.play();return Promise.resolve()}let facingMode="environment";
return this._getCameraStream("environment",true).catch(()=>{facingMode="user";return this._getCameraStream()}).then((stream)=>{this.$video.srcObject=stream;this._setVideoMirror(facingMode)}).catch((e)=>{this._active=false;throw e;})}stop(){this.pause();this._active=false}pause(){this._paused=true;if(!this._active)return;this.$video.pause();if(this._offTimeout)return;this._offTimeout=setTimeout(()=>{const track=this.$video.srcObject&&this.$video.srcObject.getTracks()[0];if(!track)return;track.stop();
this.$video.srcObject=null;this._offTimeout=null},300)}static scanImage(imageOrFileOrUrl,sourceRect=null,worker=null,canvas=null,fixedCanvasSize=false,alsoTryWithoutSourceRect=false){const promise=new Promise((resolve,reject)=>{if(!worker){worker=new Worker(QrScanner.WORKER_PATH);worker.postMessage({type:"inversionMode",data:"both"})}let timeout,onMessage,onError;onMessage=(event)=>{if(event.data.type!=="qrResult")return;worker.removeEventListener("message",onMessage);worker.removeEventListener("error",
onError);clearTimeout(timeout);if(event.data.data!==null)resolve(event.data.data);else reject("QR code not found.")};onError=(e)=>{worker.removeEventListener("message",onMessage);worker.removeEventListener("error",onError);clearTimeout(timeout);var errorMessage=!e?"Unknown Error":e.message||e;reject("Scanner error: "+errorMessage)};worker.addEventListener("message",onMessage);worker.addEventListener("error",onError);timeout=setTimeout(()=>onError("timeout"),3E3);QrScanner._loadImage(imageOrFileOrUrl).then((image)=>
{const imageData=QrScanner._getImageData(image,sourceRect,canvas,fixedCanvasSize);worker.postMessage({type:"decode",data:imageData},[imageData.data.buffer])}).catch(reject)});if(sourceRect&&alsoTryWithoutSourceRect)return promise.catch(()=>QrScanner.scanImage(imageOrFileOrUrl,null,worker,canvas,fixedCanvasSize));else return promise}setGrayscaleWeights(red,green,blue){this._qrWorker.postMessage({type:"grayscaleWeights",data:{red,green,blue}})}setInversionMode(inversionMode){this._qrWorker.postMessage({type:"inversionMode",
data:inversionMode})}_onCanPlay(){this._updateSourceRect();this.$video.play()}_onPlay(){this._updateSourceRect();this._scanFrame()}_onVisibilityChange(){if(document.hidden)this.pause();else if(this._active)this.start()}_updateSourceRect(){const smallestDimension=Math.min(this.$video.videoWidth,this.$video.videoHeight);const sourceRectSize=Math.round(2/3*smallestDimension);this._sourceRect.width=this._sourceRect.height=sourceRectSize;this._sourceRect.x=(this.$video.videoWidth-sourceRectSize)/2;this._sourceRect.y=
(this.$video.videoHeight-sourceRectSize)/2}_scanFrame(){if(!this._active||this.$video.paused||this.$video.ended)return false;requestAnimationFrame(()=>{QrScanner.scanImage(this.$video,this._sourceRect,this._qrWorker,this.$canvas,true).then(this._onDecode,(error)=>{if(this._active&&error!=="QR code not found.")console.error(error)}).then(()=>this._scanFrame())})}_getCameraStream(facingMode,exact=false){const constraintsToTry=[{width:{min:1024}},{width:{min:768}},{}];if(facingMode){if(exact)facingMode=
{exact:facingMode};constraintsToTry.forEach((constraint)=>constraint.facingMode=facingMode)}return this._getMatchingCameraStream(constraintsToTry)}_getMatchingCameraStream(constraintsToTry){if(constraintsToTry.length===0)return Promise.reject("Camera not found.");return navigator.mediaDevices.getUserMedia({video:constraintsToTry.shift()}).catch(()=>this._getMatchingCameraStream(constraintsToTry))}_setVideoMirror(facingMode){const scaleFactor=facingMode==="user"?-1:1;this.$video.style.transform="scaleX("+
scaleFactor+")"}static _getImageData(image,sourceRect=null,canvas=null,fixedCanvasSize=false){canvas=canvas||document.createElement("canvas");const sourceRectX=sourceRect&&sourceRect.x?sourceRect.x:0;const sourceRectY=sourceRect&&sourceRect.y?sourceRect.y:0;const sourceRectWidth=sourceRect&&sourceRect.width?sourceRect.width:image.width||image.videoWidth;const sourceRectHeight=sourceRect&&sourceRect.height?sourceRect.height:image.height||image.videoHeight;if(!fixedCanvasSize&&(canvas.width!==sourceRectWidth||
canvas.height!==sourceRectHeight)){canvas.width=sourceRectWidth;canvas.height=sourceRectHeight}const context=canvas.getContext("2d",{alpha:false});context.imageSmoothingEnabled=false;context.drawImage(image,sourceRectX,sourceRectY,sourceRectWidth,sourceRectHeight,0,0,canvas.width,canvas.height);return context.getImageData(0,0,canvas.width,canvas.height)}static _loadImage(imageOrFileOrUrl){if(imageOrFileOrUrl instanceof HTMLCanvasElement||imageOrFileOrUrl instanceof HTMLVideoElement||window.ImageBitmap&&
imageOrFileOrUrl instanceof window.ImageBitmap||window.OffscreenCanvas&&imageOrFileOrUrl instanceof window.OffscreenCanvas)return Promise.resolve(imageOrFileOrUrl);else if(imageOrFileOrUrl instanceof Image)return QrScanner._awaitImageLoad(imageOrFileOrUrl).then(()=>imageOrFileOrUrl);else if(imageOrFileOrUrl instanceof File||imageOrFileOrUrl instanceof URL||typeof imageOrFileOrUrl==="string"){const image=new Image;if(imageOrFileOrUrl instanceof File)image.src=URL.createObjectURL(imageOrFileOrUrl);
else image.src=imageOrFileOrUrl;return QrScanner._awaitImageLoad(image).then(()=>{if(imageOrFileOrUrl instanceof File)URL.revokeObjectURL(image.src);return image})}else return Promise.reject("Unsupported image type.")}static _awaitImageLoad(image){return new Promise((resolve,reject)=>{if(image.complete&&image.naturalWidth!==0)resolve();else{let onLoad,onError;onLoad=()=>{image.removeEventListener("load",onLoad);image.removeEventListener("error",onError);resolve()};onError=()=>{image.removeEventListener("load",
onLoad);image.removeEventListener("error",onError);reject("Image load error")};image.addEventListener("load",onLoad);image.addEventListener("error",onError)}})}}QrScanner.DEFAULT_CANVAS_SIZE=400;QrScanner.WORKER_PATH="qr-scanner-worker.min.js";
class e{static hasCamera(){return navigator.mediaDevices.enumerateDevices().then((a)=>a.some((a)=>"videoinput"===a.kind)).catch(()=>!1)}constructor(a,c,b=e.DEFAULT_CANVAS_SIZE){this.$video=a;this.$canvas=document.createElement("canvas");this._onDecode=c;this._paused=this._active=!1;this.$canvas.width=b;this.$canvas.height=b;this._sourceRect={x:0,y:0,width:b,height:b};this._onCanPlay=this._onCanPlay.bind(this);this._onPlay=this._onPlay.bind(this);this._onVisibilityChange=this._onVisibilityChange.bind(this);
this.$video.addEventListener("canplay",this._onCanPlay);this.$video.addEventListener("play",this._onPlay);document.addEventListener("visibilitychange",this._onVisibilityChange);this._qrWorker=new Worker(e.WORKER_PATH)}destroy(){this.$video.removeEventListener("canplay",this._onCanPlay);this.$video.removeEventListener("play",this._onPlay);document.removeEventListener("visibilitychange",this._onVisibilityChange);this.stop();this._qrWorker.postMessage({type:"close"})}start(){if(this._active&&!this._paused)return Promise.resolve();
"https:"!==window.location.protocol&&console.warn("The camera stream is only accessible if the page is transferred via https.");this._active=!0;this._paused=!1;if(document.hidden)return Promise.resolve();clearTimeout(this._offTimeout);this._offTimeout=null;if(this.$video.srcObject)return this.$video.play(),Promise.resolve();let a="environment";return this._getCameraStream("environment",!0).catch(()=>{a="user";return this._getCameraStream()}).then((c)=>{this.$video.srcObject=c;this._setVideoMirror(a)}).catch((a)=>
{this._active=!1;throw a;})}stop(){this.pause();this._active=!1}pause(){this._paused=!0;this._active&&(this.$video.pause(),this._offTimeout||(this._offTimeout=setTimeout(()=>{let a=this.$video.srcObject&&this.$video.srcObject.getTracks()[0];a&&(a.stop(),this._offTimeout=this.$video.srcObject=null)},300)))}static scanImage(a,c=null,b=null,d=null,f=!1,g=!1){let h=!1,l=new Promise((l,g)=>{b||(b=new Worker(e.WORKER_PATH),h=!0,b.postMessage({type:"inversionMode",data:"both"}));let n,m,k;m=(a)=>{"qrResult"===
a.data.type&&(b.removeEventListener("message",m),b.removeEventListener("error",k),clearTimeout(n),null!==a.data.data?l(a.data.data):g("QR code not found."))};k=(a)=>{b.removeEventListener("message",m);b.removeEventListener("error",k);clearTimeout(n);g("Scanner error: "+(a?a.message||a:"Unknown Error"))};b.addEventListener("message",m);b.addEventListener("error",k);n=setTimeout(()=>k("timeout"),3E3);e._loadImage(a).then((a)=>{a=e._getImageData(a,c,d,f);b.postMessage({type:"decode",data:a},[a.data.buffer])}).catch(k)});
c&&g&&(l=l.catch(()=>e.scanImage(a,null,b,d,f)));return l=l.finally(()=>{h&&b.postMessage({type:"close"})})}setGrayscaleWeights(a,c,b,d=!0){this._qrWorker.postMessage({type:"grayscaleWeights",data:{red:a,green:c,blue:b,useIntegerApproximation:d}})}setInversionMode(a){this._qrWorker.postMessage({type:"inversionMode",data:a})}_onCanPlay(){this._updateSourceRect();this.$video.play()}_onPlay(){this._updateSourceRect();this._scanFrame()}_onVisibilityChange(){document.hidden?this.pause():this._active&&
this.start()}_updateSourceRect(){let a=Math.round(2/3*Math.min(this.$video.videoWidth,this.$video.videoHeight));this._sourceRect.width=this._sourceRect.height=a;this._sourceRect.x=(this.$video.videoWidth-a)/2;this._sourceRect.y=(this.$video.videoHeight-a)/2}_scanFrame(){if(!this._active||this.$video.paused||this.$video.ended)return!1;requestAnimationFrame(()=>{e.scanImage(this.$video,this._sourceRect,this._qrWorker,this.$canvas,!0).then(this._onDecode,(a)=>{this._active&&"QR code not found."!==a&&
console.error(a)}).then(()=>this._scanFrame())})}_getCameraStream(a,c=!1){let b=[{width:{min:1024}},{width:{min:768}},{}];a&&(c&&(a={exact:a}),b.forEach((b)=>b.facingMode=a));return this._getMatchingCameraStream(b)}_getMatchingCameraStream(a){return 0===a.length?Promise.reject("Camera not found."):navigator.mediaDevices.getUserMedia({video:a.shift()}).catch(()=>this._getMatchingCameraStream(a))}_setVideoMirror(a){this.$video.style.transform="scaleX("+("user"===a?-1:1)+")"}static _getImageData(a,c=
null,b=null,d=!1){b=b||document.createElement("canvas");let f=c&&c.x?c.x:0,g=c&&c.y?c.y:0,h=c&&c.width?c.width:a.width||a.videoWidth;c=c&&c.height?c.height:a.height||a.videoHeight;d||b.width===h&&b.height===c||(b.width=h,b.height=c);d=b.getContext("2d",{alpha:!1});d.imageSmoothingEnabled=!1;d.drawImage(a,f,g,h,c,0,0,b.width,b.height);return d.getImageData(0,0,b.width,b.height)}static _loadImage(a){if(a instanceof HTMLCanvasElement||a instanceof HTMLVideoElement||window.ImageBitmap&&a instanceof window.ImageBitmap||
window.OffscreenCanvas&&a instanceof window.OffscreenCanvas)return Promise.resolve(a);if(a instanceof Image)return e._awaitImageLoad(a).then(()=>a);if(a instanceof File||a instanceof URL||"string"===typeof a){let c=new Image;c.src=a instanceof File?URL.createObjectURL(a):a;return e._awaitImageLoad(c).then(()=>{a instanceof File&&URL.revokeObjectURL(c.src);return c})}return Promise.reject("Unsupported image type.")}static _awaitImageLoad(a){return new Promise((c,b)=>{if(a.complete&&0!==a.naturalWidth)c();
else{let d,f;d=()=>{a.removeEventListener("load",d);a.removeEventListener("error",f);c()};f=()=>{a.removeEventListener("load",d);a.removeEventListener("error",f);b("Image load error")};a.addEventListener("load",d);a.addEventListener("error",f)}})}}e.DEFAULT_CANVAS_SIZE=400;e.WORKER_PATH="qr-scanner-worker.min.js";export default e;
//# sourceMappingURL=qr-scanner.min.js.map
# QR Scanner
Javascript QR Code Scanner based on [Lazar Lazslo's javascript port](https://github.com/LazarSoft/jsqrcode) of [Google's ZXing library](https://github.com/zxing/zxing).
Javascript QR Code Scanner based on [Cosmo Wolfe's javascript port](https://github.com/cozmo/jsqr) of [Google's ZXing library](https://github.com/zxing/zxing).
In this library, several improvements have been applied over the original port:
<!--
- Lightweight: ~33.7 kB (~12 kB gzipped) minified with Google's closure compiler.
- Improved binarizer which makes it more tolerant to shades and reflections on the screen.
-->
- Improved performance and reduced memory footprint.
- Runs in a WebWorker which keeps the main / UI thread responsive.
- Smaller file size.
- Can be configured for better performance on colored QR codes.
- Runs in a WebWorker which keeps the main / UI thread responsive.
- Works on higher resolution pictures by default.
According to [our benchmarking](https://github.com/danimoh/qr-scanner-benchmark) this project's scanner engine's detection rate is about 2-3 times (and up to 8 times) as high as the one of the most popular javascript QR scanner library [LazarSoft/jsqrcode](https://github.com/LazarSoft/jsqrcode).
The library supports scanning a continuous video stream from a web cam as well as scanning of single images.
The development of this library is sponsored by [nimiq](https://www.nimiq.com), the world's first browser based blockchain.
The development of this library is sponsored by [nimiq](https://www.nimiq.com), world's first browser based blockchain.
[<img src="https://ucb689f1ef4767d4abfb0925e185.previews.dropboxusercontent.com/p/thumb/AAVEuJzxQiFQdRZzaAqyBe7DbR9bX8SSncfAYCBCf4p5ryvIoabV0kBBDE2QQU1xqiZNQsl3JH4mm6K5hOY77dLpx5gsTU5FMsCEYqJiXb-FZg68EjOgMWR5OW0ux2AbUuGqQHebrYg0jwUbaeZt9R8IAKWMIBF99TSdAXTwakC0rnk6KamIGaqbVio80xvAcY1vOeZctnNnjW4nYhUIjYyCsDPhgEbPhBcrVVLJhqoygm9CUgFbXBcDLAdmgLKQSTjeDyR553GV-lqLm0b1Hxw9/p.png?size_mode=5" alt="nimiq.com" width="250">](https://nimiq.com)
[<img src="https://nimiq.github.io/qr-scanner/nimiq_logo_rgb_horizontal.svg" alt="nimiq.com" width="250">](https://nimiq.com)

@@ -27,3 +31,3 @@

```bash
npm install --safe qr-scanner
npm install --save qr-scanner
```

@@ -58,3 +62,3 @@ To install via yarn:

If you're using webpack to bundle your project, the file loader might be interesting for you, to automatically copy the worker into your build:
If you're using webpack to bundle your project, the file loader might be interesting for you to automatically copy the worker into your build:
```js

@@ -114,5 +118,5 @@ import QrScannerWorkerPath from '!!file-loader!./node_modules/qr-scanner/qr-scanner-worker.min.js';

```js
qrScanner.setGrayscaleWeights(red, green, blue);
qrScanner.setGrayscaleWeights(red, green, blue, useIntegerApproximation = true);
```
Where `red`, `green` and `blue` must sum up to 256.
Where `red`, `green` and `blue` should sum up to 256 if `useIntegerApproximation === true` and `1` otherwise. By default, [these](https://en.wikipedia.org/wiki/YUV#Full_swing_for_BT.601) values are used.

@@ -130,3 +134,3 @@ ### Clean Up

The project is prebuild in qr-scanner.min.js in combination with qr-scanner-worker.min.js. Building yourself is only necessary if you want to change the code in
the /src folder. NodeJs and Java are required for building.
the /src folder. NodeJs is required for building.

@@ -143,19 +147,1 @@ Install required build packages:

## Debug Mode
To enable debug mode:
```js
qrScanner._qrWorker.postMessage({
type: 'setDebug',
data: true
});
```
To handle the debug image:
```js
qrScanner._qrWorker.addEventListener('message', event => {
if (event.data.type === 'debugImage') {
canvasContext.putImageData(event.data.data, 0, 0);
}
});
```

@@ -116,5 +116,7 @@ export default class QrScanner {

alsoTryWithoutSourceRect=false) {
const promise = new Promise((resolve, reject) => {
let createdNewWorker = false;
let promise = new Promise((resolve, reject) => {
if (!worker) {
worker = new Worker(QrScanner.WORKER_PATH);
createdNewWorker = true;
worker.postMessage({ type: 'inversionMode', data: 'both' }); // scan inverted color qr codes too

@@ -140,3 +142,3 @@ }

clearTimeout(timeout);
var errorMessage = !e ? 'Unknown Error' : (e.message || e);
const errorMessage = !e ? 'Unknown Error' : (e.message || e);
reject('Scanner error: ' + errorMessage);

@@ -153,16 +155,23 @@ };

}, [imageData.data.buffer]);
}).catch(reject);
}).catch(onError);
});
if (sourceRect && alsoTryWithoutSourceRect) {
return promise.catch(() => QrScanner.scanImage(imageOrFileOrUrl, null, worker, canvas, fixedCanvasSize));
} else {
return promise;
promise = promise.catch(() => QrScanner.scanImage(imageOrFileOrUrl, null, worker, canvas, fixedCanvasSize));
}
promise = promise.finally(() => {
if (!createdNewWorker) return;
worker.postMessage({
type: 'close'
});
});
return promise;
}
setGrayscaleWeights(red, green, blue) {
setGrayscaleWeights(red, green, blue, useIntegerApproximation = true) {
this._qrWorker.postMessage({
type: 'grayscaleWeights',
data: { red, green, blue }
data: { red, green, blue, useIntegerApproximation }
});

@@ -249,3 +258,2 @@ }

/* async */
static _getImageData(image, sourceRect=null, canvas=null, fixedCanvasSize=false) {

@@ -252,0 +260,0 @@ canvas = canvas || document.createElement('canvas');

@@ -17,5 +17,5 @@ // Type definitions for qr-scanner

pause(): void;
setGrayscaleWeights(red: number, green: number, blue: number): void;
setInversionMode(inverionMode: QrScanner.InversionMode): void;
scanImage(
setGrayscaleWeights(red: number, green: number, blue: number, useIntegerApproximation?: boolean): void;
setInversionMode(inversionMode: QrScanner.InversionMode): void;
static scanImage(
imageOrFileOrUrl: HTMLCanvasElement | HTMLVideoElement | ImageBitmap | HTMLImageElement | File | URL | String,

@@ -22,0 +22,0 @@ sourceRect?: QrScanner.SourceRect | null,

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc