16 Commits
Author SHA1 Message Date
yugasun ee7b3ea8e8 Updates 2024-07-17 14:12:30 +08:00
yugasun e665a30b60 Updates 2022-11-23 11:56:52 +08:00
yugasun b9b09029ec Updates 2022-10-11 14:05:09 +08:00
yugasun a8f2f06f4f Updates 2022-05-29 11:24:22 +08:00
yugasun 564c55743a Updates 2022-05-29 11:21:01 +08:00
yugasun f80b934b71 Updates 2022-05-29 11:17:44 +08:00
yugasun 58c9419c2c Updates 2022-05-29 11:11:02 +08:00
yugasun 27e88436e3 Updates 2022-05-29 11:08:07 +08:00
yugasun ede323bb2a Updates 2022-05-29 11:05:22 +08:00
yugasun bf8c373a47 Updates 2021-05-19 10:41:58 +08:00
yugasun ebd34c84f6 Updates 2021-05-19 10:40:17 +08:00
yugasun 2cede9967c Updates 2021-05-12 20:52:18 +08:00
yugasun 95ae10bd90 Updates 2021-05-12 20:51:33 +08:00
yugasun f84b71c352 Updates 2020-01-16 12:38:30 +08:00
yugasun 02a4c715f4 Updates 2019-11-20 12:58:42 +08:00
yugasun 0cab0e9e0c Updates 2019-01-15 14:05:36 +08:00
39 changed files with 195 additions and 7555 deletions
-22
View File
@@ -1,22 +0,0 @@
{
"presets": [
["env",
{
"targets": {
"browsers": "last 2 versions, > 1%, ie >= 11",
"node": "8.0"
},
"modules": false,
"loose": false
}],
"stage-2"
],
"plugins": [
["transform-runtime", {
"helpers": false,
"polyfill": false,
"regenerator": false,
"moduleName": "babel-runtime"
}]
]
}
-12
View File
@@ -1,12 +0,0 @@
root = true
[{*.js,*.css,*.html}]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
insert_final_newline = true
[{package.json,.*rc,*.yml}]
indent_style = space
indent_size = 2
-1
View File
@@ -1 +0,0 @@
test
-45
View File
@@ -1,45 +0,0 @@
module.exports = {
root: true,
parserOptions: {
sourceType: 'module',
},
env: {
browser: true,
es6: true,
node: true,
},
extends: ['airbnb-base'],
rules: {
'no-shadow': [
'error',
{
allow: ['state'],
},
],
// 'import/extensions': 'off',
'import/extensions': [
'error',
'always',
{
js: 'never',
},
],
'import/no-unresolved': 'off',
'no-param-reassign': 'off',
'consistent-return': 'off',
'global-require': 'off',
'import/no-dynamic-require': 'off',
'import/no-extraneous-dependencies': 'off',
// 4 行空格缩进
indent: ['error', 4, { SwitchCase: 1 }],
'max-len': ['error', { code: 150 }],
'operator-linebreak': 0,
},
};
View File
-3
View File
@@ -1,3 +0,0 @@
node_modules
dist
.DS_Store
-11
View File
@@ -1,11 +0,0 @@
node_modules
config
demo
src
test
.babelrc
.editorconfig
.travis.yml
CHANGELOG.md
package-lock.json
TODO.md
-3
View File
@@ -1,3 +0,0 @@
language: node_js
node_js:
- "8"
-1
View File
@@ -1 +0,0 @@
# Change Log
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 Yuga Sun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-128
View File
@@ -1,128 +0,0 @@
# [qrcode-decoder](https://github.com/yugasun/qrcode-decoder)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/yugasun/qrcode-decoder/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/yugasun/qrcode-decoder.svg?branch=master)](https://travis-ci.org/yugasun/qrcode-decoder)
[![NPM downloads](http://img.shields.io/npm/dm/qrcode-decoder.svg?style=flat-square)](http://www.npmtrends.com/qrcode-decoder)
[简体中文](./README.zh-CN.md) | English
A tool for decoding qrcode.
## Directory
```
.
├── demo code demo
├── dist build output
├── doc docs
├── src source code
├── test unit test
├── CHANGELOG.md change log
└── TODO.md todo list
```
## Guide
Use `npm` to install.
```bash
$ npm install --save qrcode-decoder
```
Using in webpack:
```js
import QrcodeDecoder from 'qrcode-decoder';
```
Using in browser:
```html
<script src="node_modules/qrcode-decoder/dist/index.aio.js"></script>
```
## Demo
### QrcodeDecoder()
User `new` to create a decoder object.
```javascript
var qr = new QrcodeDecoder();
```
#### decodeFromImage(img, options)
Decodes an image from url or an `<img>` element with a `src` attribute set.
```javascript
qr.decodeFromImage(img).then((res) => {
console.log(res);
});
```
[Demo](./demo/image.html)
#### decodeFromVideo(videoElem, options)
Decodes directly from a video with a well specified `src` attribute
```javascript
qr.decodeFromVideo(videoElement).then((res) => {
console.log(res);
});
```
[Demo](./demo/video.html)
#### decodeFromCamera(videoElem, options)
Decodes from a videoElement.
```javascript
qr.decodeFromCamera(videoElem).then((res) => {
console.log(res);
});
```
[Demo](./demo/camera.html)
#### stop()
Stops the current `qr` from searching for a QRCode.
## Develop
Install dependencies:
```bash
$ npm install
```
Build code:
```bash
$ npm run build
```
Run unit test:
```bash
$ npm test
```
Modify version in `package.json`, run `release` script:
```bash
$ npm run release
```
Publish
```bash
$ npm publish
```
## License
[MIT](./LICENSE)
-128
View File
@@ -1,128 +0,0 @@
# [qrcode-decoder](https://github.com/yugasun/qrcode-decoder)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/yugasun/qrcode-decoder/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/yugasun/qrcode-decoder.svg?branch=master)](https://travis-ci.org/yugasun/qrcode-decoder)
[![NPM downloads](http://img.shields.io/npm/dm/qrcode-decoder.svg?style=flat-square)](http://www.npmtrends.com/qrcode-decoder)
简体中文 | [English](./README.md)
二维码解析工具。
## 目录介绍
```
.
├── demo 使用demo
├── dist 编译产出代码
├── doc 项目文档
├── src 源代码目录
├── test 单元测试
├── CHANGELOG.md 变更日志
└── TODO.md 计划功能
```
## 使用者指南
通过 npm 下载安装代码
```bash
$ npm install --save qrcode-decoder
```
如果你是 webpack 等环境
```js
import QrcodeDecoder from 'qrcode-decoder';
```
如果你是浏览器环境
```html
<script src="node_modules/qrcode-decoder/dist/index.aio.js"></script>
```
## 示例
### QrcodeDecoder()
通过 `new` 关键字生成处理对象。
```javascript
var qr = new QrcodeDecoder();
```
#### decodeFromImage(img, options)
解析页面中的图片二维码。
```javascript
qr.decodeFromImage(img).then((res) => {
console.log(res);
});
```
[Demo](./demo/image.html)
#### decodeFromVideo(videoElem, options)
解析页面中的视频中的二维码。
```javascript
qr.decodeFromVideo(videoElement).then((res) => {
console.log(res);
});
```
[Demo](./demo/video.html)
#### decodeFromCamera(videoElem, options)
通过获取摄像头视频来扫描解析二维码。
```javascript
qr.decodeFromCamera(videoElem).then((res) => {
console.log(res);
});
```
[Demo](./demo/camera.html)
#### stop()
停止当前视频捕获。
## 开发
首次运行需要先安装依赖
```bash
$ npm install
```
一键打包生成生产代码
```bash
$ npm run build
```
运行单元测试,浏览器环境需要手动测试,位于`test/browser`
```bash
$ npm test
```
修改 package.json 中的版本号,修改 README.md 中的版本号,修改 CHANGELOG.md,然后发布新版
```bash
$ npm run release
```
将新版本发布到 npm
```bash
$ npm publish
```
## License
[MIT](./LICENSE)
-5
View File
@@ -1,5 +0,0 @@
# TODO
Rewrite unit test.
- [] Rewrite unit test.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

+54
View File
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>QrcodeDecoder - Camera</title>
</head>
<body>
<button id="start">Start</button> <button id="stop">Stop</button><br />
<span id="result">Click start to scan qrcode.</span><br />
<hr />
<video id="video" autoplay></video>
<script src="./lib/vconsole.min.js"></script>
<script src="./lib/index.min.js"></script>
<script type="text/javascript">
var vConsole = new VConsole();
console.log('Hello world');
function main() {
var qr = new QrcodeDecoder.default();
var video = document.querySelector('#video');
var start = document.querySelector('#start');
var stop = document.querySelector('#stop');
var result = document.querySelector('#result');
async function startScan() {
if (!qr.isCanvasSupported()) {
alert("Your browser doesn't match the required specs.");
throw new Error('Canvas and getUserMedia are required');
}
let code = await qr.decodeFromCamera(video,
// you can customize your camera size like below
// {
// width: 400,
// height: 400,
// }
);
console.log('code', code);
result.innerText = 'Result: ' + code.data;
}
start.onclick = startScan;
stop.onclick = function () {
qr.stop();
};
}
main();
</script>
</body>
</html>
-52
View File
@@ -1,52 +0,0 @@
// rollup.config.js
import babel from 'rollup-plugin-babel';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import { uglify } from 'rollup-plugin-uglify';
import common from './rollup';
const prod = process.env.NODE_ENV;
export default {
input: 'src/index.js',
output: {
file: prod ? 'dist/index.aio.min.js' : 'dist/index.aio.js',
format: 'umd',
// 如果不同时使用 export 与 export default 可打开legacy
// legacy: true,
// name: common.name,
name: 'QrcodeDecoder',
banner: common.banner,
},
plugins: [
nodeResolve({
main: true,
}),
commonjs({
include: 'node_modules/**',
}),
babel({
runtimeHelpers: true,
exclude: 'node_modules/**',
}),
prod &&
uglify({
compress: {
drop_debugger: true,
drop_console: true,
},
output: {
comments: (node, comment) => {
if (comment.type === 'comment2') {
// multiline comment
return /@preserve|@license|@cc_on/i.test(
comment.value,
);
}
return false;
},
},
}),
],
};
-7
View File
@@ -1,7 +0,0 @@
import config from './rollup.config';
// ES output
config.output.format = 'es';
config.output.file = 'dist/index.esm.js';
export default config;
-21
View File
@@ -1,21 +0,0 @@
// rollup.config.js
import babel from 'rollup-plugin-babel';
import common from './rollup';
export default {
input: 'src/index.js',
output: {
file: 'dist/index.js',
format: 'cjs',
// 如果不同时使用 export 与 export default 可打开legacy
// legacy: true,
banner: common.banner,
},
plugins: [
babel({
runtimeHelpers: true,
exclude: 'node_modules/**',
}),
],
};
-18
View File
@@ -1,18 +0,0 @@
const pkg = require('../package.json');
// 兼容 qrcode-decoder 和 @yugasun/qrcode-decoder
const name = pkg.name.split('/').pop();
const { version } = pkg;
const banner = `/* @preserve
* qrcode-decoder ${version} (https://github.com/yugasun/qrcode-decoder)
* API https://github.com/yugasun/qrcode-decoder/blob/master/doc/api.md
* Copyright 2017-${new Date().getFullYear()} yugasun. All Rights Reserved
* Licensed under MIT (https://github.com/yugasun/qrcode-decoder/blob/master/LICENSE)
*/
`;
export default {
name,
banner,
};
-39
View File
@@ -1,39 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>QrcodeDecoder - Camera</title>
</head>
<body>
<button id="start">Start</button> <button id="stop">Stop</button><br />
<span id="result">Click start to scan qrcode.</span><br />
<hr />
<video id="video" autoplay></video>
<script src="./index.aio.min.js"></script>
<script type="text/javascript">
function main() {
var qr = new QrcodeDecoder();
var video = document.querySelector('#video');
var start = document.querySelector('#start');
var stop = document.querySelector('#stop');
var result = document.querySelector('#result');
async function startScan() {
if (!qr.isCanvasSupported()) {
alert("Your browser doesn't match the required specs.");
throw new Error('Canvas and getUserMedia are required');
}
let code = await qr.decodeFromCamera(video);
console.log('code', code);
result.innerText = "Result: " + code.data;
}
start.onclick = startScan;
stop.onclick = function() {
qr.stop();
};
}
main();
</script>
</body>
</html>
-52
View File
@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>QrcodeDecoder - Image</title>
</head>
<body>
<section>
<h3>Same domain image</h3>
<img src="./assets/qrcode.png" alt="qr code" /><br>
<button id="decode1">Decode!</button><br>
<span id="result1"></span><br>
</section>
<hr/>
<section>
<h3>Different domain image</h3>
<button id="decode2">Decode!</button><br>
<span id="result2"></span><br>
</section>
<script src="./index.aio.min.js"></script>
<script type="module">
function main() {
var qr = new QrcodeDecoder();
var btn1 = document.querySelector('button#decode1');
var btn2 = document.querySelector('button#decode2');
var result1 = document.querySelector('#result1');
var result2 = document.querySelector('#result2');
var img = document.querySelector('img');
btn1.onclick = async () => {
// you can also decode from image path
// const code = await qr.decodeFromImage('./assets/qrcode.png');
const code = await qr.decodeFromImage(img);
console.log(code);
result1.innerText = code.data;
};
btn2.onclick = async () => {
// you can also decode from image path
// const code = await qr.decodeFromImage('./assets/qrcode.png');
const code = await qr.decodeFromImage('https://yugasun.com/static/wechat.jpg', {
crossOrigin: 'anonymous',
});
console.log(code);
result2.innerText = code.data;
};
}
main();
</script>
</body>
</html>
-7
View File
File diff suppressed because one or more lines are too long
-18
View File
@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>QrcodeDecoder</title>
</head>
<body>
<h1>QrcodeDecoder</h1>
<h2>Examples</h2>
<ul>
<li><a href="image.html">Image</a></li>
<li><a href="video.html">Video</a></li>
<li><a href="camera.html">Camera</a></li>
</ul>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>QrcodeDecoder - Video</title>
</head>
<body>
<button id="start">Start</button> <button id="stop">Stop</button><br />
<span id="result">Click start to scan qrcode.</span><br />
<video src="./assets/qrcode-video.mp4"></video>
<script src="./index.aio.min.js"></script>
<script type="text/javascript">
function main() {
var video = document.querySelector('video');
var result = document.querySelector('#result');
var start = document.querySelector('#start');
var stop = document.querySelector('#stop');
var qr = new QrcodeDecoder();
start.onclick = startScan;
stop.onclick = function() {
qr.stop();
video.pause();
};
async function startScan() {
video.play();
const code = await qr.decodeFromVideo(video);
console.log('code', code);
result.innerText = 'Result: ' + code.data;
}
}
main();
</script>
</body>
</html>
-49
View File
@@ -1,49 +0,0 @@
# Api
### QrcodeDecoder()
User `new` to create a decoder object.
```javascript
var qr = new QrcodeDecoder();
```
#### decodeFromImage(img, options)
Decodes an image from url or an `<img>` element with a `src` attribute set.
```javascript
qr.decodeFromImage(img).then((res) => {
console.log(res);
});
```
[Demo](./demo/image.html)
#### decodeFromVideo(videoElem, options)
Decodes directly from a video with a well specified `src` attribute
```javascript
qr.decodeFromVideo(videoElement).then((res) => {
console.log(res);
});
```
[Demo](./demo/video.html)
#### decodeFromCamera(videoElem, options)
Decodes from a videoElement.
```javascript
qr.decodeFromCamera(videoElem).then((res) => {
console.log(res);
});
```
[Demo](./demo/camera.html)
#### stop()
Stops the current `qr` from searching for a QRCode.
-49
View File
@@ -1,49 +0,0 @@
# Api
### QrcodeDecoder()
通过 `new` 关键字生成处理对象。
```javascript
var qr = new QrcodeDecoder();
```
#### decodeFromImage(img, options)
解析页面中的图片二维码。
```javascript
qr.decodeFromImage(img).then((res) => {
console.log(res);
});
```
[Demo](./demo/image.html)
#### decodeFromVideo(videoElem, options)
解析页面中的视频中的二维码。
```javascript
qr.decodeFromVideo(videoElement).then((res) => {
console.log(res);
});
```
[Demo](./demo/video.html)
#### decodeFromCamera(videoElem, options)
通过获取摄像头视频来扫描解析二维码。
```javascript
qr.decodeFromCamera(videoElem).then((res) => {
console.log(res);
});
```
[Demo](./demo/camera.html)
#### stop()
停止当前视频捕获。
+66
View File
@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>QrcodeDecoder - Image</title>
</head>
<body>
<section>
<h3>Same domain image</h3>
<img id="img1" src="./assets/qrcode.png" alt="qr code" /><br />
<button id="decode1">Decode!</button><br />
<span id="result1"></span><br />
</section>
<hr />
<section>
<h3>Different domain image</h3>
<input
id="img2"
value="https://yugasun.com/static/wechat.jpg"
style="width: 400px" /><br />
<button id="decode2">Decode!</button><br />
<span id="result2"></span><br />
</section>
<script src="./lib/vconsole.min.js"></script>
<script src="./lib/index.min.js"></script>
<script type="module">
var vConsole = new VConsole();
function main() {
var qr = new QrcodeDecoder.default();
var btn1 = document.querySelector('button#decode1');
var btn2 = document.querySelector('button#decode2');
var result1 = document.querySelector('#result1');
var result2 = document.querySelector('#result2');
var img1 = document.querySelector('#img1');
var img2 = document.querySelector('#img2');
btn1.onclick = async () => {
// you can also decode from image path
// const code = await qr.decodeFromImage('./assets/qrcode.png');
const code = await qr.decodeFromImage(img1);
console.log(code);
result1.innerText = code.data;
};
btn2.onclick = async () => {
// you can also decode from image path
// const code = await qr.decodeFromImage('./assets/qrcode.png');
const code = await qr.decodeFromImage(img2.value, {
crossOrigin: 'anonymous',
});
console.log(code);
result2.innerText = code.data;
};
}
window.onload = () => {
main();
};
</script>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>QrcodeDecoder</title>
</head>
<body>
<h1>QrcodeDecoder</h1>
<h2>Examples</h2>
<ul>
<li><a href="image.html">Image</a></li>
<li><a href="video.html">Video</a></li>
<li><a href="camera.html">Camera</a></li>
</ul>
</body>
</html>
+2
View File
File diff suppressed because one or more lines are too long
+10
View File
File diff suppressed because one or more lines are too long
-59
View File
@@ -1,59 +0,0 @@
{
"name": "qrcode-decoder",
"version": "0.1.2",
"description": "Tool for decoding qrcode",
"main": "dist/index.js",
"jsnext:main": "dist/index.esm.js",
"module": "dist/index.esm.js",
"sideEffects": false,
"scripts": {
"clean": "rimraf ./dist",
"lint": "eslint src",
"build:self": "rollup -c config/rollup.config.js",
"build:esm": "rollup -c config/rollup.config.esm.js",
"build:aio": "rollup -c config/rollup.config.aio.js",
"build:aio.min": "NODE_ENV=production npm run build:aio",
"build": "npm run clean && npm run build:self && npm run build:esm && npm run build:aio && npm run build:aio.min && npm run copy-file",
"copy-file": "cp dist/index.aio.min.js demo/",
"test": "npm run lint && npm run build",
"zuul-test": "zuul --local 8080 --ui mocha-bdd -- test/test.js",
"release": "git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags",
"deploy": "gh-pages -d demo --remote origin"
},
"author": "yugasun",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/yugasun/qrcode-decoder.git"
},
"bugs": {
"url": "https://github.com/yugasun/qrcode-decoder/issues"
},
"devDependencies": {
"babel-core": "6.26.0",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-env": "1.6.1",
"babel-preset-stage-2": "^6.24.1",
"cdkit": "1.1.0",
"es5-shim": "4.5.10",
"eslint": "4.18.2",
"eslint-config-airbnb-base": "^13.1.0",
"eslint-plugin-import": "^2.14.0",
"expect.js": "0.3.1",
"gh-pages": "^2.0.1",
"jsdom": "^13.0.0",
"mocha": "3.5.3",
"mocha-jsdom": "^2.0.0",
"rimraf": "2.6.2",
"rollup": "^0.67.3",
"rollup-plugin-babel": "3.0.3",
"rollup-plugin-commonjs": "8.3.0",
"rollup-plugin-node-resolve": "3.0.3",
"rollup-plugin-uglify": "^6.0.0",
"zuul": "^3.12.0"
},
"dependencies": {
"babel-polyfill": "^6.26.0",
"jsqr": "^1.1.1"
}
}
-376
View File
@@ -1,376 +0,0 @@
import 'babel-polyfill';
import jsQR from 'jsqr';
/* eslint-disable no-underscore-dangle */
class QrcodeDecoder {
/**
* Constructor for QrcodeDecoder
*/
constructor() {
this.timerCapture = null;
this.canvasElem = null;
this.gCtx = null;
this.stream = null;
this.videoElem = null;
this.getUserMediaHandler = null;
this.videoConstraints = { video: true, audio: false };
this.defaultOption = { inversionAttempts: 'attemptBoth' };
}
/**
* Verifies if canvas element is supported.
*/
/* eslint-disable class-methods-use-this */
isCanvasSupported() {
const elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
}
/**
* draw lint
*
* @param {object} begin line begin point
* @param {object} end line end point
* @param {string} color color string
*/
// _drawLine(begin, end, color) {
// this.gCtx.beginPath();
// this.gCtx.moveTo(begin.x, begin.y);
// this.gCtx.lineTo(end.x, end.y);
// this.gCtx.lineWidth = 4;
// this.gCtx.strokeStyle = color;
// this.gCtx.stroke();
// }
/**
* create qrcode marker
*
* @param {object} code jsqr parse code object
*/
// _createQrcodeMark(code) {
// this._drawLine(
// code.location.topLeftCorner,
// code.location.topRightCorner,
// '#FF3B58',
// );
// this._drawLine(
// code.location.topRightCorner,
// code.location.bottomRightCorner,
// '#FF3B58',
// );
// this._drawLine(
// code.location.bottomRightCorner,
// code.location.bottomLeftCorner,
// '#FF3B58',
// );
// this._drawLine(
// code.location.bottomLeftCorner,
// code.location.topLeftCorner,
// '#FF3B58',
// );
// }
_createImageData(target, width, height) {
if (!this.canvasElem) {
this._prepareCanvas(width, height);
}
this.gCtx.clearRect(0, 0, width, height);
this.gCtx.drawImage(target, 0, 0, width, height);
const imageData = this.gCtx.getImageData(
0,
0,
this.canvasElem.width,
this.canvasElem.height,
);
return imageData;
}
/**
* Prepares the canvas element (which will
* receive the image from the camera and provide
* what the algorithm needs for checking for a
* QRCode and then decoding it.)
*
*
* @param {DOMElement} canvasElem the canvas
* element
* @param {number} width The width that
* the canvas element
* should have
* @param {number} height The height that
* the canvas element
* should have
* @return {DOMElement} the canvas
* after the resize if width and height
* provided.
*/
_prepareCanvas(width, height) {
if (!this.canvasElem) {
this.canvasElem = document.createElement('canvas');
this.canvasElem.style.width = `${width}px`;
this.canvasElem.style.height = `${height}px`;
this.canvasElem.width = width;
this.canvasElem.height = height;
}
this.gCtx = this.canvasElem.getContext('2d');
}
/**
* Based on the video dimensions and the canvas
* that was previously generated captures the
* video/image source and then paints into the
* canvas so that the decoder is able to work as
* it expects.
* @param {DOMElement} videoElem <video> dom element
* @param {Object} options options (optional) - Additional options.
* inversionAttempts - (attemptBoth (default), dontInvert, onlyInvert, or invertFirst)
* refer to jsqr options: https://github.com/cozmo/jsQR
*/
async _captureToCanvas(videoElem, options) {
if (this.timerCapture) {
clearTimeout(this.timerCapture);
}
const proms = () => {
const p = new Promise(async (resolve) => {
let code;
if (videoElem.videoWidth && videoElem.videoHeight) {
const imageData = this._createImageData(
videoElem,
videoElem.videoWidth,
videoElem.videoHeight,
);
code = jsQR(
imageData.data,
imageData.width,
imageData.height,
options,
);
if (code) {
resolve(code);
} else {
this.timerCapture = setTimeout(async () => {
code = await this._captureToCanvas(
videoElem,
options,
);
resolve(code);
}, 500);
}
} else {
this.timerCapture = setTimeout(async () => {
code = await this._captureToCanvas(videoElem, options);
resolve(code);
}, 500);
}
});
return p;
};
const result = await proms();
return result;
}
/**
* Prepares the video element for receiving
* camera's input. Releases a stream if there
* was any (resets).
*
* @param {DOMElement} videoElem <video> dom element
* @param {Object} options options (optional) - Additional options.
* inversionAttempts - (attemptBoth (default), dontInvert, onlyInvert, or invertFirst)
* refer to jsqr options: https://github.com/cozmo/jsQR
*/
async decodeFromCamera(videoElem, options = {}) {
const opts = {
...this.defaultOption,
...options,
};
this.stop();
if (!navigator.mediaDevices.getUserMedia) {
throw new Error("Couldn't get video from camera");
}
try {
const stream = await navigator.mediaDevices.getUserMedia(
this.videoConstraints,
);
videoElem.srcObject = stream;
// videoElem.src = window.URL.createObjectURL(stream);
this.videoElem = videoElem;
this.stream = stream;
this.videoDimensions = false;
const code = await this.decodeFromVideo(videoElem, opts);
return code;
} catch (e) {
throw e;
}
}
/**
* Prepares the video element for video file.
*
* @param {DOMElement} videoElem <video> dom element
* @param {Object} options options (optional) - Additional options.
* inversionAttempts - (attemptBoth (default), dontInvert, onlyInvert, or invertFirst)
* refer to jsqr options: https://github.com/cozmo/jsQR
*/
async decodeFromVideo(videoElem, options = {}) {
const opts = {
...this.defaultOption,
...options,
};
try {
this.videoElem = videoElem;
const code = await this._captureToCanvas(videoElem, opts);
return code;
} catch (e) {
throw e;
}
}
/**
* Decodes an image from its src.
* @param {DOMElement} imageElem
* @param {Object} options options (optional) - Additional options.
* inversionAttempts - (attemptBoth (default), dontInvert, onlyInvert, or invertFirst)
* refer to jsqr options: https://github.com/cozmo/jsQR
*/
async decodeFromImage(img, options = {}) {
let imgDom;
const opts = {
...this.defaultOption,
...options,
};
if (+img.nodeType > 0) {
if (!img.src) {
throw new Error('The ImageElement must contain a src');
}
imgDom = img;
} else if (typeof img === 'string') {
imgDom = document.createElement('img');
imgDom.src = img;
if (options.crossOrigin) {
imgDom.crossOrigin = options.crossOrigin;
}
const proms = () => new Promise((resolve) => {
imgDom.onload = () => resolve(true);
});
await proms();
}
let code = false;
if (imgDom) {
code = this._decodeFromImageElm(imgDom, opts);
}
return code;
}
_decodeFromImageElm(imgObj, options = {}) {
const opts = {
...this.defaultOption,
...options,
};
const imageData = this._createImageData(
imgObj,
imgObj.width,
imgObj.height,
);
const code = jsQR(
imageData.data,
imageData.width,
imageData.height,
opts,
);
if (code) {
return code;
}
return false;
}
/**
* Releases a video stream that was being
* captured by prepareToVideo
*/
stop() {
if (this.stream) {
const track = this.stream.getTracks()[0];
track.stop();
this.stream = undefined;
// fix: clear black bg after camera capture
this.videoElem.srcObject = null;
}
if (this.timerCapture) {
clearTimeout(this.timerCapture);
this.timerCapture = undefined;
}
return this;
}
/**
* Sets the sourceId for the camera to use.
*
* The sourceId can be found using the
* getVideoSources function on a browser that
* supports it (currently only Chrome).
*
* @param {String} sourceId The id of the
* video source you want to use (or false to use
* the current default)
*/
setSourceId(sourceId) {
if (sourceId) {
this.videoConstraints.video = {
optional: [{ sourceId }],
};
} else {
this.videoConstraints.video = true;
}
return this;
}
/**
* Gets a list of all available video sources on
* the current device.
* @param {Function} cb callback to be resolved
* with error (first param) ou results (second
* param) - a list containing all of the sources
* that are of the 'video' kind.
*/
getVideoSources() {
const sources = [];
if (!(MediaStreamTrack && MediaStreamTrack.getSources)) {
throw new Error(
'Current browser doest not support MediaStreamTrack.getSources',
);
}
MediaStreamTrack.getSources((sourceInfos) => {
sourceInfos.forEach((sourceInfo) => {
if (sourceInfo.kind === 'video') {
sources.push(sourceInfo);
}
});
});
return sources;
}
}
export default QrcodeDecoder;
-1
View File
@@ -1 +0,0 @@
make test for your own private key
-37
View File
@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="../../node_modules/es5-shim/es5-shim.js"></script>
<script src="../../node_modules/es5-shim/es5-sham.js"></script>
<script src="../../node_modules/mocha/mocha.js"></script>
<script src="../../node_modules/expect.js/index.js"></script>
<script>
mocha.setup('bdd');
</script>
<script src="../../dist/index.aio.js"></script>
<script>
var libs = {
'expect.js': expect,
'../dist/index.js': window['qrcode-decoder']
};
var require = function(path) {
return libs[path];
}
</script>
<script src="../test.js"></script>
<script>
mocha.run();
</script>
</body>
</html>
-57
View File
@@ -1,57 +0,0 @@
const expect = require('expect.js');
const QrcodeDecoder = require('../dist/index.js');
describe('QrcodeDecoder', function () {
// global.mocha.checkLeaks = false;
this.timeout(180000);
it('be defined', function () {
expect(QrcodeDecoder).to.be.ok();
});
var qr;
beforeEach(function () {
qr = new QrcodeDecoder();
});
describe('decodeFromImage', function () {
it('decode image from img element', function (done) {
const img = document.createElement('img');
img.src = 'demo/assets/qrcode.png';
img.onload = async function () {
const result = await qr.decodeFromImage(img);
expect(result.data).to.equal('192.168.1.13:3000');
done();
}
});
it('decode image from img url', async function () {
const result = await qr.decodeFromImage('demo/assets/qrcode.png');
expect(result.data).to.equal('192.168.1.13:3000');
});
it('throw if no src in image element', async function (done) {
var img = document.createElement('img');
try {
await qr.decodeFromImage(img);
} catch(e) {
expect(e.message).to.equal('The ImageElement must contain a src')
done();
}
});
});
describe('decodeFromCamera', function () {
it('decode from a video with qrcode', async function () {
const video = document.createElement('video');
video.setAttribute('autoplay', true);
video.setAttribute('src', 'demo/assets/qrcode-video.mp4');
const result = await qr.decodeFromVideo(video);
expect(result.data).to.equal('192.168.1.13:3000');
});
});
});
+45
View File
@@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>QrcodeDecoder - Video</title>
</head>
<body>
<button id="start">Start</button> <button id="stop">Stop</button><br />
<span id="result">Click start to scan qrcode.</span><br />
<video src="./assets/qrcode-video.mp4"></video>
<script src="./lib/vconsole.min.js"></script>
<script src="./lib/index.min.js"></script>
<script type="text/javascript">
var vConsole = new VConsole();
function main() {
var video = document.querySelector('video');
var result = document.querySelector('#result');
var start = document.querySelector('#start');
var stop = document.querySelector('#stop');
var qr = new QrcodeDecoder.default();
start.onclick = startScan;
stop.onclick = function () {
qr.stop();
video.pause();
};
async function startScan() {
video.play();
const code = await qr.decodeFromVideo(video);
console.log('code', code);
result.innerText = 'Result: ' + code.data;
}
}
main();
</script>
</body>
</html>
-6294
View File
File diff suppressed because it is too large Load Diff