├── .gitignore ├── .npmignore ├── snapshots ├── 1.png └── 2.png ├── scripts ├── demo │ ├── iloveme.jpg │ ├── style.css │ ├── index.html │ └── index.js ├── version.sh ├── build-gh.sh ├── exports.js └── qrcode.js ├── types └── index.d.ts ├── README.md ├── .eslintrc.yml ├── bower.json ├── package.json ├── gulpfile.js ├── src ├── utils.js ├── plugins │ ├── effects.js │ └── edger.js ├── qrgen-canvas.js └── qrcode-light.js └── dist └── qrgen.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | gh-pages 4 | *.log 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | gh-pages 3 | scripts 4 | gulpfile.js 5 | snapshots 6 | *.log -------------------------------------------------------------------------------- /snapshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gera2ld/jsqrgen/HEAD/snapshots/1.png -------------------------------------------------------------------------------- /snapshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gera2ld/jsqrgen/HEAD/snapshots/2.png -------------------------------------------------------------------------------- /scripts/demo/iloveme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gera2ld/jsqrgen/HEAD/scripts/demo/iloveme.jpg -------------------------------------------------------------------------------- /scripts/version.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | npm run lint 3 | npm run gulp --production -- build 4 | git add dist/qrgen.js 5 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace jsqrgen { 2 | function canvas(config: Object): HTMLCanvasElement; 3 | } 4 | 5 | export = jsqrgen; -------------------------------------------------------------------------------- /scripts/build-gh.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | DEMO_DIR=dist 3 | rm -rf $DEMO_DIR 4 | npm run lint 5 | npm run gulp --production 6 | cd $DEMO_DIR 7 | git init 8 | git add . 9 | git commit -m 'Auto deploy to github-pages' 10 | git push -f git@github.com:gera2ld/jsqrgen.git master:gh-pages 11 | -------------------------------------------------------------------------------- /scripts/exports.js: -------------------------------------------------------------------------------- 1 | !function (root, factory) { 2 | if (typeof module === 'object' && module.exports) 3 | module.exports = factory(root); 4 | else 5 | root.qrgen = factory(root); 6 | }(typeof window !== 'undefined' ? window : this, function (window) { 7 | 8 | <%= contents %> 9 | 10 | return { 11 | canvas: qrcanvas, 12 | }; 13 | }); 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JS QRGen 2 | === 3 | 4 | ### DEPRECATED, please use [qrcanvas](https://github.com/gera2ld/qrcanvas) instead! 5 | 6 | This repo is DEPRECATED in favor of [qrcanvas](https://github.com/gera2ld/qrcanvas) and kept for bower support. 7 | 8 | ![Bower](https://img.shields.io/bower/v/jsqrgen.svg) 9 | ![NPM](https://img.shields.io/npm/v/jsqrgen.svg) 10 | ![Downloads](https://img.shields.io/npm/dt/jsqrgen.svg) 11 | 12 | This is a QRCode generator written in pure javascript. 13 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | rules: 2 | indent: 3 | - 2 4 | - 2 5 | quotes: 6 | - 2 7 | - single 8 | linebreak-style: 9 | - 2 10 | - unix 11 | semi: 12 | - 2 13 | - always 14 | comma-dangle: 15 | - 0 16 | no-console: 17 | - 2 18 | - allow: 19 | - warn 20 | - error 21 | no-unused-vars: 22 | - 2 23 | - args: all 24 | argsIgnorePattern: ^_ 25 | 26 | env: 27 | browser: true 28 | 29 | globals: 30 | qrcode: true 31 | 32 | extends: 'eslint:recommended' 33 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsqrgen", 3 | "description": "Generate characteristic qrcodes with a canvas.", 4 | "authors": [ 5 | "Gerald " 6 | ], 7 | "main": "dist/qrgen.js", 8 | "keywords": [ 9 | "qrcode", 10 | "qrgen", 11 | "jsqrgen" 12 | ], 13 | "license": "MIT", 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "src", 19 | "backup" 20 | ], 21 | "moduleType": [ 22 | "globals" 23 | ], 24 | "homepage": "https://github.com/gera2ld/jsqrgen" 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsqrgen", 3 | "version": "2.1.1", 4 | "title": "JSQRGen", 5 | "description": "Generate characteristic qrcodes with a canvas.", 6 | "author": "Gerald ", 7 | "license": "MIT", 8 | "main": "dist/qrgen.js", 9 | "typings": "types/index.d.ts", 10 | "scripts": { 11 | "dev": "gulp watch", 12 | "gulp": "gulp", 13 | "lint": "gulp lint", 14 | "version": "sh scripts/version.sh", 15 | "deploy": "sh scripts/build-gh.sh" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git@github.com:gera2ld/jsqrgen.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/gera2ld/jsqrgen/issues" 23 | }, 24 | "devDependencies": { 25 | "gulp": "^3.9.0", 26 | "gulp-concat": "^2.6.0", 27 | "gulp-eslint": "^3.0.1", 28 | "gulp-header": "^1.7.1", 29 | "gulp-uglify": "^2.0.0", 30 | "gulp-wrap": "^0.11.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /scripts/demo/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #eee; 3 | } 4 | * { 5 | box-sizing: border-box; 6 | } 7 | .panel { 8 | display: inline-block; 9 | width: 300px; 10 | margin-right: 10px; 11 | vertical-align: top; 12 | } 13 | #qrcanvas { 14 | display: inline-block; 15 | vertical-align: top; 16 | } 17 | .group { 18 | margin-bottom: .4em; 19 | } 20 | .group > .content { 21 | display: block; 22 | margin-left: 90px; 23 | } 24 | .group > small { 25 | float: left; 26 | width: 90px; 27 | } 28 | .input > * { 29 | width: 100%; 30 | } 31 | .input-labels { 32 | text-align-last: justify; 33 | } 34 | .tabs > * { 35 | display: inline-block; 36 | } 37 | .tab:not(.active) { 38 | display: none; 39 | } 40 | #cblogo:not(:checked) ~ .logo-header { 41 | display: none; 42 | } 43 | .logo-header > * { 44 | display: inline-block; 45 | padding: .3em; 46 | border: 1px solid #aaa; 47 | border-bottom: none; 48 | background: #eee; 49 | color: gray; 50 | cursor: pointer; 51 | } 52 | .logo-header > .active { 53 | background: wheat; 54 | color: black; 55 | } 56 | .logo-body { 57 | display: block; 58 | padding: .4em; 59 | border: 1px solid #aaa; 60 | background: wheat; 61 | } 62 | #cblogo:not(:checked) ~ .logo-body { 63 | display: none; 64 | } 65 | #effect > [value=none]:checked ~ .input { 66 | display: none; 67 | } 68 | #effect > :not([value=image]):checked ~ .input > .effect-image { 69 | display: none; 70 | } -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const gulp = require('gulp'); 3 | const wrap = require('gulp-wrap'); 4 | const concat = require('gulp-concat'); 5 | const header = require('gulp-header'); 6 | const uglify = require('gulp-uglify'); 7 | const eslint = require('gulp-eslint'); 8 | const pkg = require('./package.json'); 9 | const isProd = process.env.NODE_ENV === 'production'; 10 | const banner = `\ 11 | /** 12 | * <%= pkg.title %> - <%= pkg.description %> 13 | * @version v<%= pkg.version %> 14 | * @license <%= pkg.license %> 15 | * @author <%= pkg.author %> 16 | */ 17 | `; 18 | 19 | gulp.task('build', () => { 20 | var stream = gulp.src('src/**/*.js') 21 | .pipe(concat(`qrgen.js`)) 22 | .pipe(wrap({src: 'scripts/exports.js'})); 23 | if (isProd) stream = stream 24 | .pipe(uglify({ 25 | mangleProperties: { 26 | regex: /^m_/, 27 | }, 28 | })); 29 | stream = stream 30 | .pipe(header(banner, {pkg: pkg})) 31 | .pipe(gulp.dest('dist/')); 32 | return stream; 33 | }); 34 | 35 | gulp.task('demo', () => { 36 | return gulp.src('scripts/demo/**') 37 | .pipe(gulp.dest('dist/')); 38 | }); 39 | 40 | gulp.task('default', ['build', 'demo']); 41 | 42 | gulp.task('lint', () => { 43 | return gulp.src([ 44 | 'src/**/*.js', 45 | '!src/qrcode-light.js', 46 | ]) 47 | .pipe(concat(`qrgen-lint.js`)) 48 | .pipe(gulp.dest('dist/')) 49 | .pipe(eslint()) 50 | .pipe(eslint.format()) 51 | .pipe(eslint.failAfterError()); 52 | }); 53 | 54 | gulp.task('watch', ['default'], () => { 55 | gulp.watch('src/**/*.js', ['build']); 56 | gulp.watch('scripts/demo/**', ['demo']); 57 | }); 58 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc Create a new canvas. 3 | * @param {Int} width Width of the canvas. 4 | * @param {Int} height Height of the canvas. 5 | * @return {Canvas} 6 | */ 7 | function getCanvas(width, height) { 8 | var canvas = document.createElement('canvas'); 9 | canvas.width = width; 10 | canvas.height = height; 11 | return canvas; 12 | } 13 | 14 | /** 15 | * @desc Draw to the canvas with given image or colors. 16 | * @param {Canvas} canvas The canvas to initialize. 17 | * @param {Object} options 18 | * data: {Image} or {String} or {Array} 19 | * size: {Int} 20 | * cellSize: {Int} 21 | */ 22 | function drawCanvas(canvas, options) { 23 | var data = options.data; 24 | if (data) { 25 | var ctx = canvas.getContext('2d'); 26 | if (!Array.isArray(data)) data = [data]; 27 | forEach(data, function (item) { 28 | if (item instanceof HTMLElement) { 29 | ctx.drawImage(item, 0, 0, canvas.width, canvas.height); 30 | } else { 31 | var x, y, w, h; 32 | if (typeof item === 'string') item = {style: item}; 33 | else item = item || {}; 34 | x = (('col' in item) ? item.col * options.cellSize : item.x) || 0; 35 | y = (('row' in item) ? item.row * options.cellSize : item.y) || 0; 36 | w = (('cols' in item) ? item.cols * options.cellSize : item.width) || options.size; 37 | h = (('rows' in item) ? item.rows * options.cellSize : item.height) || options.size; 38 | if (x < 0) x += options.size; 39 | if (y < 0) y += options.size; 40 | ctx.fillStyle = item.style || 'black'; 41 | ctx.fillRect(x, y, w, h); 42 | } 43 | }); 44 | } 45 | return canvas; 46 | } 47 | 48 | function forEach(arr, cb) { 49 | var length = arr && arr.length || 0; 50 | for (var i = 0; i < length; i ++) cb.call(arr, arr[i], i); 51 | } 52 | 53 | function assign() { 54 | var obj; 55 | forEach(arguments, function (arg) { 56 | if (!obj) obj = arg; 57 | else if (arg) for(var key in arg) obj[key] = arg[key]; 58 | }); 59 | return obj; 60 | } 61 | 62 | function merge() { 63 | var res = []; 64 | forEach(arguments, function (arg) { 65 | if (Array.isArray(arg)) res = res.concat(arg); 66 | else if (arg != null) res.push(arg); 67 | }); 68 | return res; 69 | } 70 | 71 | // IE 9- does not support Uint8Array 72 | var Uint8Array = window.Uint8Array || window.Array; 73 | -------------------------------------------------------------------------------- /scripts/demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | QRCode 5 | 6 | 7 | 8 | 9 | Fork me on GitHub 10 |

QRCode Generator

11 |
12 |
13 | Text: 14 |
15 | 16 |
17 |
18 |
19 | Size: 20 |
21 | 22 |
23 |
24 |
25 | Effect: 26 |
27 | None
28 | Liquid
29 | Round
30 | Image
31 |
32 | 33 | 34 | 35 |
36 |
37 |
38 |
39 | Colors: 40 |
41 |
42 | Foreground 43 | 44 |
45 |
46 | Background 47 | 48 |
49 |
50 | Outside-border 51 | 52 |
53 |
54 | Inside-border 55 | 56 |
57 |
58 |
59 |
60 | Type number: 61 |
62 | 63 |
64 |
65 |
66 | 67 | 68 |
69 | Image 70 | Text 71 |
72 |
73 |
74 |
75 | Image: 76 | 77 |
78 | 79 |
80 |
81 |
82 |
83 |
84 | Text: 85 |
86 | 87 |
88 |
89 |
90 | Font: 91 |
92 | 93 |
94 |
95 |
96 | 97 | 98 | 99 |
100 |
101 |
102 | Size: 103 |
104 | 105 |
106 |
107 |
108 | Clear edges: 109 |
110 | 111 |
112 |
113 |
114 | Margin: 115 |
116 | 117 |
118 |
119 |
120 |
121 |
122 | 123 | Wiki 124 |
125 |
126 |
127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /src/plugins/effects.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc rendering functions for each cell 3 | */ 4 | !function () { 5 | function drawCorner(context, cornerX, cornerY, x, y, r) { 6 | if (r) { 7 | context.arcTo(cornerX, cornerY, x, y, r); 8 | } else { 9 | context.lineTo(cornerX, cornerY); 10 | context.lineTo(x, y); 11 | } 12 | } 13 | 14 | function drawRound(cell, options) { 15 | var x = cell.x; 16 | var y = cell.y; 17 | var cellSize = options.cellSize; 18 | var effect = options.value * cellSize / 2; 19 | var context = options.context; 20 | // draw cell if it should be dark 21 | if(options.isDark(cell.i, cell.j)) { 22 | context.fillStyle = QRCanvas.m_colorDark; 23 | context.beginPath(); 24 | context.moveTo(x + .5 * cellSize, y); 25 | drawCorner(context, x + cellSize, y, x + cellSize, y + .5 * cellSize, effect); 26 | drawCorner(context, x + cellSize, y + cellSize, x + .5 * cellSize, y + cellSize, effect); 27 | drawCorner(context, x, y + cellSize, x, y + .5 * cellSize, effect); 28 | drawCorner(context, x, y, x + .5 * cellSize, y, effect); 29 | //context.closePath(); 30 | context.fill(); 31 | } 32 | } 33 | 34 | function fillCorner(context, startX, startY, cornerX, cornerY, destX, destY, effect) { 35 | context.beginPath(); 36 | context.moveTo(startX, startY); 37 | drawCorner(context, cornerX, cornerY, destX, destY, effect); 38 | context.lineTo(cornerX, cornerY); 39 | context.lineTo(startX, startY); 40 | //context.closePath(); 41 | context.fill(); 42 | } 43 | 44 | function drawLiquid(cell, options) { 45 | var corners = [0, 0, 0, 0]; // NW, NE, SE, SW 46 | var i = cell.i; 47 | var j = cell.j; 48 | var x = cell.x; 49 | var y = cell.y; 50 | var cellSize = options.cellSize; 51 | var effect = options.value * cellSize / 2; 52 | var context = options.context; 53 | if(options.isDark(i-1, j)) {corners[0] ++; corners[1] ++;} 54 | if(options.isDark(i+1, j)) {corners[2] ++; corners[3] ++;} 55 | if(options.isDark(i, j-1)) {corners[0] ++; corners[3] ++;} 56 | if(options.isDark(i, j+1)) {corners[1] ++; corners[2] ++;} 57 | // draw cell 58 | context.fillStyle = QRCanvas.m_colorDark; 59 | if(options.isDark(i, j)) { 60 | if(options.isDark(i-1, j-1)) corners[0] ++; 61 | if(options.isDark(i-1, j+1)) corners[1] ++; 62 | if(options.isDark(i+1, j+1)) corners[2] ++; 63 | if(options.isDark(i+1, j-1)) corners[3] ++; 64 | context.beginPath(); 65 | context.moveTo(x + .5 * cellSize, y); 66 | drawCorner(context, x + cellSize, y, x + cellSize, y + .5 * cellSize, corners[1] ? 0 : effect); 67 | drawCorner(context, x + cellSize, y + cellSize, x + .5 * cellSize, y + cellSize, corners[2] ? 0 : effect); 68 | drawCorner(context, x, y + cellSize, x, y + .5 * cellSize, corners[3] ? 0 : effect); 69 | drawCorner(context, x, y, x + .5 * cellSize, y, corners[0] ? 0 : effect); 70 | //context.closePath(); 71 | context.fill(); 72 | } else { 73 | if(corners[0] == 2) fillCorner(context, x, y + .5 * cellSize, x, y, x + .5 * cellSize, y, effect); 74 | if(corners[1] == 2) fillCorner(context, x + .5 * cellSize, y, x + cellSize, y, x + cellSize, y + .5 * cellSize, effect); 75 | if(corners[2] == 2) fillCorner(context, x + cellSize, y + .5 * cellSize, x + cellSize, y + cellSize, x + .5 * cellSize, y + cellSize, effect); 76 | if(corners[3] == 2) fillCorner(context, x + .5 * cellSize, y + cellSize, x, y + cellSize, x, y + .5 * cellSize, effect); 77 | } 78 | } 79 | 80 | function drawImage(cell, options) { 81 | var i = cell.i; 82 | var j = cell.j; 83 | var x = cell.x; 84 | var y = cell.y; 85 | var context = options.context; 86 | var cellSize = options.cellSize; 87 | var count = options.count; 88 | context.fillStyle = QRCanvas.m_colorDark; 89 | var fillSize = .25; 90 | if (i <= 7 && j <= 7 91 | || i <= 7 && count - j - 1 <= 7 92 | || count - i - 1 <= 7 && j <= 7 93 | || i + 5 <= count && i + 9 >= count && j + 5 <= count && j + 9 >= count 94 | || i === 7 || j === 7) fillSize = 1 - .1 * options.value; 95 | var offset = (1 - fillSize) / 2; 96 | context.fillRect(x + offset * cellSize, y + offset * cellSize, fillSize * cellSize, fillSize * cellSize); 97 | } 98 | 99 | function drawImageFore(options) { 100 | var cellSize = options.cellSize; 101 | var size = options.size; 102 | var mask = options.mask(); 103 | var foreground = drawCanvas(getCanvas(size, size), { 104 | cellSize: cellSize, 105 | size: size, 106 | data: options.foreground, 107 | }); 108 | var ctx = foreground.getContext('2d'); 109 | ctx.globalCompositeOperation = 'destination-in'; 110 | ctx.drawImage(mask, 0, 0); 111 | ctx.globalCompositeOperation = 'destination-over'; 112 | ctx.fillStyle = QRCanvas.m_colorLight; 113 | ctx.fillRect(0, 0, size, size); 114 | return foreground; 115 | } 116 | 117 | assign(QRCanvas.m_effects, { 118 | round: {data: drawRound}, 119 | liquid: {data: drawLiquid}, 120 | image: {data: drawImage, foreground: drawImageFore}, 121 | }); 122 | }(); 123 | -------------------------------------------------------------------------------- /scripts/demo/index.js: -------------------------------------------------------------------------------- 1 | !function () { 2 | !function () { 3 | // function shimDataset() { 4 | // // IE 10- does not support dataset 5 | // var datasets = []; 6 | // Object.defineProperty(HTMLElement.prototype, 'dataset', { 7 | // get: function () { 8 | // var dataset, ele = this; 9 | // forEach(datasets, function (item) { 10 | // if (item.ele === ele) { 11 | // dataset = item.dataset; 12 | // return false; 13 | // } 14 | // }); 15 | // if (!dataset) { 16 | // dataset = {}; 17 | // datasets.push({ele: ele, dataset: dataset}); 18 | // forEach(ele.attributes, function (attr) { 19 | // var name = attr.name; 20 | // if (/^data-/.test(name)) { 21 | // name = name.slice(5).replace(/-(\w)/g, function (m, g) { 22 | // return g.toUpperCase(); 23 | // }); 24 | // dataset[name] = attr.value; 25 | // } 26 | // }); 27 | // } 28 | // return dataset; 29 | // }, 30 | // }); 31 | // } 32 | function shimClassList() { 33 | // IE 9- does not support classList 34 | function getClassList(el) { 35 | function get() { 36 | return el.className.trim().split(/\s+/); 37 | } 38 | function set(list) { 39 | el.className = list.join(' '); 40 | } 41 | function add() { 42 | var list = get(); 43 | forEach(arguments, function (arg) { 44 | list.indexOf(arg) < 0 && list.push(arg); 45 | }); 46 | set(list); 47 | } 48 | function remove() { 49 | var list = get(); 50 | forEach(arguments, function (arg) { 51 | var i = list.indexOf(arg); 52 | if (~i) list.splice(i, 1); 53 | }); 54 | set(list); 55 | } 56 | return { 57 | add: add, 58 | remove: remove, 59 | }; 60 | } 61 | var classLists = []; 62 | Object.defineProperty(HTMLElement.prototype, 'classList', { 63 | get: function () { 64 | var classList, ele = this; 65 | forEach(classLists, function (item) { 66 | if (item.ele === ele) { 67 | classList = item.classList; 68 | return false; 69 | } 70 | }); 71 | if (!classList) { 72 | classList = getClassList(ele); 73 | classLists.push({ele: ele, classList: classList}); 74 | } 75 | return classList; 76 | }, 77 | }); 78 | } 79 | // if (!document.body.dataset) shimDataset(); 80 | if (!document.body.classList) shimClassList(); 81 | }(); 82 | 83 | function $(selector) { 84 | return document.querySelector(selector); 85 | } 86 | function forEach(arr, cb) { 87 | for (var i = 0; i < arr.length; i ++) 88 | if (cb.call(arr, arr[i], i) === false) break; 89 | } 90 | function setLogoType(el) { 91 | if (logoTab.head) logoTab.head.classList.remove('active'); 92 | logoTab.head = el; 93 | logoTab.type = el.getAttribute('data-type'); 94 | el.classList.add('active'); 95 | forEach(logoTabs, function (el) { 96 | el.classList[el.getAttribute('data-type') === logoTab.type ? 'add' : 'remove']('active'); 97 | }); 98 | } 99 | function showImage(img, file) { 100 | if (!file) return; 101 | var reader = new FileReader; 102 | reader.onload = function () { 103 | img.src = this.result; 104 | }; 105 | reader.readAsDataURL(file); 106 | } 107 | 108 | var logoTabs = document.querySelectorAll('.logo-body>.tab'); 109 | var logoHeader = $('.logo-header'); 110 | var cbLogo = $('#cblogo'); 111 | var logoImg = $('#logoImg'); 112 | var effectImg = $('#effect-img'); 113 | var logoTab = {}; 114 | setLogoType($('.logo-header>[data-type]')); 115 | logoHeader.addEventListener('click', function (e) { 116 | var type = e.target.getAttribute('data-type'); 117 | if (type) setLogoType(e.target); 118 | }, false); 119 | 120 | $('#fimg').addEventListener('change', function (e) { 121 | showImage(logoImg, e.target.files[0]); 122 | }, false); 123 | $('#effect-file').addEventListener('change', function (e) { 124 | showImage(effectImg, e.target.files[0]); 125 | }, false); 126 | 127 | var q = $('#qrcanvas'); 128 | var canvas; 129 | $('#qrgen').onclick = function () { 130 | var colorIn = $('#colorIn').value; 131 | var colorOut = $('#colorOut').value; 132 | var colorFore = $('#colorFore').value; 133 | var colorBack = $('#colorBack').value; 134 | var options = { 135 | cellSize: Number($('#cellSize').value), 136 | foreground: [ 137 | // foreground color 138 | {style: colorFore}, 139 | // outer squares of the positioner 140 | {row: 0, rows: 7, col: 0, cols: 7, style: colorOut}, 141 | {row: -7, rows: 7, col: 0, cols: 7, style: colorOut}, 142 | {row: 0, rows: 7, col: -7, cols: 7, style: colorOut}, 143 | // inner squares of the positioner 144 | {row: 2, rows: 3, col: 2, cols: 3, style: colorIn}, 145 | {row: -5, rows: 3, col: 2, cols: 3, style: colorIn}, 146 | {row: 2, rows: 3, col: -5, cols: 3, style: colorIn}, 147 | ], 148 | background: colorBack, 149 | data: $('#qrtext').value, 150 | typeNumber: Number($('#typeNumber').value), 151 | }; 152 | //q.innerHTML=''; 153 | if (cbLogo.checked) { 154 | options.logo = { 155 | clearEdges: Number($('#qrclearedges').value), 156 | size: $('#logoSize').value / 100, 157 | margin: Number($('#logoMargin').value), 158 | }; 159 | if (logoTab.type == 'image') 160 | options.logo.image = logoImg; 161 | else { 162 | options.logo.text = $('#logoText').value; 163 | var font = $('#logoFont').value; 164 | if (font) options.logo.fontFace = font; 165 | options.logo.color = $('#logoColor').value; 166 | var style = ''; 167 | if ($('#logoItalic').checked) style += 'italic '; 168 | if ($('#logoBold').checked) style += 'bold '; 169 | options.logo.fontStyle = style; 170 | } 171 | } 172 | var effect = $('[name=effect-type]:checked').value; 173 | if (effect !== 'none') { 174 | options.effect = {key: effect, value: $('#effect-value').value / 100}; 175 | if (effect === 'image') { 176 | options.background = [colorBack, effectImg]; 177 | } 178 | } 179 | options.reuseCanvas = canvas; 180 | canvas = qrgen.canvas(options); 181 | q.appendChild(canvas); 182 | }; 183 | }(); 184 | -------------------------------------------------------------------------------- /src/plugins/edger.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @desc detect image edge based on canvas 3 | */ 4 | function Edger(canvas, options) { 5 | var _this = this; 6 | options = options || {}; 7 | _this.margin = options.margin || 0; 8 | _this.nobg = !!options.nobg; 9 | _this.isBackgroundColor = options.isBackgroundColor || _this.isBackgroundColor; 10 | _this.prepare(canvas); 11 | } 12 | 13 | Edger.prototype = { 14 | /** 15 | * @desc Read image data from a canvas and find the edges of the image. 16 | */ 17 | prepare: function (canvas) { 18 | var _this = this; 19 | var ctx = canvas.getContext('2d'); 20 | _this.width = canvas.width; 21 | _this.height = canvas.height; 22 | _this.total = _this.width * _this.height; 23 | if (_this.nobg) return; 24 | var imageData = ctx.getImageData(0, 0, _this.width, _this.height); 25 | /*_this._rect = { 26 | top: -1, 27 | right: -1, 28 | bottom: -1, 29 | left: -1, 30 | };*/ 31 | 32 | /** 33 | * Whether the pixel should be background taking margin into account. 34 | * 0 - not checked 35 | * 1 - background 36 | * 2 - edge of the image 37 | */ 38 | var bgData = _this.data = new Uint8Array(_this.total); 39 | /** 40 | * Whether the pixel itself is a background color. 41 | * 0 - not checked 42 | * 1 - background 43 | * 2 - edge of the image 44 | */ 45 | var pixelData = new Uint8Array(_this.total); 46 | 47 | // BFS 48 | var queue = [], i; 49 | var slice = [].slice; 50 | for (i = 0; i < _this.width; i ++) { 51 | checkSurroundings(i); 52 | checkSurroundings(_this.total - 1 - i); 53 | } 54 | for (i = 0; i < _this.height; i ++) { 55 | checkSurroundings(i * _this.width); 56 | checkSurroundings((i + 1) * _this.width - 1); 57 | } 58 | var head = 0; 59 | while (head < queue.length) { 60 | var index = queue[head]; 61 | if (index > _this.width) checkRow(index - _this.width); 62 | checkRow(index, true); 63 | if (index + _this.width < _this.total) checkRow(index + _this.width); 64 | head ++; 65 | } 66 | _this.totalBackground = head; 67 | 68 | function isBgPixel(index) { 69 | var value = pixelData[index]; 70 | if (!value) { 71 | var offset = index * 4; 72 | var colorArr = slice.call(imageData.data, offset, offset + 4); 73 | if (_this.isBackgroundColor(colorArr)) { 74 | value = pixelData[index] = 1; 75 | } else { 76 | value = pixelData[index] = 2; 77 | } 78 | } 79 | return value === 1; 80 | } 81 | function checkSurroundings(index) { 82 | if (bgData[index]) return; 83 | var x0 = index % _this.width; 84 | var y0 = ~~ (index / _this.width); 85 | var R = _this.margin + 1; 86 | for (var x = Math.max(0, x0 - R + 1); x < x0 + R && x < _this.width; x ++) { 87 | for (var y = Math.max(0, y0 - R + 1); y < y0 + R && y < _this.height; y ++) { 88 | var dx = x - x0; 89 | var dy = y - y0; 90 | if (dx * dx + dy * dy < R * R) { 91 | if (!isBgPixel(x + y * _this.width)) { 92 | bgData[index] = 2; 93 | return; 94 | } 95 | } 96 | } 97 | } 98 | bgData[index] = 1; 99 | queue.push(index); 100 | /*var rect = _this._rect; 101 | if (rect.top < 0 || rect.top > y0) rect.top = y0; 102 | if (rect.right < 0 || rect.right < x0) rect.right = x0; 103 | if (rect.bottom < 0 || rect.bottom < y0) rect.bottom = y0; 104 | if (rect.left < 0 || rect.left > x0) rect.left = x0;*/ 105 | } 106 | function checkRow(index, excludeSelf) { 107 | if (index % _this.width) checkSurroundings(index - 1); 108 | if (!excludeSelf) checkSurroundings(index); 109 | if ((index + 1) % _this.width) checkSurroundings(index + 1); 110 | } 111 | }, 112 | /** 113 | * @desc The default isBackgroundColor callback to decide 114 | * whether a color is background by its Alpha value. 115 | */ 116 | isBackgroundColor: function (colorArr) { 117 | return !colorArr[3]; // alpha is 0 118 | }, 119 | /** 120 | * @desc The callback to tell whether a pixel or an area is outside the edges. 121 | */ 122 | isBackground: function () { 123 | var args = arguments; 124 | var _this = this; 125 | var index; 126 | if (args.length == 1) { 127 | index = args[0]; 128 | } else if (args.length == 2) { 129 | index = args[0] + args[1] * _this.width; 130 | } else if (args.length == 4) { 131 | var x0 = args[0]; 132 | var y0 = args[1]; 133 | var x1 = x0 + args[2]; 134 | var y1 = y0 + args[3]; 135 | if (x0 < 0) x0 = 0; 136 | if (y0 < 0) y0 = 0; 137 | if (x1 > _this.width) x1 = _this.width; 138 | if (y1 > _this.height) y1 = _this.height; 139 | for (var x = x0; x < x1; x ++) for (var y = y0; y < y1; y ++) { 140 | if (!_this.isBackground(x, y)) return false; 141 | } 142 | return true; 143 | } else { 144 | throw Error('Invalid index'); 145 | } 146 | return _this.nobg ? false : _this.data[index] === 1; 147 | }, 148 | /** 149 | * @desc Tranform a color number to a RGBA array. 150 | */ 151 | /*getColorArr: function (color) { 152 | color = color || 255; 153 | return Array.isArray(color) 154 | ? [ 155 | color[0] || 0, 156 | color[1] || 0, 157 | color[2] || 0, 158 | color[3] || 255, 159 | ] : [ 160 | color >>> 24, 161 | color >>> 16 & 255, 162 | color >>> 8 & 255, 163 | color & 255, 164 | ]; 165 | },*/ 166 | /** 167 | * @desc To get a shadow with pure color 168 | */ 169 | /*getShadow: function (color) { 170 | var _this = this; 171 | var canvas = getCanvas(_this.width, _this.height); 172 | var ctx = canvas.getContext('2d'); 173 | var imageData = ctx.getImageData(0, 0, _this.width, _this.height); 174 | color = _this.getColorArr(color); 175 | for (var i = 0; i < _this.total; i ++) 176 | if (!_this.isBackground(i)) { 177 | var offset = i * 4; 178 | imageData.data[offset] = color[0]; 179 | imageData.data[offset + 1] = color[1]; 180 | imageData.data[offset + 2] = color[2]; 181 | imageData.data[offset + 3] = color[3]; 182 | } 183 | ctx.putImageData(imageData, 0, 0); 184 | return canvas; 185 | },*/ 186 | /** 187 | * @desc To clear the background so that the shadow can be filled with custom styles. 188 | */ 189 | clearBackground: function (canvas) { 190 | var _this = this; 191 | if (canvas.width != _this.width || canvas.height != _this.height) return; 192 | var ctx = canvas.getContext('2d'); 193 | var imageData = ctx.getImageData(0, 0, _this.width, _this.height); 194 | for (var i = 0; i < _this.total; i ++) 195 | if (_this.isBackground(i)) { 196 | var offset = i * 4; 197 | imageData.data[offset] = 0; 198 | imageData.data[offset + 1] = 0; 199 | imageData.data[offset + 2] = 0; 200 | imageData.data[offset + 3] = 0; 201 | } 202 | ctx.putImageData(imageData, 0, 0); 203 | return canvas; 204 | }, 205 | /** 206 | * @desc Get the real edges of the image excluding the background part. 207 | */ 208 | /*getRect: function () { 209 | var rect = this._rect; 210 | return { 211 | top: rect.top, 212 | right: rect.right, 213 | bottom: rect.bottom, 214 | left: rect.left, 215 | width: rect.right - rect.left + 1, 216 | height: rect.bottom - rect.top + 1, 217 | }; 218 | },*/ 219 | }; 220 | 221 | QRCanvas.prototype.m_detectEdges = function () { 222 | var _this = this; 223 | var logo = _this.m_logo; 224 | var count = _this.m_count; 225 | var cellSize = _this.m_cellSize; 226 | var edger = logo.edger = new Edger(logo.canvas, { 227 | margin: logo.margin, 228 | nobg: logo.clearEdges == 2, 229 | }); 230 | 231 | // whether to clear cells broken by the logo (incomplete cells) 232 | if (logo.clearEdges) { 233 | /** 234 | * Whether the cell is overlapped by logo. 235 | * 0 - partially or completely overlapped. 236 | * 1 - clear. 237 | */ 238 | var transclude = _this.m_transclude = new Uint8Array(count * count); 239 | for (var i = 0; i < count; i ++) for (var j = 0; j < count; j ++) { 240 | transclude[i * count + j] = edger.isBackground(j * cellSize - logo.x, i * cellSize - logo.y, cellSize, cellSize); 241 | } 242 | } 243 | }; 244 | QRCanvas.prototype.m_clearLogo = function (canvas) { 245 | var _this = this; 246 | var logo = _this.m_logo; 247 | if((logo.image || logo.text) && !logo.clearEdges) { 248 | var canvasLogo = getCanvas(logo.width + 2 * logo.margin, logo.height + 2 * logo.margin); 249 | var ctx = canvasLogo.getContext('2d'); 250 | ctx.fillStyle = 'white'; 251 | ctx.fillRect(0, 0, canvasLogo.width, canvasLogo.height); 252 | logo.edger.clearBackground(canvasLogo); 253 | var context = canvas.getContext('2d'); 254 | context.globalCompositeOperation = 'destination-out'; 255 | context.drawImage(canvasLogo, logo.x, logo.y); 256 | } 257 | }; 258 | QRCanvas.prototype.m_shouldTransclude = function (index) { 259 | var _this = this; 260 | return _this.m_logo.clearEdges ? _this.m_transclude[index] : true; 261 | }; 262 | -------------------------------------------------------------------------------- /src/qrgen-canvas.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSQRGen: QRCode Canvas Renderer 3 | * @author Gerald 4 | * @license MIT 5 | */ 6 | 7 | function QRCanvas(options) { 8 | this.m_init(options); 9 | } 10 | 11 | // rendering functions 12 | QRCanvas.m_effects = { 13 | square: { 14 | data: function (cell, options) { 15 | var context = options.context; 16 | var cellSize = options.cellSize; 17 | if (options.isDark(cell.i, cell.j)) { 18 | context.fillStyle = QRCanvas.m_colorDark; 19 | context.fillRect(cell.x, cell.y, cellSize, cellSize); 20 | } 21 | }, 22 | }, 23 | }; 24 | QRCanvas.m_getEffect = function (key) { 25 | return QRCanvas.m_effects[key] || QRCanvas.m_effects.square; 26 | }; 27 | QRCanvas.m_colorDark = 'black'; 28 | QRCanvas.m_colorLight = 'white'; 29 | 30 | QRCanvas.prototype.m_init = function (options) { 31 | var _this = this; 32 | options = _this.m_options = assign({ 33 | // typeNumber belongs to 1..40 34 | // will be increased to the smallest valid number if too small 35 | typeNumber: 1, 36 | 37 | // correctLevel can be 'L', 'M', 'Q' or 'H' 38 | correctLevel: 'M', 39 | 40 | // cellSize is preferred to size 41 | // if none is provided, use default values below 42 | // * cellSize: 2, 43 | // * size: cellSize * count, 44 | 45 | // foreground and background may be an image or a style string 46 | // or an array of objects with attributes below: 47 | // * row | x: default 0 48 | // * col | y: default 0 49 | // * cols | width: default size 50 | // * rows | height: default size 51 | // * style: default 'black' 52 | foreground: QRCanvas.m_colorDark, 53 | background: null, 54 | 55 | // data MUST be a string 56 | data: '', 57 | 58 | // effect: an object with optional key and value 59 | // - {key: 'round', value: 0-1} 60 | // - {key: 'liquid', value: 0-1} 61 | // - {key: 'image', value: 0-1} 62 | effect: {}, 63 | 64 | // Avoid transparent pixels 65 | noAlpha: true, 66 | 67 | // Null or a canvas to be reused 68 | reuseCanvas: null, 69 | 70 | /** 71 | * an image or text can be used as a logo 72 | * logo: { 73 | * // image 74 | * image: Image, 75 | 76 | * // text 77 | * text: string, 78 | * color: string, default 'black' 79 | * fontStyle: string, e.g. 'italic bold' 80 | * fontFamily: string, default 'Cursive' 81 | 82 | * // common 83 | * clearEdges: number, default 0 84 | * 0 - not clear, just margin 85 | * 1 - clear incomplete cells 86 | * 2 - clear a larger rectangle area 87 | * margin: number, default 2 for text and 0 for image 88 | * size: float, default .15 stands for 15% of the QRCode 89 | * } 90 | */ 91 | // logo: {}, 92 | }, options); 93 | var logo = _this.m_logo = { 94 | color: QRCanvas.m_colorDark, 95 | fontFamily: 'Cursive', 96 | clearEdges: 0, 97 | margin: -1, 98 | size: .15, 99 | }; 100 | var optionLogo = options.logo; 101 | optionLogo && (optionLogo.image || optionLogo.text) && assign(logo, optionLogo); 102 | if (logo.image || logo.text) { 103 | if (logo.margin < 0) logo.margin = logo.image ? 0 : 2; 104 | } 105 | 106 | if (logo.image || logo.text || options.effect.key === 'image') { 107 | options.correctLevel = 'H'; 108 | } 109 | 110 | // Generate QRCode data with qrcode-light.js 111 | var qr = qrcode(options.typeNumber, options.correctLevel); 112 | qr.addData(options.data); 113 | qr.make(); 114 | 115 | // calculate QRCode and cell sizes 116 | var count = qr.getModuleCount(); 117 | var cellSize = options.cellSize; 118 | var size = options.size; 119 | if (!cellSize && !size) cellSize = 2; 120 | if (cellSize) { 121 | size = cellSize * count; 122 | } else { 123 | cellSize = size / count; 124 | } 125 | _this.m_cellSize = cellSize; 126 | _this.m_size = size; 127 | _this.m_count = count; 128 | _this.m_data = qr; 129 | }; 130 | QRCanvas.prototype.m_isDark = function (i, j) { 131 | var _this = this; 132 | var count = _this.m_count; 133 | return i >= 0 && i < count && j >= 0 && j < count 134 | && _this.m_shouldTransclude(i * count + j) 135 | && _this.m_data.isDark(i, j); 136 | }; 137 | QRCanvas.prototype.m_draw = function () { 138 | var _this = this; 139 | var options = _this.m_options; 140 | var count = _this.m_count; 141 | // ensure size and cellSize are integers 142 | // so that there will not be gaps between cells 143 | var cellSize = Math.ceil(_this.m_cellSize); 144 | var size = cellSize * count; 145 | var canvasData = getCanvas(size, size); 146 | var optionsDraw = { 147 | cellSize: cellSize, 148 | size: size, 149 | count: count, 150 | effect: options.effect, 151 | foreground: options.foreground, 152 | }; 153 | 154 | _this.m_initLogo(canvasData); 155 | _this.m_drawCells(canvasData, optionsDraw); 156 | _this.m_clearLogo(canvasData); 157 | 158 | var foreground = _this.m_drawForeground(optionsDraw); 159 | var contextFore = foreground.getContext('2d'); 160 | contextFore.globalCompositeOperation = 'destination-in'; 161 | contextFore.drawImage(canvasData, 0, 0); 162 | 163 | var canvas = drawCanvas(getCanvas(size, size), { 164 | cellSize: cellSize, 165 | size: size, 166 | data: merge( 167 | options.noAlpha ? QRCanvas.m_colorLight : null, 168 | options.background, 169 | foreground 170 | ), 171 | }); 172 | 173 | var logo = _this.m_logo; 174 | if (logo.canvas) canvas.getContext('2d').drawImage(logo.canvas, logo.x, logo.y); 175 | 176 | var destSize = _this.m_size; 177 | var canvasTarget = options.reuseCanvas; 178 | if (canvasTarget) { 179 | canvasTarget.width = canvasTarget.height = destSize; 180 | } else if (size != destSize) { 181 | // strech image if the size is not expected 182 | canvasTarget = getCanvas(destSize, destSize); 183 | } 184 | if (canvasTarget) { 185 | var contextTarget = canvasTarget.getContext('2d'); 186 | contextTarget.drawImage(canvas, 0, 0, destSize, destSize); 187 | } else { 188 | canvasTarget = canvas; 189 | } 190 | return canvasTarget; 191 | }; 192 | QRCanvas.prototype.m_drawForeground = function (options) { 193 | var _this = this; 194 | var cellSize = options.cellSize; 195 | var size = options.size; 196 | var effect = options.effect || {}; 197 | var draw = QRCanvas.m_getEffect(effect.key); 198 | if (draw.foreground) { 199 | return draw.foreground(assign({ 200 | mask: function () { 201 | // mask is a canvas with basic rendered QRCode 202 | var mask = getCanvas(size, size); 203 | // draw mask without effects 204 | _this.m_drawCells(mask, { 205 | cellSize: cellSize, 206 | count: options.count, 207 | }); 208 | return mask; 209 | }, 210 | }, options)); 211 | } else { 212 | return drawCanvas(getCanvas(size, size), { 213 | cellSize: cellSize, 214 | size: size, 215 | data: options.foreground, 216 | }); 217 | } 218 | }; 219 | QRCanvas.prototype.m_initLogo = function (canvas) { 220 | // limit the logo size 221 | var _this = this; 222 | var logo = _this.m_logo; 223 | var count = _this.m_count; 224 | var cellSize = _this.m_cellSize; 225 | var size = _this.m_size; 226 | var context = canvas.getContext('2d'); 227 | var k, width, height; 228 | 229 | // if logo is an image 230 | if (logo.image) { 231 | k = logo.image; 232 | width = k.naturalWidth || k.width; 233 | height = k.naturalHeight || k.height; 234 | } 235 | // if logo is text 236 | else if (logo.text) { 237 | // get text width/height radio by assuming fontHeight=100px 238 | height = 100; 239 | k = ''; 240 | if (logo.fontStyle) k += logo.fontStyle + ' '; 241 | k += height + 'px ' + logo.fontFamily; 242 | context.font = k; 243 | width = context.measureText(logo.text).width; 244 | } 245 | // otherwise do nothing 246 | else return; 247 | 248 | // calculate the number of cells to be broken or covered by the logo 249 | k = width / height; 250 | var numberHeight = ~~ (Math.sqrt(Math.min(width * height / size / size, logo.size) / k) * count); 251 | var numberWidth = ~~ (k * numberHeight); 252 | // (count - [numberWidth | numberHeight]) must be even if the logo is in the middle 253 | if ((count - numberWidth) % 2) numberWidth ++; 254 | if ((count - numberHeight) % 2) numberHeight ++; 255 | 256 | // calculate the final width and height of the logo 257 | k = Math.min((numberHeight * cellSize - 2 * logo.margin) / height, (numberWidth * cellSize - 2 * logo.margin) / width, 1); 258 | logo.width = ~~ (k * width); 259 | logo.height = ~~ (k * height); 260 | logo.x = ((size - logo.width) >> 1) - logo.margin; 261 | logo.y = ((size - logo.height) >> 1) - logo.margin; 262 | 263 | // draw logo to a canvas 264 | logo.canvas = getCanvas(logo.width + 2 * logo.margin, logo.height + 2 * logo.margin); 265 | var ctx = logo.canvas.getContext('2d'); 266 | if (logo.image) { 267 | ctx.drawImage(logo.image, logo.margin, logo.margin, logo.width, logo.height); 268 | } else { 269 | var font = ''; 270 | if (logo.fontStyle) font += logo.fontStyle + ' '; 271 | font += logo.height + 'px ' + logo.fontFamily; 272 | ctx.font = font; 273 | // draw text in the middle 274 | ctx.textAlign = 'center'; 275 | ctx.textBaseline = 'middle'; 276 | ctx.fillStyle = logo.color; 277 | ctx.fillText(logo.text, (logo.width >> 1) + logo.margin, (logo.height >> 1) + logo.margin); 278 | } 279 | _this.m_detectEdges(); 280 | }; 281 | QRCanvas.prototype.m_drawCells = function (canvas, options) { 282 | var _this = this; 283 | var cellSize = options.cellSize; 284 | var count = options.count; 285 | var effect = options.effect || {}; 286 | var cellOptions = { 287 | cellSize: cellSize, 288 | count: count, 289 | context: canvas.getContext('2d'), 290 | value: effect.value || 0, 291 | isDark: _this.m_isDark.bind(_this), 292 | }; 293 | // draw qrcode according to effect 294 | var draw = QRCanvas.m_getEffect(effect.key); 295 | // draw cells 296 | for (var i = 0; i < count; i ++) { 297 | for (var j = 0; j < count; j ++) { 298 | draw.data({ 299 | i: i, 300 | j: j, 301 | x: j * cellSize, 302 | y: i * cellSize, 303 | }, cellOptions); 304 | } 305 | } 306 | }; 307 | /** 308 | * @desc Transform color to remove alpha channel 309 | */ 310 | QRCanvas.prototype.m_transformColor = function (fg, bg, alpha) { 311 | return ~~ (fg * alpha / 255 + bg * (255 - alpha) / 255); 312 | }; 313 | QRCanvas.prototype.m_detectEdges = function () {}; 314 | QRCanvas.prototype.m_clearLogo = function (_canvas) {}; 315 | QRCanvas.prototype.m_shouldTransclude = function (_index) { 316 | if (this.m_logo.clearEdges) { 317 | return false; 318 | } else { 319 | return true; 320 | } 321 | }; 322 | 323 | /* eslint-disable */ 324 | function qrcanvas(options) { 325 | var qrcanvas = new QRCanvas(options); 326 | return qrcanvas.m_draw(); 327 | } 328 | -------------------------------------------------------------------------------- /dist/qrgen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * JSQRGen - Generate characteristic qrcodes with a canvas. 3 | * @version v2.1.1 4 | * @license MIT 5 | * @author Gerald 6 | */ 7 | !function(r,t){"object"==typeof module&&module.exports?module.exports=t(r):r.qrgen=t(r)}("undefined"!=typeof window?window:this,function(r){function t(r){this.a(r)}function e(r){var e=new t(r);return e.b()}function n(r,t){var e=document.createElement("canvas");return e.width=r,e.height=t,e}function a(r,t){var e=t.data;if(e){var n=r.getContext("2d");Array.isArray(e)||(e=[e]),o(e,function(e){if(e instanceof HTMLElement)n.drawImage(e,0,0,r.width,r.height);else{var a,o,i,u;e="string"==typeof e?{style:e}:e||{},a=("col"in e?e.col*t.cellSize:e.x)||0,o=("row"in e?e.row*t.cellSize:e.y)||0,i=("cols"in e?e.cols*t.cellSize:e.width)||t.size,u=("rows"in e?e.rows*t.cellSize:e.height)||t.size,a<0&&(a+=t.size),o<0&&(o+=t.size),n.fillStyle=e.style||"black",n.fillRect(a,o,i,u)}})}return r}function o(r,t){for(var e=r&&r.length||0,n=0;n40)throw r}s=4*g+17,h=function(r){for(var t=new Array(r),e=0;e=7&&E(r),D(v,t)},m=function(r,t){for(var e=-1;e<=7;e+=1)if(!(r+e<=-1||s<=r+e))for(var n=-1;n<=7;n+=1)t+n<=-1||s<=t+n||(0<=e&&e<=6&&(0==n||6==n)||0<=n&&n<=6&&(0==e||6==e)||2<=e&&e<=4&&2<=n&&n<=4?h[r+e][t+n]=!0:h[r+e][t+n]=!1)},y=function(){for(var r=0,t=0,e=0;e<8;e+=1){p(!0,e);var n=o.getLostPoint(w);(0==e||r>n)&&(r=n,t=e)}return t},k=function(){for(var r=8;r>e&1);h[Math.floor(e/3)][e%3+s-8-3]=n}for(var e=0;e<18;e+=1){var n=!r&&1==(t>>e&1);h[e%3+s-8-3][Math.floor(e/3)]=n}},T=function(r,t){for(var e=c<<3|t,n=o.getBCHTypeInfo(e),a=0;a<15;a+=1){var i=!r&&1==(n>>a&1);a<6?h[a][8]=i:a<8?h[a+1][8]=i:h[s-15+a][8]=i}for(var a=0;a<15;a+=1){var i=!r&&1==(n>>a&1);a<8?h[8][s-a-1]=i:a<9?h[8][15-a-1+1]=i:h[8][15-a-1]=i}h[s-8][8]=!r},D=function(r,t){for(var e=-1,n=s-1,a=7,i=0,u=o.getMaskFunction(t),f=s-1;f>0;f-=2)for(6==f&&(f-=1);;){for(var l=0;l<2;l+=1)if(null==h[n][f-l]){var g=!1;i>>a&1));var c=u(n,f-l);c&&(g=!g),h[n][f-l]=g,a-=1,a==-1&&(i+=1,a=7)}if(n+=e,n<0||s<=n){n-=e,e=-e;break}}},M=function(t,e){for(var n=0,a=0,i=0,u=new Array(e.length),f=new Array(e.length),l=0;l=0?d.getAt(w):0}}for(var p=0,h=0;h8*h)throw new Error("code length overflow. ("+l.getLengthInBits()+">"+8*h+")");for(l.getLengthInBits()+4<=8*h&&l.put(0,4);l.getLengthInBits()%8!=0;)l.putBit(!1);for(;;){if(l.getLengthInBits()>=8*h)break;if(l.put(a,8),l.getLengthInBits()>=8*h)break;l.put(i,8)}return M(l,n)};return w.addData=function(r){var t=l(r);d.push(t),v=null},w.isDark=function(r,t){if(r<0||s<=r||t<0||s<=t)throw new Error(r+","+t);return h[r][t]},w.getModuleCount=function(){return s},w.make=function(){p(!1,y())},w};t.stringToBytes=function(r){var t=[];r=r.replace(/\r\n/g,"\n");for(var e=0;e>6|192,63&n|128):t.push(n>>12|224,n>>6&63|128,63&n|128)}return t},t.createStringToBytes=function(r,t){var e=function(){for(var e=base64DecodeInputStream(r),n=function(){var r=e.read();if(r==-1)throw new Error;return r},a=0,o={};;){var i=e.read();if(i==-1)break;var u=n(),f=n(),l=n(),g=String.fromCharCode(i<<8|u),c=f<<8|l;o[g]=c,a+=1}if(a!=t)throw new Error(a+" != "+t);return o}(),n="?".charCodeAt(0);return function(r){for(var t=new Array,a=0;a>>8),t.push(255&i)):t.push(n)}}return t}};var e={MODE_NUMBER:1,MODE_ALPHA_NUM:2,MODE_8BIT_BYTE:4,MODE_KANJI:8},n={L:1,M:0,Q:3,H:2},a={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7},o=function(){var t=[[],[6,18],[6,22],[6,26],[6,30],[6,34],[6,22,38],[6,24,42],[6,26,46],[6,28,50],[6,30,54],[6,32,58],[6,34,62],[6,26,46,66],[6,26,48,70],[6,26,50,74],[6,30,54,78],[6,30,56,82],[6,30,58,86],[6,34,62,90],[6,28,50,72,94],[6,26,50,74,98],[6,30,54,78,102],[6,28,54,80,106],[6,32,58,84,110],[6,30,58,86,114],[6,34,62,90,118],[6,26,50,74,98,122],[6,30,54,78,102,126],[6,26,52,78,104,130],[6,30,56,82,108,134],[6,34,60,86,112,138],[6,30,58,86,114,142],[6,34,62,90,118,146],[6,30,54,78,102,126,150],[6,24,50,76,102,128,154],[6,28,54,80,106,132,158],[6,32,58,84,110,136,162],[6,26,54,82,110,138,166],[6,30,58,86,114,142,170]],n=1335,o=7973,u=21522,f={},l=function(r){for(var t=0;0!=r;)t+=1,r>>>=1;return t};return f.getBCHTypeInfo=function(r){for(var t=r<<10;l(t)-l(n)>=0;)t^=n<=0;)t^=o<5&&(e+=3+o-5)}for(var n=0;n=256;)t-=255;return r[t]},n}(),u=function(){var r=[[1,26,19],[1,26,16],[1,26,13],[1,26,9],[1,44,34],[1,44,28],[1,44,22],[1,44,16],[1,70,55],[1,70,44],[2,35,17],[2,35,13],[1,100,80],[2,50,32],[2,50,24],[4,25,9],[1,134,108],[2,67,43],[2,33,15,2,34,16],[2,33,11,2,34,12],[2,86,68],[4,43,27],[4,43,19],[4,43,15],[2,98,78],[4,49,31],[2,32,14,4,33,15],[4,39,13,1,40,14],[2,121,97],[2,60,38,2,61,39],[4,40,18,2,41,19],[4,40,14,2,41,15],[2,146,116],[3,58,36,2,59,37],[4,36,16,4,37,17],[4,36,12,4,37,13],[2,86,68,2,87,69],[4,69,43,1,70,44],[6,43,19,2,44,20],[6,43,15,2,44,16][81],[1,80,50,4,81,51],[4,50,22,4,51,23],[3,36,12,8,37,13],[2,116,92,2,117,93],[6,58,36,2,59,37],[4,46,20,6,47,21],[7,42,14,4,43,15],[4,133,107],[8,59,37,1,60,38],[8,44,20,4,45,21],[12,33,11,4,34,12],[3,145,115,1,146,116],[4,64,40,5,65,41],[11,36,16,5,37,17],[11,36,12,5,37,13],[5,109,87,1,110,88],[5,65,41,5,66,42],[5,54,24,7,55,25],[11,36,12,7,37,13],[5,122,98,1,123,99],[7,73,45,3,74,46],[15,43,19,2,44,20],[3,45,15,13,46,16],[1,135,107,5,136,108],[10,74,46,1,75,47],[1,50,22,15,51,23],[2,42,14,17,43,15],[5,150,120,1,151,121],[9,69,43,4,70,44],[17,50,22,1,51,23],[2,42,14,19,43,15],[3,141,113,4,142,114],[3,70,44,11,71,45],[17,47,21,4,48,22],[9,39,13,16,40,14],[3,135,107,5,136,108],[3,67,41,13,68,42],[15,54,24,5,55,25],[15,43,15,10,44,16],[4,144,116,4,145,117],[17,68,42],[17,50,22,6,51,23],[19,46,16,6,47,17],[2,139,111,7,140,112],[17,74,46],[7,54,24,16,55,25],[34,37,13],[4,151,121,5,152,122],[4,75,47,14,76,48],[11,54,24,14,55,25],[16,45,15,14,46,16],[6,147,117,4,148,118],[6,73,45,14,74,46],[11,54,24,16,55,25],[30,46,16,2,47,17],[8,132,106,4,133,107],[8,75,47,13,76,48],[7,54,24,22,55,25],[22,45,15,13,46,16],[10,142,114,2,143,115],[19,74,46,4,75,47],[28,50,22,6,51,23],[33,46,16,4,47,17],[8,152,122,4,153,123],[22,73,45,3,74,46],[8,53,23,26,54,24],[12,45,15,28,46,16],[3,147,117,10,148,118],[3,73,45,23,74,46],[4,54,24,31,55,25],[11,45,15,31,46,16],[7,146,116,7,147,117],[21,73,45,7,74,46],[1,53,23,37,54,24],[19,45,15,26,46,16],[5,145,115,10,146,116],[19,75,47,10,76,48],[15,54,24,25,55,25],[23,45,15,25,46,16],[13,145,115,3,146,116],[2,74,46,29,75,47],[42,54,24,1,55,25],[23,45,15,28,46,16],[17,145,115],[10,74,46,23,75,47],[10,54,24,35,55,25],[19,45,15,35,46,16],[17,145,115,1,146,116],[14,74,46,21,75,47],[29,54,24,19,55,25],[11,45,15,46,46,16],[13,145,115,6,146,116],[14,74,46,23,75,47],[44,54,24,7,55,25],[59,46,16,1,47,17],[12,151,121,7,152,122],[12,75,47,26,76,48],[39,54,24,14,55,25],[22,45,15,41,46,16],[6,151,121,14,152,122],[6,75,47,34,76,48],[46,54,24,10,55,25],[2,45,15,64,46,16],[17,152,122,4,153,123],[29,74,46,14,75,47],[49,54,24,10,55,25],[24,45,15,46,46,16],[4,152,122,18,153,123],[13,74,46,32,75,47],[48,54,24,14,55,25],[42,45,15,32,46,16],[20,147,117,4,148,118],[40,75,47,7,76,48],[43,54,24,22,55,25],[10,45,15,67,46,16],[19,148,118,6,149,119],[18,75,47,31,76,48],[34,54,24,34,55,25],[20,45,15,61,46,16]],t=function(r,t){var e={};return e.totalCount=r,e.dataCount=t,e},e={},a=function(t,e){switch(e){case n.L:return r[4*(t-1)+0];case n.M:return r[4*(t-1)+1];case n.Q:return r[4*(t-1)+2];case n.H:return r[4*(t-1)+3];default:return}};return e.getRSBlocks=function(r,e){var n=a(r,e);if("undefined"==typeof n)throw new Error("bad rs block @ typeNumber:"+r+"/errorCorrectLevel:"+e);for(var o=n.length/3,i=new Array,u=0;u>>7-t%8&1)},e.put=function(r,t){for(var n=0;n>>t-n-1&1))},e.getLengthInBits=function(){return t},e.putBit=function(e){var n=Math.floor(t/8);r.length<=n&&r.push(0),e&&(r[n]|=128>>>t%8),t+=1},e},l=function(r){var n=e.MODE_8BIT_BYTE,a=t.stringToBytes(r),o={};return o.getMode=function(){return n},o.getLength=function(r){return a.length},o.write=function(r){for(var t=0;t=0&&r=0&&t>1)-i.margin,i.y=(l-i.height>>1)-i.margin,i.canvas=n(i.width+2*i.margin,i.height+2*i.margin);var s=i.canvas.getContext("2d");if(i.image)s.drawImage(i.image,i.margin,i.margin,i.width,i.height);else{var v="";i.fontStyle&&(v+=i.fontStyle+" "),v+=i.height+"px "+i.fontFamily,s.font=v,s.textAlign="center",s.textBaseline="middle",s.fillStyle=i.color,s.fillText(i.text,(i.width>>1)+i.margin,(i.height>>1)+i.margin)}o.u()},t.prototype.r=function(r,e){for(var n=this,a=e.cellSize,o=e.count,i=e.effect||{},u={cellSize:a,count:o,context:r.getContext("2d"),value:i.value||0,isDark:n.o.bind(n)},f=t.e(i.key),l=0;la.width&&n(v-a.width),n(v,!0),v+a.widthe.width&&(o=e.width),i>e.height&&(i=e.height);for(var u=n;u=l&&a+5<=l&&a+9>=l||7===n||7===a)&&(g=1-.1*e.value);var c=(1-g)/2;u.fillRect(o+c*f,i+c*f,g*f,g*f)}function l(r){var e=r.cellSize,o=r.size,i=r.mask(),u=a(n(o,o),{cellSize:e,size:o,data:r.foreground}),f=u.getContext("2d");return f.globalCompositeOperation="destination-in",f.drawImage(i,0,0),f.globalCompositeOperation="destination-over",f.fillStyle=t.f,f.fillRect(0,0,o,o),u}i(t.c,{round:{data:e},liquid:{data:u},image:{data:f,foreground:l}})}(),{canvas:e}}); -------------------------------------------------------------------------------- /src/qrcode-light.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript 4 | // 5 | // Copyright (c) 2009 Kazuhiko Arase 6 | // 7 | // URL: http://www.d-project.com/ 8 | // 9 | // Licensed under the MIT license: 10 | // http://www.opensource.org/licenses/mit-license.php 11 | // 12 | // The word 'QR Code' is registered trademark of 13 | // DENSO WAVE INCORPORATED 14 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 | // 16 | // 17 | // Modified by: Gerald 18 | // * Removed unneeded code 19 | // * Added UTF-8 encoding 20 | //----------------------------------------------------------------------- 21 | 22 | var qrcode = function() { 23 | 24 | //--------------------------------------------------------------------- 25 | // qrcode 26 | //--------------------------------------------------------------------- 27 | 28 | /** 29 | * qrcode 30 | * @param typeNumber 1 to 10 31 | * @param errorCorrectLevel 'L','M','Q','H' 32 | */ 33 | var qrcode = function(typeNumber, errorCorrectLevel) { 34 | 35 | var PAD0 = 0xEC; 36 | var PAD1 = 0x11; 37 | 38 | var _typeNumber = typeNumber; 39 | var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel]; 40 | var _modules = null; 41 | var _moduleCount = 0; 42 | var _dataCache = null; 43 | var _dataList = new Array(); 44 | 45 | var _this = {}; 46 | 47 | var makeImpl = function(test, maskPattern) { 48 | 49 | while (_dataCache == null) { 50 | try { 51 | _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList); 52 | break; 53 | } catch (e) { 54 | _typeNumber ++; 55 | if (_typeNumber > 40) throw e; 56 | } 57 | } 58 | 59 | _moduleCount = _typeNumber * 4 + 17; 60 | _modules = function(moduleCount) { 61 | var modules = new Array(moduleCount); 62 | for (var row = 0; row < moduleCount; row += 1) { 63 | modules[row] = new Array(moduleCount); 64 | for (var col = 0; col < moduleCount; col += 1) { 65 | modules[row][col] = null; 66 | } 67 | } 68 | return modules; 69 | }(_moduleCount); 70 | 71 | setupPositionProbePattern(0, 0); 72 | setupPositionProbePattern(_moduleCount - 7, 0); 73 | setupPositionProbePattern(0, _moduleCount - 7); 74 | setupPositionAdjustPattern(); 75 | setupTimingPattern(); 76 | setupTypeInfo(test, maskPattern); 77 | 78 | if (_typeNumber >= 7) { 79 | setupTypeNumber(test); 80 | } 81 | 82 | mapData(_dataCache, maskPattern); 83 | }; 84 | 85 | var setupPositionProbePattern = function(row, col) { 86 | 87 | for (var r = -1; r <= 7; r += 1) { 88 | 89 | if (row + r <= -1 || _moduleCount <= row + r) continue; 90 | 91 | for (var c = -1; c <= 7; c += 1) { 92 | 93 | if (col + c <= -1 || _moduleCount <= col + c) continue; 94 | 95 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) 96 | || (0 <= c && c <= 6 && (r == 0 || r == 6) ) 97 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { 98 | _modules[row + r][col + c] = true; 99 | } else { 100 | _modules[row + r][col + c] = false; 101 | } 102 | } 103 | } 104 | }; 105 | 106 | var getBestMaskPattern = function() { 107 | 108 | var minLostPoint = 0; 109 | var pattern = 0; 110 | 111 | for (var i = 0; i < 8; i += 1) { 112 | 113 | makeImpl(true, i); 114 | 115 | var lostPoint = QRUtil.getLostPoint(_this); 116 | 117 | if (i == 0 || minLostPoint > lostPoint) { 118 | minLostPoint = lostPoint; 119 | pattern = i; 120 | } 121 | } 122 | 123 | return pattern; 124 | }; 125 | 126 | var setupTimingPattern = function() { 127 | 128 | for (var r = 8; r < _moduleCount - 8; r += 1) { 129 | if (_modules[r][6] != null) { 130 | continue; 131 | } 132 | _modules[r][6] = (r % 2 == 0); 133 | } 134 | 135 | for (var c = 8; c < _moduleCount - 8; c += 1) { 136 | if (_modules[6][c] != null) { 137 | continue; 138 | } 139 | _modules[6][c] = (c % 2 == 0); 140 | } 141 | }; 142 | 143 | var setupPositionAdjustPattern = function() { 144 | 145 | var pos = QRUtil.getPatternPosition(_typeNumber); 146 | 147 | for (var i = 0; i < pos.length; i += 1) { 148 | 149 | for (var j = 0; j < pos.length; j += 1) { 150 | 151 | var row = pos[i]; 152 | var col = pos[j]; 153 | 154 | if (_modules[row][col] != null) { 155 | continue; 156 | } 157 | 158 | for (var r = -2; r <= 2; r += 1) { 159 | 160 | for (var c = -2; c <= 2; c += 1) { 161 | 162 | if (r == -2 || r == 2 || c == -2 || c == 2 163 | || (r == 0 && c == 0) ) { 164 | _modules[row + r][col + c] = true; 165 | } else { 166 | _modules[row + r][col + c] = false; 167 | } 168 | } 169 | } 170 | } 171 | } 172 | }; 173 | 174 | var setupTypeNumber = function(test) { 175 | 176 | var bits = QRUtil.getBCHTypeNumber(_typeNumber); 177 | 178 | for (var i = 0; i < 18; i += 1) { 179 | var mod = (!test && ( (bits >> i) & 1) == 1); 180 | _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; 181 | } 182 | 183 | for (var i = 0; i < 18; i += 1) { 184 | var mod = (!test && ( (bits >> i) & 1) == 1); 185 | _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; 186 | } 187 | }; 188 | 189 | var setupTypeInfo = function(test, maskPattern) { 190 | 191 | var data = (_errorCorrectLevel << 3) | maskPattern; 192 | var bits = QRUtil.getBCHTypeInfo(data); 193 | 194 | // vertical 195 | for (var i = 0; i < 15; i += 1) { 196 | 197 | var mod = (!test && ( (bits >> i) & 1) == 1); 198 | 199 | if (i < 6) { 200 | _modules[i][8] = mod; 201 | } else if (i < 8) { 202 | _modules[i + 1][8] = mod; 203 | } else { 204 | _modules[_moduleCount - 15 + i][8] = mod; 205 | } 206 | } 207 | 208 | // horizontal 209 | for (var i = 0; i < 15; i += 1) { 210 | 211 | var mod = (!test && ( (bits >> i) & 1) == 1); 212 | 213 | if (i < 8) { 214 | _modules[8][_moduleCount - i - 1] = mod; 215 | } else if (i < 9) { 216 | _modules[8][15 - i - 1 + 1] = mod; 217 | } else { 218 | _modules[8][15 - i - 1] = mod; 219 | } 220 | } 221 | 222 | // fixed module 223 | _modules[_moduleCount - 8][8] = (!test); 224 | }; 225 | 226 | var mapData = function(data, maskPattern) { 227 | 228 | var inc = -1; 229 | var row = _moduleCount - 1; 230 | var bitIndex = 7; 231 | var byteIndex = 0; 232 | var maskFunc = QRUtil.getMaskFunction(maskPattern); 233 | 234 | for (var col = _moduleCount - 1; col > 0; col -= 2) { 235 | 236 | if (col == 6) col -= 1; 237 | 238 | while (true) { 239 | 240 | for (var c = 0; c < 2; c += 1) { 241 | 242 | if (_modules[row][col - c] == null) { 243 | 244 | var dark = false; 245 | 246 | if (byteIndex < data.length) { 247 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); 248 | } 249 | 250 | var mask = maskFunc(row, col - c); 251 | 252 | if (mask) { 253 | dark = !dark; 254 | } 255 | 256 | _modules[row][col - c] = dark; 257 | bitIndex -= 1; 258 | 259 | if (bitIndex == -1) { 260 | byteIndex += 1; 261 | bitIndex = 7; 262 | } 263 | } 264 | } 265 | 266 | row += inc; 267 | 268 | if (row < 0 || _moduleCount <= row) { 269 | row -= inc; 270 | inc = -inc; 271 | break; 272 | } 273 | } 274 | } 275 | }; 276 | 277 | var createBytes = function(buffer, rsBlocks) { 278 | 279 | var offset = 0; 280 | 281 | var maxDcCount = 0; 282 | var maxEcCount = 0; 283 | 284 | var dcdata = new Array(rsBlocks.length); 285 | var ecdata = new Array(rsBlocks.length); 286 | 287 | for (var r = 0; r < rsBlocks.length; r += 1) { 288 | 289 | var dcCount = rsBlocks[r].dataCount; 290 | var ecCount = rsBlocks[r].totalCount - dcCount; 291 | 292 | maxDcCount = Math.max(maxDcCount, dcCount); 293 | maxEcCount = Math.max(maxEcCount, ecCount); 294 | 295 | dcdata[r] = new Array(dcCount); 296 | 297 | for (var i = 0; i < dcdata[r].length; i += 1) { 298 | dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; 299 | } 300 | offset += dcCount; 301 | 302 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); 303 | var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); 304 | 305 | var modPoly = rawPoly.mod(rsPoly); 306 | ecdata[r] = new Array(rsPoly.getLength() - 1); 307 | for (var i = 0; i < ecdata[r].length; i += 1) { 308 | var modIndex = i + modPoly.getLength() - ecdata[r].length; 309 | ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; 310 | } 311 | } 312 | 313 | var totalCodeCount = 0; 314 | for (var i = 0; i < rsBlocks.length; i += 1) { 315 | totalCodeCount += rsBlocks[i].totalCount; 316 | } 317 | 318 | var data = new Array(totalCodeCount); 319 | var index = 0; 320 | 321 | for (var i = 0; i < maxDcCount; i += 1) { 322 | for (var r = 0; r < rsBlocks.length; r += 1) { 323 | if (i < dcdata[r].length) { 324 | data[index] = dcdata[r][i]; 325 | index += 1; 326 | } 327 | } 328 | } 329 | 330 | for (var i = 0; i < maxEcCount; i += 1) { 331 | for (var r = 0; r < rsBlocks.length; r += 1) { 332 | if (i < ecdata[r].length) { 333 | data[index] = ecdata[r][i]; 334 | index += 1; 335 | } 336 | } 337 | } 338 | 339 | return data; 340 | }; 341 | 342 | var createData = function(typeNumber, errorCorrectLevel, dataList) { 343 | 344 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); 345 | 346 | var buffer = qrBitBuffer(); 347 | 348 | for (var i = 0; i < dataList.length; i += 1) { 349 | var data = dataList[i]; 350 | buffer.put(data.getMode(), 4); 351 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); 352 | data.write(buffer); 353 | } 354 | 355 | // calc num max data. 356 | var totalDataCount = 0; 357 | for (var i = 0; i < rsBlocks.length; i += 1) { 358 | totalDataCount += rsBlocks[i].dataCount; 359 | } 360 | 361 | if (buffer.getLengthInBits() > totalDataCount * 8) { 362 | throw new Error('code length overflow. (' 363 | + buffer.getLengthInBits() 364 | + '>' 365 | + totalDataCount * 8 366 | + ')'); 367 | } 368 | 369 | // end code 370 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 371 | buffer.put(0, 4); 372 | } 373 | 374 | // padding 375 | while (buffer.getLengthInBits() % 8 != 0) { 376 | buffer.putBit(false); 377 | } 378 | 379 | // padding 380 | while (true) { 381 | 382 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 383 | break; 384 | } 385 | buffer.put(PAD0, 8); 386 | 387 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 388 | break; 389 | } 390 | buffer.put(PAD1, 8); 391 | } 392 | 393 | return createBytes(buffer, rsBlocks); 394 | }; 395 | 396 | _this.addData = function(data) { 397 | var newData = qr8BitByte(data); 398 | _dataList.push(newData); 399 | _dataCache = null; 400 | }; 401 | 402 | _this.isDark = function(row, col) { 403 | if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { 404 | throw new Error(row + ',' + col); 405 | } 406 | return _modules[row][col]; 407 | }; 408 | 409 | _this.getModuleCount = function() { 410 | return _moduleCount; 411 | }; 412 | 413 | _this.make = function() { 414 | makeImpl(false, getBestMaskPattern() ); 415 | }; 416 | 417 | return _this; 418 | }; 419 | 420 | //--------------------------------------------------------------------- 421 | // qrcode.stringToBytes 422 | //--------------------------------------------------------------------- 423 | 424 | // qrcode.stringToBytes = function(s) { 425 | // var bytes = new Array(); 426 | // for (var i = 0; i < s.length; i += 1) { 427 | // var c = s.charCodeAt(i); 428 | // bytes.push(c & 0xff); 429 | // } 430 | // return bytes; 431 | // }; 432 | qrcode.stringToBytes = function(s) { 433 | var bytes = []; 434 | s = s.replace(/\r\n/g, '\n'); 435 | for (var i = 0; i < s.length; i ++) { 436 | var c = s.charCodeAt(i); 437 | if (c < 128) bytes.push(c); 438 | else if (c < 2048) { 439 | bytes.push( 440 | (c >> 6) | 192, 441 | (c & 63) | 128 442 | ); 443 | } else { 444 | bytes.push( 445 | (c >> 12) | 224, 446 | ((c >> 6) & 63) | 128, 447 | (c & 63) | 128 448 | ); 449 | } 450 | } 451 | return bytes; 452 | }; 453 | 454 | //--------------------------------------------------------------------- 455 | // qrcode.createStringToBytes 456 | //--------------------------------------------------------------------- 457 | 458 | /** 459 | * @param unicodeData base64 string of byte array. 460 | * [16bit Unicode],[16bit Bytes], ... 461 | * @param numChars 462 | */ 463 | qrcode.createStringToBytes = function(unicodeData, numChars) { 464 | 465 | // create conversion map. 466 | 467 | var unicodeMap = function() { 468 | 469 | var bin = base64DecodeInputStream(unicodeData); 470 | var read = function() { 471 | var b = bin.read(); 472 | if (b == -1) throw new Error(); 473 | return b; 474 | }; 475 | 476 | var count = 0; 477 | var unicodeMap = {}; 478 | while (true) { 479 | var b0 = bin.read(); 480 | if (b0 == -1) break; 481 | var b1 = read(); 482 | var b2 = read(); 483 | var b3 = read(); 484 | var k = String.fromCharCode( (b0 << 8) | b1); 485 | var v = (b2 << 8) | b3; 486 | unicodeMap[k] = v; 487 | count += 1; 488 | } 489 | if (count != numChars) { 490 | throw new Error(count + ' != ' + numChars); 491 | } 492 | 493 | return unicodeMap; 494 | }(); 495 | 496 | var unknownChar = '?'.charCodeAt(0); 497 | 498 | return function(s) { 499 | var bytes = new Array(); 500 | for (var i = 0; i < s.length; i += 1) { 501 | var c = s.charCodeAt(i); 502 | if (c < 128) { 503 | bytes.push(c); 504 | } else { 505 | var b = unicodeMap[s.charAt(i)]; 506 | if (typeof b == 'number') { 507 | if ( (b & 0xff) == b) { 508 | // 1byte 509 | bytes.push(b); 510 | } else { 511 | // 2bytes 512 | bytes.push(b >>> 8); 513 | bytes.push(b & 0xff); 514 | } 515 | } else { 516 | bytes.push(unknownChar); 517 | } 518 | } 519 | } 520 | return bytes; 521 | }; 522 | }; 523 | 524 | //--------------------------------------------------------------------- 525 | // QRMode 526 | //--------------------------------------------------------------------- 527 | 528 | var QRMode = { 529 | MODE_NUMBER : 1 << 0, 530 | MODE_ALPHA_NUM : 1 << 1, 531 | MODE_8BIT_BYTE : 1 << 2, 532 | MODE_KANJI : 1 << 3 533 | }; 534 | 535 | //--------------------------------------------------------------------- 536 | // QRErrorCorrectLevel 537 | //--------------------------------------------------------------------- 538 | 539 | var QRErrorCorrectLevel = { 540 | L : 1, 541 | M : 0, 542 | Q : 3, 543 | H : 2 544 | }; 545 | 546 | //--------------------------------------------------------------------- 547 | // QRMaskPattern 548 | //--------------------------------------------------------------------- 549 | 550 | var QRMaskPattern = { 551 | PATTERN000 : 0, 552 | PATTERN001 : 1, 553 | PATTERN010 : 2, 554 | PATTERN011 : 3, 555 | PATTERN100 : 4, 556 | PATTERN101 : 5, 557 | PATTERN110 : 6, 558 | PATTERN111 : 7 559 | }; 560 | 561 | //--------------------------------------------------------------------- 562 | // QRUtil 563 | //--------------------------------------------------------------------- 564 | 565 | var QRUtil = function() { 566 | 567 | var PATTERN_POSITION_TABLE = [ 568 | [], 569 | [6, 18], 570 | [6, 22], 571 | [6, 26], 572 | [6, 30], 573 | [6, 34], 574 | [6, 22, 38], 575 | [6, 24, 42], 576 | [6, 26, 46], 577 | [6, 28, 50], 578 | [6, 30, 54], 579 | [6, 32, 58], 580 | [6, 34, 62], 581 | [6, 26, 46, 66], 582 | [6, 26, 48, 70], 583 | [6, 26, 50, 74], 584 | [6, 30, 54, 78], 585 | [6, 30, 56, 82], 586 | [6, 30, 58, 86], 587 | [6, 34, 62, 90], 588 | [6, 28, 50, 72, 94], 589 | [6, 26, 50, 74, 98], 590 | [6, 30, 54, 78, 102], 591 | [6, 28, 54, 80, 106], 592 | [6, 32, 58, 84, 110], 593 | [6, 30, 58, 86, 114], 594 | [6, 34, 62, 90, 118], 595 | [6, 26, 50, 74, 98, 122], 596 | [6, 30, 54, 78, 102, 126], 597 | [6, 26, 52, 78, 104, 130], 598 | [6, 30, 56, 82, 108, 134], 599 | [6, 34, 60, 86, 112, 138], 600 | [6, 30, 58, 86, 114, 142], 601 | [6, 34, 62, 90, 118, 146], 602 | [6, 30, 54, 78, 102, 126, 150], 603 | [6, 24, 50, 76, 102, 128, 154], 604 | [6, 28, 54, 80, 106, 132, 158], 605 | [6, 32, 58, 84, 110, 136, 162], 606 | [6, 26, 54, 82, 110, 138, 166], 607 | [6, 30, 58, 86, 114, 142, 170] 608 | ]; 609 | var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 610 | var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 611 | var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); 612 | 613 | var _this = {}; 614 | 615 | var getBCHDigit = function(data) { 616 | var digit = 0; 617 | while (data != 0) { 618 | digit += 1; 619 | data >>>= 1; 620 | } 621 | return digit; 622 | }; 623 | 624 | _this.getBCHTypeInfo = function(data) { 625 | var d = data << 10; 626 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 627 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 628 | } 629 | return ( (data << 10) | d) ^ G15_MASK; 630 | }; 631 | 632 | _this.getBCHTypeNumber = function(data) { 633 | var d = data << 12; 634 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 635 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 636 | } 637 | return (data << 12) | d; 638 | }; 639 | 640 | _this.getPatternPosition = function(typeNumber) { 641 | return PATTERN_POSITION_TABLE[typeNumber - 1]; 642 | }; 643 | 644 | _this.getMaskFunction = function(maskPattern) { 645 | 646 | switch (maskPattern) { 647 | 648 | case QRMaskPattern.PATTERN000 : 649 | return function(i, j) { return (i + j) % 2 == 0; }; 650 | case QRMaskPattern.PATTERN001 : 651 | return function(i, j) { return i % 2 == 0; }; 652 | case QRMaskPattern.PATTERN010 : 653 | return function(i, j) { return j % 3 == 0; }; 654 | case QRMaskPattern.PATTERN011 : 655 | return function(i, j) { return (i + j) % 3 == 0; }; 656 | case QRMaskPattern.PATTERN100 : 657 | return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; }; 658 | case QRMaskPattern.PATTERN101 : 659 | return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; 660 | case QRMaskPattern.PATTERN110 : 661 | return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; }; 662 | case QRMaskPattern.PATTERN111 : 663 | return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; }; 664 | 665 | default : 666 | throw new Error('bad maskPattern:' + maskPattern); 667 | } 668 | }; 669 | 670 | _this.getErrorCorrectPolynomial = function(errorCorrectLength) { 671 | var a = qrPolynomial([1], 0); 672 | for (var i = 0; i < errorCorrectLength; i += 1) { 673 | a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) ); 674 | } 675 | return a; 676 | }; 677 | 678 | _this.getLengthInBits = function(mode, type) { 679 | 680 | if (1 <= type && type < 10) { 681 | 682 | // 1 - 9 683 | 684 | switch(mode) { 685 | case QRMode.MODE_NUMBER : return 10; 686 | case QRMode.MODE_ALPHA_NUM : return 9; 687 | case QRMode.MODE_8BIT_BYTE : return 8; 688 | case QRMode.MODE_KANJI : return 8; 689 | default : 690 | throw new Error('mode:' + mode); 691 | } 692 | 693 | } else if (type < 27) { 694 | 695 | // 10 - 26 696 | 697 | switch(mode) { 698 | case QRMode.MODE_NUMBER : return 12; 699 | case QRMode.MODE_ALPHA_NUM : return 11; 700 | case QRMode.MODE_8BIT_BYTE : return 16; 701 | case QRMode.MODE_KANJI : return 10; 702 | default : 703 | throw new Error('mode:' + mode); 704 | } 705 | 706 | } else if (type < 41) { 707 | 708 | // 27 - 40 709 | 710 | switch(mode) { 711 | case QRMode.MODE_NUMBER : return 14; 712 | case QRMode.MODE_ALPHA_NUM : return 13; 713 | case QRMode.MODE_8BIT_BYTE : return 16; 714 | case QRMode.MODE_KANJI : return 12; 715 | default : 716 | throw new Error('mode:' + mode); 717 | } 718 | 719 | } else { 720 | throw new Error('type:' + type); 721 | } 722 | }; 723 | 724 | _this.getLostPoint = function(qrcode) { 725 | 726 | var moduleCount = qrcode.getModuleCount(); 727 | 728 | var lostPoint = 0; 729 | 730 | // LEVEL1 731 | 732 | for (var row = 0; row < moduleCount; row += 1) { 733 | for (var col = 0; col < moduleCount; col += 1) { 734 | 735 | var sameCount = 0; 736 | var dark = qrcode.isDark(row, col); 737 | 738 | for (var r = -1; r <= 1; r += 1) { 739 | 740 | if (row + r < 0 || moduleCount <= row + r) { 741 | continue; 742 | } 743 | 744 | for (var c = -1; c <= 1; c += 1) { 745 | 746 | if (col + c < 0 || moduleCount <= col + c) { 747 | continue; 748 | } 749 | 750 | if (r == 0 && c == 0) { 751 | continue; 752 | } 753 | 754 | if (dark == qrcode.isDark(row + r, col + c) ) { 755 | sameCount += 1; 756 | } 757 | } 758 | } 759 | 760 | if (sameCount > 5) { 761 | lostPoint += (3 + sameCount - 5); 762 | } 763 | } 764 | }; 765 | 766 | // LEVEL2 767 | 768 | for (var row = 0; row < moduleCount - 1; row += 1) { 769 | for (var col = 0; col < moduleCount - 1; col += 1) { 770 | var count = 0; 771 | if (qrcode.isDark(row, col) ) count += 1; 772 | if (qrcode.isDark(row + 1, col) ) count += 1; 773 | if (qrcode.isDark(row, col + 1) ) count += 1; 774 | if (qrcode.isDark(row + 1, col + 1) ) count += 1; 775 | if (count == 0 || count == 4) { 776 | lostPoint += 3; 777 | } 778 | } 779 | } 780 | 781 | // LEVEL3 782 | 783 | for (var row = 0; row < moduleCount; row += 1) { 784 | for (var col = 0; col < moduleCount - 6; col += 1) { 785 | if (qrcode.isDark(row, col) 786 | && !qrcode.isDark(row, col + 1) 787 | && qrcode.isDark(row, col + 2) 788 | && qrcode.isDark(row, col + 3) 789 | && qrcode.isDark(row, col + 4) 790 | && !qrcode.isDark(row, col + 5) 791 | && qrcode.isDark(row, col + 6) ) { 792 | lostPoint += 40; 793 | } 794 | } 795 | } 796 | 797 | for (var col = 0; col < moduleCount; col += 1) { 798 | for (var row = 0; row < moduleCount - 6; row += 1) { 799 | if (qrcode.isDark(row, col) 800 | && !qrcode.isDark(row + 1, col) 801 | && qrcode.isDark(row + 2, col) 802 | && qrcode.isDark(row + 3, col) 803 | && qrcode.isDark(row + 4, col) 804 | && !qrcode.isDark(row + 5, col) 805 | && qrcode.isDark(row + 6, col) ) { 806 | lostPoint += 40; 807 | } 808 | } 809 | } 810 | 811 | // LEVEL4 812 | 813 | var darkCount = 0; 814 | 815 | for (var col = 0; col < moduleCount; col += 1) { 816 | for (var row = 0; row < moduleCount; row += 1) { 817 | if (qrcode.isDark(row, col) ) { 818 | darkCount += 1; 819 | } 820 | } 821 | } 822 | 823 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 824 | lostPoint += ratio * 10; 825 | 826 | return lostPoint; 827 | }; 828 | 829 | return _this; 830 | }(); 831 | 832 | //--------------------------------------------------------------------- 833 | // QRMath 834 | //--------------------------------------------------------------------- 835 | 836 | var QRMath = function() { 837 | 838 | var EXP_TABLE = new Array(256); 839 | var LOG_TABLE = new Array(256); 840 | 841 | // initialize tables 842 | for (var i = 0; i < 8; i += 1) { 843 | EXP_TABLE[i] = 1 << i; 844 | } 845 | for (var i = 8; i < 256; i += 1) { 846 | EXP_TABLE[i] = EXP_TABLE[i - 4] 847 | ^ EXP_TABLE[i - 5] 848 | ^ EXP_TABLE[i - 6] 849 | ^ EXP_TABLE[i - 8]; 850 | } 851 | for (var i = 0; i < 255; i += 1) { 852 | LOG_TABLE[EXP_TABLE[i] ] = i; 853 | } 854 | 855 | var _this = {}; 856 | 857 | _this.glog = function(n) { 858 | 859 | if (n < 1) { 860 | throw new Error('glog(' + n + ')'); 861 | } 862 | 863 | return LOG_TABLE[n]; 864 | }; 865 | 866 | _this.gexp = function(n) { 867 | 868 | while (n < 0) { 869 | n += 255; 870 | } 871 | 872 | while (n >= 256) { 873 | n -= 255; 874 | } 875 | 876 | return EXP_TABLE[n]; 877 | }; 878 | 879 | return _this; 880 | }(); 881 | 882 | //--------------------------------------------------------------------- 883 | // qrPolynomial 884 | //--------------------------------------------------------------------- 885 | 886 | function qrPolynomial(num, shift) { 887 | 888 | if (typeof num.length == 'undefined') { 889 | throw new Error(num.length + '/' + shift); 890 | } 891 | 892 | var _num = function() { 893 | var offset = 0; 894 | while (offset < num.length && num[offset] == 0) { 895 | offset += 1; 896 | } 897 | var _num = new Array(num.length - offset + shift); 898 | for (var i = 0; i < num.length - offset; i += 1) { 899 | _num[i] = num[i + offset]; 900 | } 901 | return _num; 902 | }(); 903 | 904 | var _this = {}; 905 | 906 | _this.getAt = function(index) { 907 | return _num[index]; 908 | }; 909 | 910 | _this.getLength = function() { 911 | return _num.length; 912 | }; 913 | 914 | _this.multiply = function(e) { 915 | 916 | var num = new Array(_this.getLength() + e.getLength() - 1); 917 | 918 | for (var i = 0; i < _this.getLength(); i += 1) { 919 | for (var j = 0; j < e.getLength(); j += 1) { 920 | num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) ); 921 | } 922 | } 923 | 924 | return qrPolynomial(num, 0); 925 | }; 926 | 927 | _this.mod = function(e) { 928 | 929 | if (_this.getLength() - e.getLength() < 0) { 930 | return _this; 931 | } 932 | 933 | var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) ); 934 | 935 | var num = new Array(_this.getLength() ); 936 | for (var i = 0; i < _this.getLength(); i += 1) { 937 | num[i] = _this.getAt(i); 938 | } 939 | 940 | for (var i = 0; i < e.getLength(); i += 1) { 941 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 942 | } 943 | 944 | // recursive call 945 | return qrPolynomial(num, 0).mod(e); 946 | }; 947 | 948 | return _this; 949 | }; 950 | 951 | //--------------------------------------------------------------------- 952 | // QRRSBlock 953 | //--------------------------------------------------------------------- 954 | 955 | var QRRSBlock = function() { 956 | 957 | var RS_BLOCK_TABLE = [ 958 | 959 | // L 960 | // M 961 | // Q 962 | // H 963 | 964 | // 1 965 | [1, 26, 19], 966 | [1, 26, 16], 967 | [1, 26, 13], 968 | [1, 26, 9], 969 | 970 | // 2 971 | [1, 44, 34], 972 | [1, 44, 28], 973 | [1, 44, 22], 974 | [1, 44, 16], 975 | 976 | // 3 977 | [1, 70, 55], 978 | [1, 70, 44], 979 | [2, 35, 17], 980 | [2, 35, 13], 981 | 982 | // 4 983 | [1, 100, 80], 984 | [2, 50, 32], 985 | [2, 50, 24], 986 | [4, 25, 9], 987 | 988 | // 5 989 | [1, 134, 108], 990 | [2, 67, 43], 991 | [2, 33, 15, 2, 34, 16], 992 | [2, 33, 11, 2, 34, 12], 993 | 994 | // 6 995 | [2, 86, 68], 996 | [4, 43, 27], 997 | [4, 43, 19], 998 | [4, 43, 15], 999 | 1000 | // 7 1001 | [2, 98, 78], 1002 | [4, 49, 31], 1003 | [2, 32, 14, 4, 33, 15], 1004 | [4, 39, 13, 1, 40, 14], 1005 | 1006 | // 8 1007 | [2, 121, 97], 1008 | [2, 60, 38, 2, 61, 39], 1009 | [4, 40, 18, 2, 41, 19], 1010 | [4, 40, 14, 2, 41, 15], 1011 | 1012 | // 9 1013 | [2, 146, 116], 1014 | [3, 58, 36, 2, 59, 37], 1015 | [4, 36, 16, 4, 37, 17], 1016 | [4, 36, 12, 4, 37, 13], 1017 | 1018 | // 10 1019 | [2, 86, 68, 2, 87, 69], 1020 | [4, 69, 43, 1, 70, 44], 1021 | [6, 43, 19, 2, 44, 20], 1022 | [6, 43, 15, 2, 44, 16] 1023 | 1024 | // 11 1025 | [4, 101, 81], 1026 | [1, 80, 50, 4, 81, 51], 1027 | [4, 50, 22, 4, 51, 23], 1028 | [3, 36, 12, 8, 37, 13], 1029 | 1030 | // 12 1031 | [2, 116, 92, 2, 117, 93], 1032 | [6, 58, 36, 2, 59, 37], 1033 | [4, 46, 20, 6, 47, 21], 1034 | [7, 42, 14, 4, 43, 15], 1035 | 1036 | // 13 1037 | [4, 133, 107], 1038 | [8, 59, 37, 1, 60, 38], 1039 | [8, 44, 20, 4, 45, 21], 1040 | [12, 33, 11, 4, 34, 12], 1041 | 1042 | // 14 1043 | [3, 145, 115, 1, 146, 116], 1044 | [4, 64, 40, 5, 65, 41], 1045 | [11, 36, 16, 5, 37, 17], 1046 | [11, 36, 12, 5, 37, 13], 1047 | 1048 | // 15 1049 | [5, 109, 87, 1, 110, 88], 1050 | [5, 65, 41, 5, 66, 42], 1051 | [5, 54, 24, 7, 55, 25], 1052 | [11, 36, 12, 7, 37, 13], 1053 | 1054 | // 16 1055 | [5, 122, 98, 1, 123, 99], 1056 | [7, 73, 45, 3, 74, 46], 1057 | [15, 43, 19, 2, 44, 20], 1058 | [3, 45, 15, 13, 46, 16], 1059 | 1060 | // 17 1061 | [1, 135, 107, 5, 136, 108], 1062 | [10, 74, 46, 1, 75, 47], 1063 | [1, 50, 22, 15, 51, 23], 1064 | [2, 42, 14, 17, 43, 15], 1065 | 1066 | // 18 1067 | [5, 150, 120, 1, 151, 121], 1068 | [9, 69, 43, 4, 70, 44], 1069 | [17, 50, 22, 1, 51, 23], 1070 | [2, 42, 14, 19, 43, 15], 1071 | 1072 | // 19 1073 | [3, 141, 113, 4, 142, 114], 1074 | [3, 70, 44, 11, 71, 45], 1075 | [17, 47, 21, 4, 48, 22], 1076 | [9, 39, 13, 16, 40, 14], 1077 | 1078 | // 20 1079 | [3, 135, 107, 5, 136, 108], 1080 | [3, 67, 41, 13, 68, 42], 1081 | [15, 54, 24, 5, 55, 25], 1082 | [15, 43, 15, 10, 44, 16], 1083 | 1084 | // 21 1085 | [4, 144, 116, 4, 145, 117], 1086 | [17, 68, 42], 1087 | [17, 50, 22, 6, 51, 23], 1088 | [19, 46, 16, 6, 47, 17], 1089 | 1090 | // 22 1091 | [2, 139, 111, 7, 140, 112], 1092 | [17, 74, 46], 1093 | [7, 54, 24, 16, 55, 25], 1094 | [34, 37, 13], 1095 | 1096 | // 23 1097 | [4, 151, 121, 5, 152, 122], 1098 | [4, 75, 47, 14, 76, 48], 1099 | [11, 54, 24, 14, 55, 25], 1100 | [16, 45, 15, 14, 46, 16], 1101 | 1102 | // 24 1103 | [6, 147, 117, 4, 148, 118], 1104 | [6, 73, 45, 14, 74, 46], 1105 | [11, 54, 24, 16, 55, 25], 1106 | [30, 46, 16, 2, 47, 17], 1107 | 1108 | // 25 1109 | [8, 132, 106, 4, 133, 107], 1110 | [8, 75, 47, 13, 76, 48], 1111 | [7, 54, 24, 22, 55, 25], 1112 | [22, 45, 15, 13, 46, 16], 1113 | 1114 | // 26 1115 | [10, 142, 114, 2, 143, 115], 1116 | [19, 74, 46, 4, 75, 47], 1117 | [28, 50, 22, 6, 51, 23], 1118 | [33, 46, 16, 4, 47, 17], 1119 | 1120 | // 27 1121 | [8, 152, 122, 4, 153, 123], 1122 | [22, 73, 45, 3, 74, 46], 1123 | [8, 53, 23, 26, 54, 24], 1124 | [12, 45, 15, 28, 46, 16], 1125 | 1126 | // 28 1127 | [3, 147, 117, 10, 148, 118], 1128 | [3, 73, 45, 23, 74, 46], 1129 | [4, 54, 24, 31, 55, 25], 1130 | [11, 45, 15, 31, 46, 16], 1131 | 1132 | // 29 1133 | [7, 146, 116, 7, 147, 117], 1134 | [21, 73, 45, 7, 74, 46], 1135 | [1, 53, 23, 37, 54, 24], 1136 | [19, 45, 15, 26, 46, 16], 1137 | 1138 | // 30 1139 | [5, 145, 115, 10, 146, 116], 1140 | [19, 75, 47, 10, 76, 48], 1141 | [15, 54, 24, 25, 55, 25], 1142 | [23, 45, 15, 25, 46, 16], 1143 | 1144 | // 31 1145 | [13, 145, 115, 3, 146, 116], 1146 | [2, 74, 46, 29, 75, 47], 1147 | [42, 54, 24, 1, 55, 25], 1148 | [23, 45, 15, 28, 46, 16], 1149 | 1150 | // 32 1151 | [17, 145, 115], 1152 | [10, 74, 46, 23, 75, 47], 1153 | [10, 54, 24, 35, 55, 25], 1154 | [19, 45, 15, 35, 46, 16], 1155 | 1156 | // 33 1157 | [17, 145, 115, 1, 146, 116], 1158 | [14, 74, 46, 21, 75, 47], 1159 | [29, 54, 24, 19, 55, 25], 1160 | [11, 45, 15, 46, 46, 16], 1161 | 1162 | // 34 1163 | [13, 145, 115, 6, 146, 116], 1164 | [14, 74, 46, 23, 75, 47], 1165 | [44, 54, 24, 7, 55, 25], 1166 | [59, 46, 16, 1, 47, 17], 1167 | 1168 | // 35 1169 | [12, 151, 121, 7, 152, 122], 1170 | [12, 75, 47, 26, 76, 48], 1171 | [39, 54, 24, 14, 55, 25], 1172 | [22, 45, 15, 41, 46, 16], 1173 | 1174 | // 36 1175 | [6, 151, 121, 14, 152, 122], 1176 | [6, 75, 47, 34, 76, 48], 1177 | [46, 54, 24, 10, 55, 25], 1178 | [2, 45, 15, 64, 46, 16], 1179 | 1180 | // 37 1181 | [17, 152, 122, 4, 153, 123], 1182 | [29, 74, 46, 14, 75, 47], 1183 | [49, 54, 24, 10, 55, 25], 1184 | [24, 45, 15, 46, 46, 16], 1185 | 1186 | // 38 1187 | [4, 152, 122, 18, 153, 123], 1188 | [13, 74, 46, 32, 75, 47], 1189 | [48, 54, 24, 14, 55, 25], 1190 | [42, 45, 15, 32, 46, 16], 1191 | 1192 | // 39 1193 | [20, 147, 117, 4, 148, 118], 1194 | [40, 75, 47, 7, 76, 48], 1195 | [43, 54, 24, 22, 55, 25], 1196 | [10, 45, 15, 67, 46, 16], 1197 | 1198 | // 40 1199 | [19, 148, 118, 6, 149, 119], 1200 | [18, 75, 47, 31, 76, 48], 1201 | [34, 54, 24, 34, 55, 25], 1202 | [20, 45, 15, 61, 46, 16] 1203 | ]; 1204 | 1205 | var qrRSBlock = function(totalCount, dataCount) { 1206 | var _this = {}; 1207 | _this.totalCount = totalCount; 1208 | _this.dataCount = dataCount; 1209 | return _this; 1210 | }; 1211 | 1212 | var _this = {}; 1213 | 1214 | var getRsBlockTable = function(typeNumber, errorCorrectLevel) { 1215 | 1216 | switch(errorCorrectLevel) { 1217 | case QRErrorCorrectLevel.L : 1218 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 1219 | case QRErrorCorrectLevel.M : 1220 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 1221 | case QRErrorCorrectLevel.Q : 1222 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 1223 | case QRErrorCorrectLevel.H : 1224 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 1225 | default : 1226 | return undefined; 1227 | } 1228 | }; 1229 | 1230 | _this.getRSBlocks = function(typeNumber, errorCorrectLevel) { 1231 | 1232 | var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel); 1233 | 1234 | if (typeof rsBlock == 'undefined') { 1235 | throw new Error('bad rs block @ typeNumber:' + typeNumber + 1236 | '/errorCorrectLevel:' + errorCorrectLevel); 1237 | } 1238 | 1239 | var length = rsBlock.length / 3; 1240 | 1241 | var list = new Array(); 1242 | 1243 | for (var i = 0; i < length; i += 1) { 1244 | 1245 | var count = rsBlock[i * 3 + 0]; 1246 | var totalCount = rsBlock[i * 3 + 1]; 1247 | var dataCount = rsBlock[i * 3 + 2]; 1248 | 1249 | for (var j = 0; j < count; j += 1) { 1250 | list.push(qrRSBlock(totalCount, dataCount) ); 1251 | } 1252 | } 1253 | 1254 | return list; 1255 | }; 1256 | 1257 | return _this; 1258 | }(); 1259 | 1260 | //--------------------------------------------------------------------- 1261 | // qrBitBuffer 1262 | //--------------------------------------------------------------------- 1263 | 1264 | var qrBitBuffer = function() { 1265 | 1266 | var _buffer = new Array(); 1267 | var _length = 0; 1268 | 1269 | var _this = {}; 1270 | 1271 | _this.getBuffer = function() { 1272 | return _buffer; 1273 | }; 1274 | 1275 | _this.getAt = function(index) { 1276 | var bufIndex = Math.floor(index / 8); 1277 | return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; 1278 | }; 1279 | 1280 | _this.put = function(num, length) { 1281 | for (var i = 0; i < length; i += 1) { 1282 | _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 1283 | } 1284 | }; 1285 | 1286 | _this.getLengthInBits = function() { 1287 | return _length; 1288 | }; 1289 | 1290 | _this.putBit = function(bit) { 1291 | 1292 | var bufIndex = Math.floor(_length / 8); 1293 | if (_buffer.length <= bufIndex) { 1294 | _buffer.push(0); 1295 | } 1296 | 1297 | if (bit) { 1298 | _buffer[bufIndex] |= (0x80 >>> (_length % 8) ); 1299 | } 1300 | 1301 | _length += 1; 1302 | }; 1303 | 1304 | return _this; 1305 | }; 1306 | 1307 | //--------------------------------------------------------------------- 1308 | // qr8BitByte 1309 | //--------------------------------------------------------------------- 1310 | 1311 | var qr8BitByte = function(data) { 1312 | 1313 | var _mode = QRMode.MODE_8BIT_BYTE; 1314 | var _data = data; 1315 | var _bytes = qrcode.stringToBytes(data); 1316 | 1317 | var _this = {}; 1318 | 1319 | _this.getMode = function() { 1320 | return _mode; 1321 | }; 1322 | 1323 | _this.getLength = function(buffer) { 1324 | return _bytes.length; 1325 | }; 1326 | 1327 | _this.write = function(buffer) { 1328 | for (var i = 0; i < _bytes.length; i += 1) { 1329 | buffer.put(_bytes[i], 8); 1330 | } 1331 | }; 1332 | 1333 | return _this; 1334 | }; 1335 | 1336 | //--------------------------------------------------------------------- 1337 | // returns qrcode function. 1338 | 1339 | return qrcode; 1340 | }(); 1341 | -------------------------------------------------------------------------------- /scripts/qrcode.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // 3 | // QR Code Generator for JavaScript 4 | // 5 | // Copyright (c) 2009 Kazuhiko Arase 6 | // 7 | // URL: http://www.d-project.com/ 8 | // 9 | // Licensed under the MIT license: 10 | // http://www.opensource.org/licenses/mit-license.php 11 | // 12 | // The word 'QR Code' is registered trademark of 13 | // DENSO WAVE INCORPORATED 14 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 15 | // 16 | //--------------------------------------------------------------------- 17 | 18 | var qrcode = function() { 19 | 20 | //--------------------------------------------------------------------- 21 | // qrcode 22 | //--------------------------------------------------------------------- 23 | 24 | /** 25 | * qrcode 26 | * @param typeNumber 1 to 40 27 | * @param errorCorrectLevel 'L','M','Q','H' 28 | */ 29 | var qrcode = function(typeNumber, errorCorrectLevel) { 30 | 31 | var PAD0 = 0xEC; 32 | var PAD1 = 0x11; 33 | 34 | var _typeNumber = typeNumber; 35 | var _errorCorrectLevel = QRErrorCorrectLevel[errorCorrectLevel]; 36 | var _modules = null; 37 | var _moduleCount = 0; 38 | var _dataCache = null; 39 | var _dataList = new Array(); 40 | 41 | var _this = {}; 42 | 43 | var makeImpl = function(test, maskPattern) { 44 | 45 | _moduleCount = _typeNumber * 4 + 17; 46 | _modules = function(moduleCount) { 47 | var modules = new Array(moduleCount); 48 | for (var row = 0; row < moduleCount; row += 1) { 49 | modules[row] = new Array(moduleCount); 50 | for (var col = 0; col < moduleCount; col += 1) { 51 | modules[row][col] = null; 52 | } 53 | } 54 | return modules; 55 | }(_moduleCount); 56 | 57 | setupPositionProbePattern(0, 0); 58 | setupPositionProbePattern(_moduleCount - 7, 0); 59 | setupPositionProbePattern(0, _moduleCount - 7); 60 | setupPositionAdjustPattern(); 61 | setupTimingPattern(); 62 | setupTypeInfo(test, maskPattern); 63 | 64 | if (_typeNumber >= 7) { 65 | setupTypeNumber(test); 66 | } 67 | 68 | if (_dataCache == null) { 69 | _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList); 70 | } 71 | 72 | mapData(_dataCache, maskPattern); 73 | }; 74 | 75 | var setupPositionProbePattern = function(row, col) { 76 | 77 | for (var r = -1; r <= 7; r += 1) { 78 | 79 | if (row + r <= -1 || _moduleCount <= row + r) continue; 80 | 81 | for (var c = -1; c <= 7; c += 1) { 82 | 83 | if (col + c <= -1 || _moduleCount <= col + c) continue; 84 | 85 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) 86 | || (0 <= c && c <= 6 && (r == 0 || r == 6) ) 87 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { 88 | _modules[row + r][col + c] = true; 89 | } else { 90 | _modules[row + r][col + c] = false; 91 | } 92 | } 93 | } 94 | }; 95 | 96 | var getBestMaskPattern = function() { 97 | 98 | var minLostPoint = 0; 99 | var pattern = 0; 100 | 101 | for (var i = 0; i < 8; i += 1) { 102 | 103 | makeImpl(true, i); 104 | 105 | var lostPoint = QRUtil.getLostPoint(_this); 106 | 107 | if (i == 0 || minLostPoint > lostPoint) { 108 | minLostPoint = lostPoint; 109 | pattern = i; 110 | } 111 | } 112 | 113 | return pattern; 114 | }; 115 | 116 | var setupTimingPattern = function() { 117 | 118 | for (var r = 8; r < _moduleCount - 8; r += 1) { 119 | if (_modules[r][6] != null) { 120 | continue; 121 | } 122 | _modules[r][6] = (r % 2 == 0); 123 | } 124 | 125 | for (var c = 8; c < _moduleCount - 8; c += 1) { 126 | if (_modules[6][c] != null) { 127 | continue; 128 | } 129 | _modules[6][c] = (c % 2 == 0); 130 | } 131 | }; 132 | 133 | var setupPositionAdjustPattern = function() { 134 | 135 | var pos = QRUtil.getPatternPosition(_typeNumber); 136 | 137 | for (var i = 0; i < pos.length; i += 1) { 138 | 139 | for (var j = 0; j < pos.length; j += 1) { 140 | 141 | var row = pos[i]; 142 | var col = pos[j]; 143 | 144 | if (_modules[row][col] != null) { 145 | continue; 146 | } 147 | 148 | for (var r = -2; r <= 2; r += 1) { 149 | 150 | for (var c = -2; c <= 2; c += 1) { 151 | 152 | if (r == -2 || r == 2 || c == -2 || c == 2 153 | || (r == 0 && c == 0) ) { 154 | _modules[row + r][col + c] = true; 155 | } else { 156 | _modules[row + r][col + c] = false; 157 | } 158 | } 159 | } 160 | } 161 | } 162 | }; 163 | 164 | var setupTypeNumber = function(test) { 165 | 166 | var bits = QRUtil.getBCHTypeNumber(_typeNumber); 167 | 168 | for (var i = 0; i < 18; i += 1) { 169 | var mod = (!test && ( (bits >> i) & 1) == 1); 170 | _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod; 171 | } 172 | 173 | for (var i = 0; i < 18; i += 1) { 174 | var mod = (!test && ( (bits >> i) & 1) == 1); 175 | _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod; 176 | } 177 | }; 178 | 179 | var setupTypeInfo = function(test, maskPattern) { 180 | 181 | var data = (_errorCorrectLevel << 3) | maskPattern; 182 | var bits = QRUtil.getBCHTypeInfo(data); 183 | 184 | // vertical 185 | for (var i = 0; i < 15; i += 1) { 186 | 187 | var mod = (!test && ( (bits >> i) & 1) == 1); 188 | 189 | if (i < 6) { 190 | _modules[i][8] = mod; 191 | } else if (i < 8) { 192 | _modules[i + 1][8] = mod; 193 | } else { 194 | _modules[_moduleCount - 15 + i][8] = mod; 195 | } 196 | } 197 | 198 | // horizontal 199 | for (var i = 0; i < 15; i += 1) { 200 | 201 | var mod = (!test && ( (bits >> i) & 1) == 1); 202 | 203 | if (i < 8) { 204 | _modules[8][_moduleCount - i - 1] = mod; 205 | } else if (i < 9) { 206 | _modules[8][15 - i - 1 + 1] = mod; 207 | } else { 208 | _modules[8][15 - i - 1] = mod; 209 | } 210 | } 211 | 212 | // fixed module 213 | _modules[_moduleCount - 8][8] = (!test); 214 | }; 215 | 216 | var mapData = function(data, maskPattern) { 217 | 218 | var inc = -1; 219 | var row = _moduleCount - 1; 220 | var bitIndex = 7; 221 | var byteIndex = 0; 222 | var maskFunc = QRUtil.getMaskFunction(maskPattern); 223 | 224 | for (var col = _moduleCount - 1; col > 0; col -= 2) { 225 | 226 | if (col == 6) col -= 1; 227 | 228 | while (true) { 229 | 230 | for (var c = 0; c < 2; c += 1) { 231 | 232 | if (_modules[row][col - c] == null) { 233 | 234 | var dark = false; 235 | 236 | if (byteIndex < data.length) { 237 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); 238 | } 239 | 240 | var mask = maskFunc(row, col - c); 241 | 242 | if (mask) { 243 | dark = !dark; 244 | } 245 | 246 | _modules[row][col - c] = dark; 247 | bitIndex -= 1; 248 | 249 | if (bitIndex == -1) { 250 | byteIndex += 1; 251 | bitIndex = 7; 252 | } 253 | } 254 | } 255 | 256 | row += inc; 257 | 258 | if (row < 0 || _moduleCount <= row) { 259 | row -= inc; 260 | inc = -inc; 261 | break; 262 | } 263 | } 264 | } 265 | }; 266 | 267 | var createBytes = function(buffer, rsBlocks) { 268 | 269 | var offset = 0; 270 | 271 | var maxDcCount = 0; 272 | var maxEcCount = 0; 273 | 274 | var dcdata = new Array(rsBlocks.length); 275 | var ecdata = new Array(rsBlocks.length); 276 | 277 | for (var r = 0; r < rsBlocks.length; r += 1) { 278 | 279 | var dcCount = rsBlocks[r].dataCount; 280 | var ecCount = rsBlocks[r].totalCount - dcCount; 281 | 282 | maxDcCount = Math.max(maxDcCount, dcCount); 283 | maxEcCount = Math.max(maxEcCount, ecCount); 284 | 285 | dcdata[r] = new Array(dcCount); 286 | 287 | for (var i = 0; i < dcdata[r].length; i += 1) { 288 | dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset]; 289 | } 290 | offset += dcCount; 291 | 292 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); 293 | var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1); 294 | 295 | var modPoly = rawPoly.mod(rsPoly); 296 | ecdata[r] = new Array(rsPoly.getLength() - 1); 297 | for (var i = 0; i < ecdata[r].length; i += 1) { 298 | var modIndex = i + modPoly.getLength() - ecdata[r].length; 299 | ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0; 300 | } 301 | } 302 | 303 | var totalCodeCount = 0; 304 | for (var i = 0; i < rsBlocks.length; i += 1) { 305 | totalCodeCount += rsBlocks[i].totalCount; 306 | } 307 | 308 | var data = new Array(totalCodeCount); 309 | var index = 0; 310 | 311 | for (var i = 0; i < maxDcCount; i += 1) { 312 | for (var r = 0; r < rsBlocks.length; r += 1) { 313 | if (i < dcdata[r].length) { 314 | data[index] = dcdata[r][i]; 315 | index += 1; 316 | } 317 | } 318 | } 319 | 320 | for (var i = 0; i < maxEcCount; i += 1) { 321 | for (var r = 0; r < rsBlocks.length; r += 1) { 322 | if (i < ecdata[r].length) { 323 | data[index] = ecdata[r][i]; 324 | index += 1; 325 | } 326 | } 327 | } 328 | 329 | return data; 330 | }; 331 | 332 | var createData = function(typeNumber, errorCorrectLevel, dataList) { 333 | 334 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); 335 | 336 | var buffer = qrBitBuffer(); 337 | 338 | for (var i = 0; i < dataList.length; i += 1) { 339 | var data = dataList[i]; 340 | buffer.put(data.getMode(), 4); 341 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) ); 342 | data.write(buffer); 343 | } 344 | 345 | // calc num max data. 346 | var totalDataCount = 0; 347 | for (var i = 0; i < rsBlocks.length; i += 1) { 348 | totalDataCount += rsBlocks[i].dataCount; 349 | } 350 | 351 | if (buffer.getLengthInBits() > totalDataCount * 8) { 352 | throw new Error('code length overflow. (' 353 | + buffer.getLengthInBits() 354 | + '>' 355 | + totalDataCount * 8 356 | + ')'); 357 | } 358 | 359 | // end code 360 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 361 | buffer.put(0, 4); 362 | } 363 | 364 | // padding 365 | while (buffer.getLengthInBits() % 8 != 0) { 366 | buffer.putBit(false); 367 | } 368 | 369 | // padding 370 | while (true) { 371 | 372 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 373 | break; 374 | } 375 | buffer.put(PAD0, 8); 376 | 377 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 378 | break; 379 | } 380 | buffer.put(PAD1, 8); 381 | } 382 | 383 | return createBytes(buffer, rsBlocks); 384 | }; 385 | 386 | _this.addData = function(data) { 387 | var newData = qr8BitByte(data); 388 | _dataList.push(newData); 389 | _dataCache = null; 390 | }; 391 | 392 | _this.isDark = function(row, col) { 393 | if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) { 394 | throw new Error(row + ',' + col); 395 | } 396 | return _modules[row][col]; 397 | }; 398 | 399 | _this.getModuleCount = function() { 400 | return _moduleCount; 401 | }; 402 | 403 | _this.make = function() { 404 | makeImpl(false, getBestMaskPattern() ); 405 | }; 406 | 407 | _this.createTableTag = function(cellSize, margin) { 408 | 409 | cellSize = cellSize || 2; 410 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 411 | 412 | var qrHtml = ''; 413 | 414 | qrHtml += ''; 419 | qrHtml += ''; 420 | 421 | for (var r = 0; r < _this.getModuleCount(); r += 1) { 422 | 423 | qrHtml += ''; 424 | 425 | for (var c = 0; c < _this.getModuleCount(); c += 1) { 426 | qrHtml += ''; 439 | } 440 | 441 | qrHtml += ''; 442 | qrHtml += '
'; 436 | } 437 | 438 | qrHtml += '
'; 443 | 444 | return qrHtml; 445 | }; 446 | 447 | _this.createSvgTag = function(cellSize, margin) { 448 | 449 | cellSize = cellSize || 2; 450 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin; 451 | var size = _this.getModuleCount() * cellSize + margin * 2; 452 | var c, mc, r, mr, qrSvg='', rect; 453 | 454 | rect = 'l' + cellSize + ',0 0,' + cellSize + 455 | ' -' + cellSize + ',0 0,-' + cellSize + 'z '; 456 | 457 | qrSvg += '>> 8); 575 | bytes.push(b & 0xff); 576 | } 577 | } else { 578 | bytes.push(unknownChar); 579 | } 580 | } 581 | } 582 | return bytes; 583 | }; 584 | }; 585 | 586 | //--------------------------------------------------------------------- 587 | // QRMode 588 | //--------------------------------------------------------------------- 589 | 590 | var QRMode = { 591 | MODE_NUMBER : 1 << 0, 592 | MODE_ALPHA_NUM : 1 << 1, 593 | MODE_8BIT_BYTE : 1 << 2, 594 | MODE_KANJI : 1 << 3 595 | }; 596 | 597 | //--------------------------------------------------------------------- 598 | // QRErrorCorrectLevel 599 | //--------------------------------------------------------------------- 600 | 601 | var QRErrorCorrectLevel = { 602 | L : 1, 603 | M : 0, 604 | Q : 3, 605 | H : 2 606 | }; 607 | 608 | //--------------------------------------------------------------------- 609 | // QRMaskPattern 610 | //--------------------------------------------------------------------- 611 | 612 | var QRMaskPattern = { 613 | PATTERN000 : 0, 614 | PATTERN001 : 1, 615 | PATTERN010 : 2, 616 | PATTERN011 : 3, 617 | PATTERN100 : 4, 618 | PATTERN101 : 5, 619 | PATTERN110 : 6, 620 | PATTERN111 : 7 621 | }; 622 | 623 | //--------------------------------------------------------------------- 624 | // QRUtil 625 | //--------------------------------------------------------------------- 626 | 627 | var QRUtil = function() { 628 | 629 | var PATTERN_POSITION_TABLE = [ 630 | [], 631 | [6, 18], 632 | [6, 22], 633 | [6, 26], 634 | [6, 30], 635 | [6, 34], 636 | [6, 22, 38], 637 | [6, 24, 42], 638 | [6, 26, 46], 639 | [6, 28, 50], 640 | [6, 30, 54], 641 | [6, 32, 58], 642 | [6, 34, 62], 643 | [6, 26, 46, 66], 644 | [6, 26, 48, 70], 645 | [6, 26, 50, 74], 646 | [6, 30, 54, 78], 647 | [6, 30, 56, 82], 648 | [6, 30, 58, 86], 649 | [6, 34, 62, 90], 650 | [6, 28, 50, 72, 94], 651 | [6, 26, 50, 74, 98], 652 | [6, 30, 54, 78, 102], 653 | [6, 28, 54, 80, 106], 654 | [6, 32, 58, 84, 110], 655 | [6, 30, 58, 86, 114], 656 | [6, 34, 62, 90, 118], 657 | [6, 26, 50, 74, 98, 122], 658 | [6, 30, 54, 78, 102, 126], 659 | [6, 26, 52, 78, 104, 130], 660 | [6, 30, 56, 82, 108, 134], 661 | [6, 34, 60, 86, 112, 138], 662 | [6, 30, 58, 86, 114, 142], 663 | [6, 34, 62, 90, 118, 146], 664 | [6, 30, 54, 78, 102, 126, 150], 665 | [6, 24, 50, 76, 102, 128, 154], 666 | [6, 28, 54, 80, 106, 132, 158], 667 | [6, 32, 58, 84, 110, 136, 162], 668 | [6, 26, 54, 82, 110, 138, 166], 669 | [6, 30, 58, 86, 114, 142, 170] 670 | ]; 671 | var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0); 672 | var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0); 673 | var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1); 674 | 675 | var _this = {}; 676 | 677 | var getBCHDigit = function(data) { 678 | var digit = 0; 679 | while (data != 0) { 680 | digit += 1; 681 | data >>>= 1; 682 | } 683 | return digit; 684 | }; 685 | 686 | _this.getBCHTypeInfo = function(data) { 687 | var d = data << 10; 688 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) { 689 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) ); 690 | } 691 | return ( (data << 10) | d) ^ G15_MASK; 692 | }; 693 | 694 | _this.getBCHTypeNumber = function(data) { 695 | var d = data << 12; 696 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) { 697 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) ); 698 | } 699 | return (data << 12) | d; 700 | }; 701 | 702 | _this.getPatternPosition = function(typeNumber) { 703 | return PATTERN_POSITION_TABLE[typeNumber - 1]; 704 | }; 705 | 706 | _this.getMaskFunction = function(maskPattern) { 707 | 708 | switch (maskPattern) { 709 | 710 | case QRMaskPattern.PATTERN000 : 711 | return function(i, j) { return (i + j) % 2 == 0; }; 712 | case QRMaskPattern.PATTERN001 : 713 | return function(i, j) { return i % 2 == 0; }; 714 | case QRMaskPattern.PATTERN010 : 715 | return function(i, j) { return j % 3 == 0; }; 716 | case QRMaskPattern.PATTERN011 : 717 | return function(i, j) { return (i + j) % 3 == 0; }; 718 | case QRMaskPattern.PATTERN100 : 719 | return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; }; 720 | case QRMaskPattern.PATTERN101 : 721 | return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; }; 722 | case QRMaskPattern.PATTERN110 : 723 | return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; }; 724 | case QRMaskPattern.PATTERN111 : 725 | return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; }; 726 | 727 | default : 728 | throw new Error('bad maskPattern:' + maskPattern); 729 | } 730 | }; 731 | 732 | _this.getErrorCorrectPolynomial = function(errorCorrectLength) { 733 | var a = qrPolynomial([1], 0); 734 | for (var i = 0; i < errorCorrectLength; i += 1) { 735 | a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) ); 736 | } 737 | return a; 738 | }; 739 | 740 | _this.getLengthInBits = function(mode, type) { 741 | 742 | if (1 <= type && type < 10) { 743 | 744 | // 1 - 9 745 | 746 | switch(mode) { 747 | case QRMode.MODE_NUMBER : return 10; 748 | case QRMode.MODE_ALPHA_NUM : return 9; 749 | case QRMode.MODE_8BIT_BYTE : return 8; 750 | case QRMode.MODE_KANJI : return 8; 751 | default : 752 | throw new Error('mode:' + mode); 753 | } 754 | 755 | } else if (type < 27) { 756 | 757 | // 10 - 26 758 | 759 | switch(mode) { 760 | case QRMode.MODE_NUMBER : return 12; 761 | case QRMode.MODE_ALPHA_NUM : return 11; 762 | case QRMode.MODE_8BIT_BYTE : return 16; 763 | case QRMode.MODE_KANJI : return 10; 764 | default : 765 | throw new Error('mode:' + mode); 766 | } 767 | 768 | } else if (type < 41) { 769 | 770 | // 27 - 40 771 | 772 | switch(mode) { 773 | case QRMode.MODE_NUMBER : return 14; 774 | case QRMode.MODE_ALPHA_NUM : return 13; 775 | case QRMode.MODE_8BIT_BYTE : return 16; 776 | case QRMode.MODE_KANJI : return 12; 777 | default : 778 | throw new Error('mode:' + mode); 779 | } 780 | 781 | } else { 782 | throw new Error('type:' + type); 783 | } 784 | }; 785 | 786 | _this.getLostPoint = function(qrcode) { 787 | 788 | var moduleCount = qrcode.getModuleCount(); 789 | 790 | var lostPoint = 0; 791 | 792 | // LEVEL1 793 | 794 | for (var row = 0; row < moduleCount; row += 1) { 795 | for (var col = 0; col < moduleCount; col += 1) { 796 | 797 | var sameCount = 0; 798 | var dark = qrcode.isDark(row, col); 799 | 800 | for (var r = -1; r <= 1; r += 1) { 801 | 802 | if (row + r < 0 || moduleCount <= row + r) { 803 | continue; 804 | } 805 | 806 | for (var c = -1; c <= 1; c += 1) { 807 | 808 | if (col + c < 0 || moduleCount <= col + c) { 809 | continue; 810 | } 811 | 812 | if (r == 0 && c == 0) { 813 | continue; 814 | } 815 | 816 | if (dark == qrcode.isDark(row + r, col + c) ) { 817 | sameCount += 1; 818 | } 819 | } 820 | } 821 | 822 | if (sameCount > 5) { 823 | lostPoint += (3 + sameCount - 5); 824 | } 825 | } 826 | }; 827 | 828 | // LEVEL2 829 | 830 | for (var row = 0; row < moduleCount - 1; row += 1) { 831 | for (var col = 0; col < moduleCount - 1; col += 1) { 832 | var count = 0; 833 | if (qrcode.isDark(row, col) ) count += 1; 834 | if (qrcode.isDark(row + 1, col) ) count += 1; 835 | if (qrcode.isDark(row, col + 1) ) count += 1; 836 | if (qrcode.isDark(row + 1, col + 1) ) count += 1; 837 | if (count == 0 || count == 4) { 838 | lostPoint += 3; 839 | } 840 | } 841 | } 842 | 843 | // LEVEL3 844 | 845 | for (var row = 0; row < moduleCount; row += 1) { 846 | for (var col = 0; col < moduleCount - 6; col += 1) { 847 | if (qrcode.isDark(row, col) 848 | && !qrcode.isDark(row, col + 1) 849 | && qrcode.isDark(row, col + 2) 850 | && qrcode.isDark(row, col + 3) 851 | && qrcode.isDark(row, col + 4) 852 | && !qrcode.isDark(row, col + 5) 853 | && qrcode.isDark(row, col + 6) ) { 854 | lostPoint += 40; 855 | } 856 | } 857 | } 858 | 859 | for (var col = 0; col < moduleCount; col += 1) { 860 | for (var row = 0; row < moduleCount - 6; row += 1) { 861 | if (qrcode.isDark(row, col) 862 | && !qrcode.isDark(row + 1, col) 863 | && qrcode.isDark(row + 2, col) 864 | && qrcode.isDark(row + 3, col) 865 | && qrcode.isDark(row + 4, col) 866 | && !qrcode.isDark(row + 5, col) 867 | && qrcode.isDark(row + 6, col) ) { 868 | lostPoint += 40; 869 | } 870 | } 871 | } 872 | 873 | // LEVEL4 874 | 875 | var darkCount = 0; 876 | 877 | for (var col = 0; col < moduleCount; col += 1) { 878 | for (var row = 0; row < moduleCount; row += 1) { 879 | if (qrcode.isDark(row, col) ) { 880 | darkCount += 1; 881 | } 882 | } 883 | } 884 | 885 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 886 | lostPoint += ratio * 10; 887 | 888 | return lostPoint; 889 | }; 890 | 891 | return _this; 892 | }(); 893 | 894 | //--------------------------------------------------------------------- 895 | // QRMath 896 | //--------------------------------------------------------------------- 897 | 898 | var QRMath = function() { 899 | 900 | var EXP_TABLE = new Array(256); 901 | var LOG_TABLE = new Array(256); 902 | 903 | // initialize tables 904 | for (var i = 0; i < 8; i += 1) { 905 | EXP_TABLE[i] = 1 << i; 906 | } 907 | for (var i = 8; i < 256; i += 1) { 908 | EXP_TABLE[i] = EXP_TABLE[i - 4] 909 | ^ EXP_TABLE[i - 5] 910 | ^ EXP_TABLE[i - 6] 911 | ^ EXP_TABLE[i - 8]; 912 | } 913 | for (var i = 0; i < 255; i += 1) { 914 | LOG_TABLE[EXP_TABLE[i] ] = i; 915 | } 916 | 917 | var _this = {}; 918 | 919 | _this.glog = function(n) { 920 | 921 | if (n < 1) { 922 | throw new Error('glog(' + n + ')'); 923 | } 924 | 925 | return LOG_TABLE[n]; 926 | }; 927 | 928 | _this.gexp = function(n) { 929 | 930 | while (n < 0) { 931 | n += 255; 932 | } 933 | 934 | while (n >= 256) { 935 | n -= 255; 936 | } 937 | 938 | return EXP_TABLE[n]; 939 | }; 940 | 941 | return _this; 942 | }(); 943 | 944 | //--------------------------------------------------------------------- 945 | // qrPolynomial 946 | //--------------------------------------------------------------------- 947 | 948 | function qrPolynomial(num, shift) { 949 | 950 | if (typeof num.length == 'undefined') { 951 | throw new Error(num.length + '/' + shift); 952 | } 953 | 954 | var _num = function() { 955 | var offset = 0; 956 | while (offset < num.length && num[offset] == 0) { 957 | offset += 1; 958 | } 959 | var _num = new Array(num.length - offset + shift); 960 | for (var i = 0; i < num.length - offset; i += 1) { 961 | _num[i] = num[i + offset]; 962 | } 963 | return _num; 964 | }(); 965 | 966 | var _this = {}; 967 | 968 | _this.getAt = function(index) { 969 | return _num[index]; 970 | }; 971 | 972 | _this.getLength = function() { 973 | return _num.length; 974 | }; 975 | 976 | _this.multiply = function(e) { 977 | 978 | var num = new Array(_this.getLength() + e.getLength() - 1); 979 | 980 | for (var i = 0; i < _this.getLength(); i += 1) { 981 | for (var j = 0; j < e.getLength(); j += 1) { 982 | num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) ); 983 | } 984 | } 985 | 986 | return qrPolynomial(num, 0); 987 | }; 988 | 989 | _this.mod = function(e) { 990 | 991 | if (_this.getLength() - e.getLength() < 0) { 992 | return _this; 993 | } 994 | 995 | var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) ); 996 | 997 | var num = new Array(_this.getLength() ); 998 | for (var i = 0; i < _this.getLength(); i += 1) { 999 | num[i] = _this.getAt(i); 1000 | } 1001 | 1002 | for (var i = 0; i < e.getLength(); i += 1) { 1003 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio); 1004 | } 1005 | 1006 | // recursive call 1007 | return qrPolynomial(num, 0).mod(e); 1008 | }; 1009 | 1010 | return _this; 1011 | }; 1012 | 1013 | //--------------------------------------------------------------------- 1014 | // QRRSBlock 1015 | //--------------------------------------------------------------------- 1016 | 1017 | var QRRSBlock = function() { 1018 | 1019 | var RS_BLOCK_TABLE = [ 1020 | 1021 | // L 1022 | // M 1023 | // Q 1024 | // H 1025 | 1026 | // 1 1027 | [1, 26, 19], 1028 | [1, 26, 16], 1029 | [1, 26, 13], 1030 | [1, 26, 9], 1031 | 1032 | // 2 1033 | [1, 44, 34], 1034 | [1, 44, 28], 1035 | [1, 44, 22], 1036 | [1, 44, 16], 1037 | 1038 | // 3 1039 | [1, 70, 55], 1040 | [1, 70, 44], 1041 | [2, 35, 17], 1042 | [2, 35, 13], 1043 | 1044 | // 4 1045 | [1, 100, 80], 1046 | [2, 50, 32], 1047 | [2, 50, 24], 1048 | [4, 25, 9], 1049 | 1050 | // 5 1051 | [1, 134, 108], 1052 | [2, 67, 43], 1053 | [2, 33, 15, 2, 34, 16], 1054 | [2, 33, 11, 2, 34, 12], 1055 | 1056 | // 6 1057 | [2, 86, 68], 1058 | [4, 43, 27], 1059 | [4, 43, 19], 1060 | [4, 43, 15], 1061 | 1062 | // 7 1063 | [2, 98, 78], 1064 | [4, 49, 31], 1065 | [2, 32, 14, 4, 33, 15], 1066 | [4, 39, 13, 1, 40, 14], 1067 | 1068 | // 8 1069 | [2, 121, 97], 1070 | [2, 60, 38, 2, 61, 39], 1071 | [4, 40, 18, 2, 41, 19], 1072 | [4, 40, 14, 2, 41, 15], 1073 | 1074 | // 9 1075 | [2, 146, 116], 1076 | [3, 58, 36, 2, 59, 37], 1077 | [4, 36, 16, 4, 37, 17], 1078 | [4, 36, 12, 4, 37, 13], 1079 | 1080 | // 10 1081 | [2, 86, 68, 2, 87, 69], 1082 | [4, 69, 43, 1, 70, 44], 1083 | [6, 43, 19, 2, 44, 20], 1084 | [6, 43, 15, 2, 44, 16], 1085 | 1086 | // 11 1087 | [4, 101, 81], 1088 | [1, 80, 50, 4, 81, 51], 1089 | [4, 50, 22, 4, 51, 23], 1090 | [3, 36, 12, 8, 37, 13], 1091 | 1092 | // 12 1093 | [2, 116, 92, 2, 117, 93], 1094 | [6, 58, 36, 2, 59, 37], 1095 | [4, 46, 20, 6, 47, 21], 1096 | [7, 42, 14, 4, 43, 15], 1097 | 1098 | // 13 1099 | [4, 133, 107], 1100 | [8, 59, 37, 1, 60, 38], 1101 | [8, 44, 20, 4, 45, 21], 1102 | [12, 33, 11, 4, 34, 12], 1103 | 1104 | // 14 1105 | [3, 145, 115, 1, 146, 116], 1106 | [4, 64, 40, 5, 65, 41], 1107 | [11, 36, 16, 5, 37, 17], 1108 | [11, 36, 12, 5, 37, 13], 1109 | 1110 | // 15 1111 | [5, 109, 87, 1, 110, 88], 1112 | [5, 65, 41, 5, 66, 42], 1113 | [5, 54, 24, 7, 55, 25], 1114 | [11, 36, 12, 7, 37, 13], 1115 | 1116 | // 16 1117 | [5, 122, 98, 1, 123, 99], 1118 | [7, 73, 45, 3, 74, 46], 1119 | [15, 43, 19, 2, 44, 20], 1120 | [3, 45, 15, 13, 46, 16], 1121 | 1122 | // 17 1123 | [1, 135, 107, 5, 136, 108], 1124 | [10, 74, 46, 1, 75, 47], 1125 | [1, 50, 22, 15, 51, 23], 1126 | [2, 42, 14, 17, 43, 15], 1127 | 1128 | // 18 1129 | [5, 150, 120, 1, 151, 121], 1130 | [9, 69, 43, 4, 70, 44], 1131 | [17, 50, 22, 1, 51, 23], 1132 | [2, 42, 14, 19, 43, 15], 1133 | 1134 | // 19 1135 | [3, 141, 113, 4, 142, 114], 1136 | [3, 70, 44, 11, 71, 45], 1137 | [17, 47, 21, 4, 48, 22], 1138 | [9, 39, 13, 16, 40, 14], 1139 | 1140 | // 20 1141 | [3, 135, 107, 5, 136, 108], 1142 | [3, 67, 41, 13, 68, 42], 1143 | [15, 54, 24, 5, 55, 25], 1144 | [15, 43, 15, 10, 44, 16], 1145 | 1146 | // 21 1147 | [4, 144, 116, 4, 145, 117], 1148 | [17, 68, 42], 1149 | [17, 50, 22, 6, 51, 23], 1150 | [19, 46, 16, 6, 47, 17], 1151 | 1152 | // 22 1153 | [2, 139, 111, 7, 140, 112], 1154 | [17, 74, 46], 1155 | [7, 54, 24, 16, 55, 25], 1156 | [34, 37, 13], 1157 | 1158 | // 23 1159 | [4, 151, 121, 5, 152, 122], 1160 | [4, 75, 47, 14, 76, 48], 1161 | [11, 54, 24, 14, 55, 25], 1162 | [16, 45, 15, 14, 46, 16], 1163 | 1164 | // 24 1165 | [6, 147, 117, 4, 148, 118], 1166 | [6, 73, 45, 14, 74, 46], 1167 | [11, 54, 24, 16, 55, 25], 1168 | [30, 46, 16, 2, 47, 17], 1169 | 1170 | // 25 1171 | [8, 132, 106, 4, 133, 107], 1172 | [8, 75, 47, 13, 76, 48], 1173 | [7, 54, 24, 22, 55, 25], 1174 | [22, 45, 15, 13, 46, 16], 1175 | 1176 | // 26 1177 | [10, 142, 114, 2, 143, 115], 1178 | [19, 74, 46, 4, 75, 47], 1179 | [28, 50, 22, 6, 51, 23], 1180 | [33, 46, 16, 4, 47, 17], 1181 | 1182 | // 27 1183 | [8, 152, 122, 4, 153, 123], 1184 | [22, 73, 45, 3, 74, 46], 1185 | [8, 53, 23, 26, 54, 24], 1186 | [12, 45, 15, 28, 46, 16], 1187 | 1188 | // 28 1189 | [3, 147, 117, 10, 148, 118], 1190 | [3, 73, 45, 23, 74, 46], 1191 | [4, 54, 24, 31, 55, 25], 1192 | [11, 45, 15, 31, 46, 16], 1193 | 1194 | // 29 1195 | [7, 146, 116, 7, 147, 117], 1196 | [21, 73, 45, 7, 74, 46], 1197 | [1, 53, 23, 37, 54, 24], 1198 | [19, 45, 15, 26, 46, 16], 1199 | 1200 | // 30 1201 | [5, 145, 115, 10, 146, 116], 1202 | [19, 75, 47, 10, 76, 48], 1203 | [15, 54, 24, 25, 55, 25], 1204 | [23, 45, 15, 25, 46, 16], 1205 | 1206 | // 31 1207 | [13, 145, 115, 3, 146, 116], 1208 | [2, 74, 46, 29, 75, 47], 1209 | [42, 54, 24, 1, 55, 25], 1210 | [23, 45, 15, 28, 46, 16], 1211 | 1212 | // 32 1213 | [17, 145, 115], 1214 | [10, 74, 46, 23, 75, 47], 1215 | [10, 54, 24, 35, 55, 25], 1216 | [19, 45, 15, 35, 46, 16], 1217 | 1218 | // 33 1219 | [17, 145, 115, 1, 146, 116], 1220 | [14, 74, 46, 21, 75, 47], 1221 | [29, 54, 24, 19, 55, 25], 1222 | [11, 45, 15, 46, 46, 16], 1223 | 1224 | // 34 1225 | [13, 145, 115, 6, 146, 116], 1226 | [14, 74, 46, 23, 75, 47], 1227 | [44, 54, 24, 7, 55, 25], 1228 | [59, 46, 16, 1, 47, 17], 1229 | 1230 | // 35 1231 | [12, 151, 121, 7, 152, 122], 1232 | [12, 75, 47, 26, 76, 48], 1233 | [39, 54, 24, 14, 55, 25], 1234 | [22, 45, 15, 41, 46, 16], 1235 | 1236 | // 36 1237 | [6, 151, 121, 14, 152, 122], 1238 | [6, 75, 47, 34, 76, 48], 1239 | [46, 54, 24, 10, 55, 25], 1240 | [2, 45, 15, 64, 46, 16], 1241 | 1242 | // 37 1243 | [17, 152, 122, 4, 153, 123], 1244 | [29, 74, 46, 14, 75, 47], 1245 | [49, 54, 24, 10, 55, 25], 1246 | [24, 45, 15, 46, 46, 16], 1247 | 1248 | // 38 1249 | [4, 152, 122, 18, 153, 123], 1250 | [13, 74, 46, 32, 75, 47], 1251 | [48, 54, 24, 14, 55, 25], 1252 | [42, 45, 15, 32, 46, 16], 1253 | 1254 | // 39 1255 | [20, 147, 117, 4, 148, 118], 1256 | [40, 75, 47, 7, 76, 48], 1257 | [43, 54, 24, 22, 55, 25], 1258 | [10, 45, 15, 67, 46, 16], 1259 | 1260 | // 40 1261 | [19, 148, 118, 6, 149, 119], 1262 | [18, 75, 47, 31, 76, 48], 1263 | [34, 54, 24, 34, 55, 25], 1264 | [20, 45, 15, 61, 46, 16] 1265 | ]; 1266 | 1267 | var qrRSBlock = function(totalCount, dataCount) { 1268 | var _this = {}; 1269 | _this.totalCount = totalCount; 1270 | _this.dataCount = dataCount; 1271 | return _this; 1272 | }; 1273 | 1274 | var _this = {}; 1275 | 1276 | var getRsBlockTable = function(typeNumber, errorCorrectLevel) { 1277 | 1278 | switch(errorCorrectLevel) { 1279 | case QRErrorCorrectLevel.L : 1280 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 1281 | case QRErrorCorrectLevel.M : 1282 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 1283 | case QRErrorCorrectLevel.Q : 1284 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 1285 | case QRErrorCorrectLevel.H : 1286 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 1287 | default : 1288 | return undefined; 1289 | } 1290 | }; 1291 | 1292 | _this.getRSBlocks = function(typeNumber, errorCorrectLevel) { 1293 | 1294 | var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel); 1295 | 1296 | if (typeof rsBlock == 'undefined') { 1297 | throw new Error('bad rs block @ typeNumber:' + typeNumber + 1298 | '/errorCorrectLevel:' + errorCorrectLevel); 1299 | } 1300 | 1301 | var length = rsBlock.length / 3; 1302 | 1303 | var list = new Array(); 1304 | 1305 | for (var i = 0; i < length; i += 1) { 1306 | 1307 | var count = rsBlock[i * 3 + 0]; 1308 | var totalCount = rsBlock[i * 3 + 1]; 1309 | var dataCount = rsBlock[i * 3 + 2]; 1310 | 1311 | for (var j = 0; j < count; j += 1) { 1312 | list.push(qrRSBlock(totalCount, dataCount) ); 1313 | } 1314 | } 1315 | 1316 | return list; 1317 | }; 1318 | 1319 | return _this; 1320 | }(); 1321 | 1322 | //--------------------------------------------------------------------- 1323 | // qrBitBuffer 1324 | //--------------------------------------------------------------------- 1325 | 1326 | var qrBitBuffer = function() { 1327 | 1328 | var _buffer = new Array(); 1329 | var _length = 0; 1330 | 1331 | var _this = {}; 1332 | 1333 | _this.getBuffer = function() { 1334 | return _buffer; 1335 | }; 1336 | 1337 | _this.getAt = function(index) { 1338 | var bufIndex = Math.floor(index / 8); 1339 | return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; 1340 | }; 1341 | 1342 | _this.put = function(num, length) { 1343 | for (var i = 0; i < length; i += 1) { 1344 | _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 1345 | } 1346 | }; 1347 | 1348 | _this.getLengthInBits = function() { 1349 | return _length; 1350 | }; 1351 | 1352 | _this.putBit = function(bit) { 1353 | 1354 | var bufIndex = Math.floor(_length / 8); 1355 | if (_buffer.length <= bufIndex) { 1356 | _buffer.push(0); 1357 | } 1358 | 1359 | if (bit) { 1360 | _buffer[bufIndex] |= (0x80 >>> (_length % 8) ); 1361 | } 1362 | 1363 | _length += 1; 1364 | }; 1365 | 1366 | return _this; 1367 | }; 1368 | 1369 | //--------------------------------------------------------------------- 1370 | // qr8BitByte 1371 | //--------------------------------------------------------------------- 1372 | 1373 | var qr8BitByte = function(data) { 1374 | 1375 | var _mode = QRMode.MODE_8BIT_BYTE; 1376 | var _data = data; 1377 | var _bytes = qrcode.stringToBytes(data); 1378 | 1379 | var _this = {}; 1380 | 1381 | _this.getMode = function() { 1382 | return _mode; 1383 | }; 1384 | 1385 | _this.getLength = function(buffer) { 1386 | return _bytes.length; 1387 | }; 1388 | 1389 | _this.write = function(buffer) { 1390 | for (var i = 0; i < _bytes.length; i += 1) { 1391 | buffer.put(_bytes[i], 8); 1392 | } 1393 | }; 1394 | 1395 | return _this; 1396 | }; 1397 | 1398 | //===================================================================== 1399 | // GIF Support etc. 1400 | // 1401 | 1402 | //--------------------------------------------------------------------- 1403 | // byteArrayOutputStream 1404 | //--------------------------------------------------------------------- 1405 | 1406 | var byteArrayOutputStream = function() { 1407 | 1408 | var _bytes = new Array(); 1409 | 1410 | var _this = {}; 1411 | 1412 | _this.writeByte = function(b) { 1413 | _bytes.push(b & 0xff); 1414 | }; 1415 | 1416 | _this.writeShort = function(i) { 1417 | _this.writeByte(i); 1418 | _this.writeByte(i >>> 8); 1419 | }; 1420 | 1421 | _this.writeBytes = function(b, off, len) { 1422 | off = off || 0; 1423 | len = len || b.length; 1424 | for (var i = 0; i < len; i += 1) { 1425 | _this.writeByte(b[i + off]); 1426 | } 1427 | }; 1428 | 1429 | _this.writeString = function(s) { 1430 | for (var i = 0; i < s.length; i += 1) { 1431 | _this.writeByte(s.charCodeAt(i) ); 1432 | } 1433 | }; 1434 | 1435 | _this.toByteArray = function() { 1436 | return _bytes; 1437 | }; 1438 | 1439 | _this.toString = function() { 1440 | var s = ''; 1441 | s += '['; 1442 | for (var i = 0; i < _bytes.length; i += 1) { 1443 | if (i > 0) { 1444 | s += ','; 1445 | } 1446 | s += _bytes[i]; 1447 | } 1448 | s += ']'; 1449 | return s; 1450 | }; 1451 | 1452 | return _this; 1453 | }; 1454 | 1455 | //--------------------------------------------------------------------- 1456 | // base64EncodeOutputStream 1457 | //--------------------------------------------------------------------- 1458 | 1459 | var base64EncodeOutputStream = function() { 1460 | 1461 | var _buffer = 0; 1462 | var _buflen = 0; 1463 | var _length = 0; 1464 | var _base64 = ''; 1465 | 1466 | var _this = {}; 1467 | 1468 | var writeEncoded = function(b) { 1469 | _base64 += String.fromCharCode(encode(b & 0x3f) ); 1470 | }; 1471 | 1472 | var encode = function(n) { 1473 | if (n < 0) { 1474 | // error. 1475 | } else if (n < 26) { 1476 | return 0x41 + n; 1477 | } else if (n < 52) { 1478 | return 0x61 + (n - 26); 1479 | } else if (n < 62) { 1480 | return 0x30 + (n - 52); 1481 | } else if (n == 62) { 1482 | return 0x2b; 1483 | } else if (n == 63) { 1484 | return 0x2f; 1485 | } 1486 | throw new Error('n:' + n); 1487 | }; 1488 | 1489 | _this.writeByte = function(n) { 1490 | 1491 | _buffer = (_buffer << 8) | (n & 0xff); 1492 | _buflen += 8; 1493 | _length += 1; 1494 | 1495 | while (_buflen >= 6) { 1496 | writeEncoded(_buffer >>> (_buflen - 6) ); 1497 | _buflen -= 6; 1498 | } 1499 | }; 1500 | 1501 | _this.flush = function() { 1502 | 1503 | if (_buflen > 0) { 1504 | writeEncoded(_buffer << (6 - _buflen) ); 1505 | _buffer = 0; 1506 | _buflen = 0; 1507 | } 1508 | 1509 | if (_length % 3 != 0) { 1510 | // padding 1511 | var padlen = 3 - _length % 3; 1512 | for (var i = 0; i < padlen; i += 1) { 1513 | _base64 += '='; 1514 | } 1515 | } 1516 | }; 1517 | 1518 | _this.toString = function() { 1519 | return _base64; 1520 | }; 1521 | 1522 | return _this; 1523 | }; 1524 | 1525 | //--------------------------------------------------------------------- 1526 | // base64DecodeInputStream 1527 | //--------------------------------------------------------------------- 1528 | 1529 | var base64DecodeInputStream = function(str) { 1530 | 1531 | var _str = str; 1532 | var _pos = 0; 1533 | var _buffer = 0; 1534 | var _buflen = 0; 1535 | 1536 | var _this = {}; 1537 | 1538 | _this.read = function() { 1539 | 1540 | while (_buflen < 8) { 1541 | 1542 | if (_pos >= _str.length) { 1543 | if (_buflen == 0) { 1544 | return -1; 1545 | } 1546 | throw new Error('unexpected end of file./' + _buflen); 1547 | } 1548 | 1549 | var c = _str.charAt(_pos); 1550 | _pos += 1; 1551 | 1552 | if (c == '=') { 1553 | _buflen = 0; 1554 | return -1; 1555 | } else if (c.match(/^\s$/) ) { 1556 | // ignore if whitespace. 1557 | continue; 1558 | } 1559 | 1560 | _buffer = (_buffer << 6) | decode(c.charCodeAt(0) ); 1561 | _buflen += 6; 1562 | } 1563 | 1564 | var n = (_buffer >>> (_buflen - 8) ) & 0xff; 1565 | _buflen -= 8; 1566 | return n; 1567 | }; 1568 | 1569 | var decode = function(c) { 1570 | if (0x41 <= c && c <= 0x5a) { 1571 | return c - 0x41; 1572 | } else if (0x61 <= c && c <= 0x7a) { 1573 | return c - 0x61 + 26; 1574 | } else if (0x30 <= c && c <= 0x39) { 1575 | return c - 0x30 + 52; 1576 | } else if (c == 0x2b) { 1577 | return 62; 1578 | } else if (c == 0x2f) { 1579 | return 63; 1580 | } else { 1581 | throw new Error('c:' + c); 1582 | } 1583 | }; 1584 | 1585 | return _this; 1586 | }; 1587 | 1588 | //--------------------------------------------------------------------- 1589 | // gifImage (B/W) 1590 | //--------------------------------------------------------------------- 1591 | 1592 | var gifImage = function(width, height) { 1593 | 1594 | var _width = width; 1595 | var _height = height; 1596 | var _data = new Array(width * height); 1597 | 1598 | var _this = {}; 1599 | 1600 | _this.setPixel = function(x, y, pixel) { 1601 | _data[y * _width + x] = pixel; 1602 | }; 1603 | 1604 | _this.write = function(out) { 1605 | 1606 | //--------------------------------- 1607 | // GIF Signature 1608 | 1609 | out.writeString('GIF87a'); 1610 | 1611 | //--------------------------------- 1612 | // Screen Descriptor 1613 | 1614 | out.writeShort(_width); 1615 | out.writeShort(_height); 1616 | 1617 | out.writeByte(0x80); // 2bit 1618 | out.writeByte(0); 1619 | out.writeByte(0); 1620 | 1621 | //--------------------------------- 1622 | // Global Color Map 1623 | 1624 | // black 1625 | out.writeByte(0x00); 1626 | out.writeByte(0x00); 1627 | out.writeByte(0x00); 1628 | 1629 | // white 1630 | out.writeByte(0xff); 1631 | out.writeByte(0xff); 1632 | out.writeByte(0xff); 1633 | 1634 | //--------------------------------- 1635 | // Image Descriptor 1636 | 1637 | out.writeString(','); 1638 | out.writeShort(0); 1639 | out.writeShort(0); 1640 | out.writeShort(_width); 1641 | out.writeShort(_height); 1642 | out.writeByte(0); 1643 | 1644 | //--------------------------------- 1645 | // Local Color Map 1646 | 1647 | //--------------------------------- 1648 | // Raster Data 1649 | 1650 | var lzwMinCodeSize = 2; 1651 | var raster = getLZWRaster(lzwMinCodeSize); 1652 | 1653 | out.writeByte(lzwMinCodeSize); 1654 | 1655 | var offset = 0; 1656 | 1657 | while (raster.length - offset > 255) { 1658 | out.writeByte(255); 1659 | out.writeBytes(raster, offset, 255); 1660 | offset += 255; 1661 | } 1662 | 1663 | out.writeByte(raster.length - offset); 1664 | out.writeBytes(raster, offset, raster.length - offset); 1665 | out.writeByte(0x00); 1666 | 1667 | //--------------------------------- 1668 | // GIF Terminator 1669 | out.writeString(';'); 1670 | }; 1671 | 1672 | var bitOutputStream = function(out) { 1673 | 1674 | var _out = out; 1675 | var _bitLength = 0; 1676 | var _bitBuffer = 0; 1677 | 1678 | var _this = {}; 1679 | 1680 | _this.write = function(data, length) { 1681 | 1682 | if ( (data >>> length) != 0) { 1683 | throw new Error('length over'); 1684 | } 1685 | 1686 | while (_bitLength + length >= 8) { 1687 | _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) ); 1688 | length -= (8 - _bitLength); 1689 | data >>>= (8 - _bitLength); 1690 | _bitBuffer = 0; 1691 | _bitLength = 0; 1692 | } 1693 | 1694 | _bitBuffer = (data << _bitLength) | _bitBuffer; 1695 | _bitLength = _bitLength + length; 1696 | }; 1697 | 1698 | _this.flush = function() { 1699 | if (_bitLength > 0) { 1700 | _out.writeByte(_bitBuffer); 1701 | } 1702 | }; 1703 | 1704 | return _this; 1705 | }; 1706 | 1707 | var getLZWRaster = function(lzwMinCodeSize) { 1708 | 1709 | var clearCode = 1 << lzwMinCodeSize; 1710 | var endCode = (1 << lzwMinCodeSize) + 1; 1711 | var bitLength = lzwMinCodeSize + 1; 1712 | 1713 | // Setup LZWTable 1714 | var table = lzwTable(); 1715 | 1716 | for (var i = 0; i < clearCode; i += 1) { 1717 | table.add(String.fromCharCode(i) ); 1718 | } 1719 | table.add(String.fromCharCode(clearCode) ); 1720 | table.add(String.fromCharCode(endCode) ); 1721 | 1722 | var byteOut = byteArrayOutputStream(); 1723 | var bitOut = bitOutputStream(byteOut); 1724 | 1725 | // clear code 1726 | bitOut.write(clearCode, bitLength); 1727 | 1728 | var dataIndex = 0; 1729 | 1730 | var s = String.fromCharCode(_data[dataIndex]); 1731 | dataIndex += 1; 1732 | 1733 | while (dataIndex < _data.length) { 1734 | 1735 | var c = String.fromCharCode(_data[dataIndex]); 1736 | dataIndex += 1; 1737 | 1738 | if (table.contains(s + c) ) { 1739 | 1740 | s = s + c; 1741 | 1742 | } else { 1743 | 1744 | bitOut.write(table.indexOf(s), bitLength); 1745 | 1746 | if (table.size() < 0xfff) { 1747 | 1748 | if (table.size() == (1 << bitLength) ) { 1749 | bitLength += 1; 1750 | } 1751 | 1752 | table.add(s + c); 1753 | } 1754 | 1755 | s = c; 1756 | } 1757 | } 1758 | 1759 | bitOut.write(table.indexOf(s), bitLength); 1760 | 1761 | // end code 1762 | bitOut.write(endCode, bitLength); 1763 | 1764 | bitOut.flush(); 1765 | 1766 | return byteOut.toByteArray(); 1767 | }; 1768 | 1769 | var lzwTable = function() { 1770 | 1771 | var _map = {}; 1772 | var _size = 0; 1773 | 1774 | var _this = {}; 1775 | 1776 | _this.add = function(key) { 1777 | if (_this.contains(key) ) { 1778 | throw new Error('dup key:' + key); 1779 | } 1780 | _map[key] = _size; 1781 | _size += 1; 1782 | }; 1783 | 1784 | _this.size = function() { 1785 | return _size; 1786 | }; 1787 | 1788 | _this.indexOf = function(key) { 1789 | return _map[key]; 1790 | }; 1791 | 1792 | _this.contains = function(key) { 1793 | return typeof _map[key] != 'undefined'; 1794 | }; 1795 | 1796 | return _this; 1797 | }; 1798 | 1799 | return _this; 1800 | }; 1801 | 1802 | var createImgTag = function(width, height, getPixel, alt) { 1803 | 1804 | var gif = gifImage(width, height); 1805 | for (var y = 0; y < height; y += 1) { 1806 | for (var x = 0; x < width; x += 1) { 1807 | gif.setPixel(x, y, getPixel(x, y) ); 1808 | } 1809 | } 1810 | 1811 | var b = byteArrayOutputStream(); 1812 | gif.write(b); 1813 | 1814 | var base64 = base64EncodeOutputStream(); 1815 | var bytes = b.toByteArray(); 1816 | for (var i = 0; i < bytes.length; i += 1) { 1817 | base64.writeByte(bytes[i]); 1818 | } 1819 | base64.flush(); 1820 | 1821 | var img = ''; 1822 | img += '