├── .bowerrc ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── angular-qr.min.js ├── bower.json ├── demo └── index.html ├── gulpfile.js ├── karma.conf.js ├── lib └── qrcode.js ├── package.json ├── src └── angular-qr.js └── test └── unit.spec.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | node_modules/ 3 | *.log -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "strict": true, 3 | "undef": true, 4 | "unused": false, 5 | "node": true, 6 | "globals": { 7 | "window": true, 8 | "document": true, 9 | "navigator": true, 10 | "angular": true, 11 | "describe": true, 12 | "it": true, 13 | "beforeEach": true, 14 | "afterEach": true 15 | } 16 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | 5 | before_install: 6 | - export DISPLAY=:99.0 7 | - sh -e /etc/init.d/xvfb start 8 | - npm install -g bower gulp 9 | - npm install 10 | - bower install 11 | 12 | script: "gulp" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.2.0 (2014-06-22) 2 | 3 | 4 | #### Bug Fixes 5 | 6 | * binding attributes ([eb3c89ea](git://github.com/janantala/angular-qr.git/commit/eb3c89ea1c0882489e7ad2a62fc780b6ec30a4bd)) 7 | * **gulp-changelog:** module no longer available ([7ddd57fa](git://github.com/janantala/angular-qr.git/commit/7ddd57fa17b4b5ca0c2b172780c85a1053345362)) 8 | 9 | 10 | #### Features 11 | 12 | * render qr code into img element ([10ea4681](git://github.com/janantala/angular-qr.git/commit/10ea46817854c4080077d4a2bafb010430f549d3)) 13 | * **build:** 14 | * use changelog directly ([8b9287c0](git://github.com/janantala/angular-qr.git/commit/8b9287c0f8f2c1edb6ddf1880ac7d8d582706c7c)) 15 | 16 | 17 | 18 | ### v0.1.4 (2013-12-18) 19 | 20 | 21 | #### Features 22 | 23 | * **bower:** require angular 1.2.x version ([b5458a21](https://github.com/janantala/angular-qr/commit/b5458a2156cb00d1ea9e4520db17a07c1079b8ba)) 24 | 25 | 26 | ### v0.1.3 (2013-11-14) 27 | 28 | 29 | #### Bug Fixes 30 | 31 | * **is8bit:** max 8bit character has code 255 not 256 ([deebe0eb](https://github.com/janantala/angular-qr/commit/deebe0eb2eb353a52e023a37e1478e75f7b7221a)) 32 | 33 | 34 | 35 | ### v0.1.2 (2013-11-13) 36 | 37 | 38 | #### Features 39 | 40 | * **conventional-changelog:** add changelog support ([8dafd515](https://github.com/janantala/angular-qr/commit/8dafd515f0bf361366047838b024c22d767bae0b)) 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jan Antala 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-qr v0.2.0 [![Build Status](https://travis-ci.org/janantala/angular-qr.png?branch=master)](https://travis-ci.org/janantala/angular-qr) 2 | 3 | QR code generator for AngularJS 4 | 5 | ### Demo 6 | 7 | Check out http://janantala.github.io/angular-qr/demo/ 8 | 9 | # Requirements 10 | 11 | - AngularJS v 1.0+ 12 | - [qrcode.js](https://github.com/janantala/qrcode) (`bower install qrcode` is installed with angular-qr as dependecy) 13 | 14 | # Usage 15 | 16 | We use [bower](http://twitter.github.com/bower/) for dependency management. Add 17 | 18 | ```json 19 | dependencies: { 20 | "angular-qr": "latest" 21 | } 22 | ``` 23 | 24 | To your `bower.json` file. Then run 25 | 26 | bower install 27 | 28 | This will copy the angular-qr files into your `bower_components` folder, along with its dependencies. Load the script files in your application: 29 | 30 | ```html 31 | 32 | 33 | 34 | ``` 35 | 36 | Add the **ja.qr** module as a dependency to your application module: 37 | 38 | ```js 39 | var myAppModule = angular.module('MyApp', ['ja.qr']); 40 | ``` 41 | 42 | ## Directive 43 | 44 | ```js 45 | $scope.string = 'YOUR TEXT TO ENCODE'; 46 | ``` 47 | 48 | ```html 49 | 50 | ``` 51 | 52 | ```html 53 | 54 | ``` 55 | 56 | ### Required attributes 57 | 58 | #### text 59 | Your text to encode from variable in the scope. If you want to encode text directly you need to escape it `text="'YOUR TEXT TO ENCODE'"`. 60 | 61 | ### Optional attributes 62 | 63 | #### type-number 64 | - 1-40 65 | - default value: `0` = minimal required version 66 | 67 | #### correction-level 68 | - `L` - Low 69 | - `M` - Medium (default) 70 | - `Q` - Quartile 71 | - `H` - High 72 | 73 | #### size 74 | Size in pixels 75 | - default value: 250 76 | 77 | #### input-mode 78 | - `NUMBER`: *0, 1, 2, 3, 4, 5, 6, 7, 8, 9* 79 | - `ALPHA_NUM`: *0–9, A–Z (upper-case only), space, $, %, *, +, -, ., /, :* 80 | - `8bit`: *[ISO 8859-1](http://en.wikipedia.org/wiki/ISO_8859-1)* 81 | - default value: minimal required input mode based on input text 82 | 83 | #### image 84 | - If you want to render qr code into image element set this attribute to `true`. 85 | 86 | # Contributing 87 | 88 | Contributions are welcome. Please make a pull request against canary branch, use [Git Commit Message Conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#heading=h.uyo6cb12dt6w) and do not bump versions. Also include tests. 89 | 90 | # Testing 91 | 92 | We use karma and jshint to ensure the quality of the code. The easiest way to run these checks is to use gulp: 93 | 94 | npm install -g gulp 95 | npm install 96 | bower install 97 | gulp 98 | 99 | The karma task will try to open Chrome as a browser in which to run the tests. Make sure this is available or change the configuration in `karma.conf.js` 100 | 101 | 102 | # License 103 | 104 | The MIT License 105 | 106 | Copyright (c) 2014 [Jan Antala](http://www.janantala.com) 107 | -------------------------------------------------------------------------------- /angular-qr.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * angular-qr v0.2.0 3 | * The MIT License 4 | * Copyright (c) 2014 Jan Antala 5 | */ 6 | 7 | !function(t){"use strict";angular.module("ja.qr",[]).controller("QrCtrl",["$scope",function(t){t.getTypeNumeber=function(){return t.typeNumber||0},t.getCorrection=function(){var e={L:1,M:0,Q:3,H:2},r=t.correctionLevel||0;return e[r]||0},t.getText=function(){return t.text||""},t.getSize=function(){return t.size||250},t.isNUMBER=function(t){var e=/^[0-9]*$/;return e.test(t)},t.isALPHA_NUM=function(t){var e=/^[0-9A-Z $%*+\-./:]*$/;return e.test(t)},t.is8bit=function(t){for(var e=0;e255)return!1}return!0},t.checkInputMode=function(e,r){if("NUMBER"===e&&!t.isNUMBER(r))throw new Error("The `NUMBER` input mode is invalid for text.");if("ALPHA_NUM"===e&&!t.isALPHA_NUM(r))throw new Error("The `ALPHA_NUM` input mode is invalid for text.");if("8bit"===e&&!t.is8bit(r))throw new Error("The `8bit` input mode is invalid for text.");if(!t.is8bit(r))throw new Error("Input mode is invalid for text.");return!0},t.getInputMode=function(e){var r=t.inputMode;return r=r||(t.isNUMBER(e)?"NUMBER":void 0),r=r||(t.isALPHA_NUM(e)?"ALPHA_NUM":void 0),r=r||(t.is8bit(e)?"8bit":""),t.checkInputMode(r,e)?r:""}}]).directive("qr",["$timeout","$window",function(e,r){return{restrict:"E",template:'',scope:{typeNumber:"=",correctionLevel:"=",inputMode:"=",size:"=",text:"=",image:"="},controller:"QrCtrl",link:function(n,i){if(void 0===n.text)throw new Error("The `text` attribute is required.");var o=i.find("canvas")[0],E=!!r.CanvasRenderingContext2D;n.TYPE_NUMBER=n.getTypeNumeber(),n.TEXT=n.getText(),n.CORRECTION=n.getCorrection(),n.SIZE=n.getSize(),n.INPUT_MODE=n.getInputMode(n.TEXT),n.canvasImage="http://lorempixel.com/500/500/";var a=function(t,e,r,n){for(var i=0;r>i;i++)for(var o=0;r>o;o++){var E=Math.ceil((o+1)*n)-Math.floor(o*n),a=Math.ceil((i+1)*n)-Math.floor(i*n);t.fillStyle=e.isDark(i,o)?"#000":"#fff",t.fillRect(Math.round(o*n),Math.round(i*n),E,a)}},u=function(e,r,i,o,u,c){var T=/^\s+|\s+$/g,M=r.replace(T,""),f=new t(i,o,c);f.addData(M),f.make();var N=e.getContext("2d"),d=f.getModuleCount(),s=u/d;e.width=e.height=u,E&&(a(N,f,d,s),n.canvasImage=e.toDataURL())};u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE),e(function(){n.$watch("text",function(t,e){t!==e&&(n.TEXT=n.getText(),n.INPUT_MODE=n.getInputMode(n.TEXT),u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE))}),n.$watch("correctionLevel",function(t,e){t!==e&&(n.CORRECTION=n.getCorrection(),u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE))}),n.$watch("typeNumber",function(t,e){t!==e&&(n.TYPE_NUMBER=n.getTypeNumeber(),u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE))}),n.$watch("size",function(t,e){t!==e&&(n.SIZE=n.getSize(),u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE))}),n.$watch("inputMode",function(t,e){t!==e&&(n.INPUT_MODE=n.getInputMode(n.TEXT),u(o,n.TEXT,n.TYPE_NUMBER,n.CORRECTION,n.SIZE,n.INPUT_MODE))})})}}}])}(window.QRCode); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-qr", 3 | "version": "0.2.0", 4 | "description": "QR code generator for AngularJS", 5 | "keywords": ["qr", "qrcode", "angular"], 6 | "authors": ["Jan Antala "], 7 | "license": "MIT", 8 | "homepage": "https://github.com/janantala/angular-qr", 9 | "main": "./src/angular-qr.js", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/janantala/angular-qr.git" 13 | }, 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test*", 19 | "demo*", 20 | "Gruntfile.js", 21 | "package.json" 22 | ], 23 | "dependencies": { 24 | "angular": "~1.2.5", 25 | "qrcode": "~1.0.x" 26 | }, 27 | "devDependencies": { 28 | "angular-mocks": "~1.2.5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | angular-qr 8 | 9 | 10 | 11 | 158 | 159 | 160 | 161 |
162 | 163 |
164 |

angular-qr

165 |

QR code generator for AngularJS.

166 | 167 | Fork me on GitHub 168 | 169 |

170 | bower install angular-qr 171 |

172 | 173 |

174 | 176 | 177 | 179 | 180 | 182 |

183 |
184 | 185 |
186 | 187 |

Load dependecies:

188 | 189 |

190 | <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.13/angular.min.js"></script> 191 |

192 |

193 | <script src="bower_components/qrcode/lib/qrcode.min.js"></script> 194 |

195 |

196 | <script src="bower_components/angular-qr/angular-qr.min.js"></script> 197 |

198 | 199 |

Usage:

200 | 201 |

202 | <qr text="qrcodeString"></qr> 203 |

204 | 205 |

206 | 207 |

208 | 209 |

210 | 211 |

212 |

213 | 214 |

215 | 216 |

Optional attributes:

217 | 218 |

219 | <qr text="qrcodeString" type-number="typeNumber" correction-level="correctionLevel" size="SIZE" input-mode="inputMode" image="image"></qr> 220 |

221 | 222 |

223 | 224 | {{typeNumber}} (use 0 as minimal possible) 225 |

226 |

227 | 228 |

229 | 230 |

231 | 232 | {{correctionLevel}} 233 |

234 |

235 | Auto (M) 236 | L (Low) 237 | M (Medium) 238 | Q (Quartile) 239 | H (High) 240 |

241 | 242 | 243 |

244 | 245 | {{size}} 246 |

247 |

248 | 249 |

250 | 251 |

252 | 253 | {{inputMode}} 254 |

255 |

256 | Auto 257 | NUMBER 258 | ALPHA_NUM 259 | 8bit 260 |

261 | 262 |

263 | 264 | {{image}} 265 |

266 |

267 | Yes 268 | No 269 |

270 | 271 |
272 | 273 |
274 |

Made with by Jan Antala

275 |

2014 Licensed under MIT

276 |
277 | 278 |
279 | 280 | 281 | 282 | 283 | 284 | 296 | 297 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var env = require('gulp-util').env; 5 | var log = require('gulp-util').log; 6 | var dateformat = require('gulp-util').date; 7 | var uglify = require('gulp-uglify'); 8 | var concat = require('gulp-concat'); 9 | var header = require('gulp-header'); 10 | var rename = require('gulp-rename'); 11 | var jshint = require('gulp-jshint'); 12 | var karma = require('gulp-karma'); 13 | var changelog = require('conventional-changelog'); 14 | 15 | var now = new Date(); 16 | var year = dateformat(now, "yyyy"); 17 | var pkg = require('./package.json'); 18 | var banner = [ 19 | '/*!', 20 | ' * <%= pkg.name %> v<%= pkg.version %>', 21 | ' * The <%= pkg.license %> License', 22 | ' * Copyright (c) <%= year %> <%= pkg.authors.join(",") %>', 23 | ' */', 24 | '\n' 25 | ].join('\n'); 26 | 27 | var codeFiles = ['src/*.js']; 28 | var testFiles = ['bower_components/angular/angular.js', 'bower_components/angular-mocks/angular-mocks.js', 'lib/qrcode.js', 'src/*.js', 'test/*.spec.js']; 29 | 30 | gulp.task('lint', function(){ 31 | log('Linting Files'); 32 | return gulp.src(codeFiles) 33 | .pipe(jshint('.jshintrc')) 34 | .pipe(jshint.reporter()); 35 | }); 36 | 37 | gulp.task('karma', function () { 38 | 39 | var options = { 40 | configFile: 'karma.conf.js', 41 | action: 'run' 42 | }; 43 | 44 | if (process.env.TRAVIS) { 45 | options.browsers = ['Firefox']; 46 | } 47 | 48 | return gulp.src(testFiles) 49 | .pipe(karma(options)); 50 | }); 51 | 52 | gulp.task('build', function() { 53 | return gulp.src(codeFiles) 54 | .pipe(uglify({'evil': true})) 55 | .pipe(header(banner, { pkg: pkg, year: year })) 56 | .pipe(rename({ 57 | ext: ".min.js" 58 | })) 59 | .pipe(gulp.dest('')); 60 | }); 61 | 62 | gulp.task('changelog', function() { 63 | var fs = require('fs'); 64 | changelog({ 65 | repository: require('./package.json').repository.url, 66 | version: require('./package.json').version 67 | }, function(err, log){ 68 | fs.writeFile('CHANGELOG.md', log); 69 | }); 70 | }); 71 | 72 | gulp.task('default', ['lint', 'karma']); 73 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | basePath: '', 4 | files: [ 5 | // Defined by gulp 6 | ], 7 | frameworks: ['jasmine'], 8 | singleRun: true, 9 | browsers: [ 'Chrome' ] 10 | }); 11 | }; -------------------------------------------------------------------------------- /lib/qrcode.js: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // QRCode for JavaScript 3 | // 4 | // Copyright (c) 2009 Kazuhiko Arase, URL: http://www.d-project.com/ 5 | // Copyright (c) 2013 Jan Antala, URL: http://www.janantala.com/ 6 | // 7 | // Licensed under the MIT license: 8 | // http://www.opensource.org/licenses/mit-license.php 9 | // 10 | // The word "QR Code" is registered trademark of 11 | // DENSO WAVE INCORPORATED 12 | // http://www.denso-wave.com/qrcode/faqpatent-e.html 13 | // 14 | //--------------------------------------------------------------------- 15 | 16 | //--------------------------------------------------------------------- 17 | // QR8bitByte 18 | //--------------------------------------------------------------------- 19 | 20 | function QR8bitByte(data) { 21 | this.mode = QRMode.MODE_8BIT_BYTE; 22 | this.data = data; 23 | } 24 | 25 | QR8bitByte.prototype = { 26 | 27 | getLength : function(buffer) { 28 | return this.data.length; 29 | }, 30 | 31 | write : function(buffer) { 32 | for (var i = 0; i < this.data.length; i++) { 33 | // not JIS ... 34 | buffer.put(this.data.charCodeAt(i), 8); 35 | } 36 | } 37 | }; 38 | 39 | //--------------------------------------------------------------------- 40 | // ALPHA_NUM 41 | //--------------------------------------------------------------------- 42 | 43 | function ALPHA_NUM(data) { 44 | this.mode = QRMode.MODE_ALPHA_NUM; 45 | this.data = data; 46 | } 47 | 48 | ALPHA_NUM.prototype = { 49 | 50 | getCode: function(code) { 51 | var codes = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'; 52 | return codes.indexOf(code); 53 | }, 54 | 55 | getLength : function(buffer) { 56 | return this.data.length; 57 | }, 58 | 59 | write : function(buffer) { 60 | for (var i = 0; i < this.data.length; i++) { 61 | if (this.data[i+1]) { 62 | buffer.put((45 * this.getCode(this.data[i])) + this.getCode(this.data[i+1]), 11); 63 | } 64 | else { 65 | buffer.put(this.getCode(this.data[i]), 6); 66 | } 67 | i++; 68 | } 69 | } 70 | }; 71 | 72 | //--------------------------------------------------------------------- 73 | // NUMBER 74 | //--------------------------------------------------------------------- 75 | 76 | function NUMBER(data) { 77 | this.mode = QRMode.MODE_NUMBER; 78 | this.data = data; 79 | } 80 | 81 | NUMBER.prototype = { 82 | 83 | getBitLen: function(length) { 84 | var NUMBER_LENGTH = {3: 10, 2: 7, 1: 4}; 85 | return NUMBER_LENGTH[length]; 86 | }, 87 | 88 | getLength : function(buffer) { 89 | return this.data.length; 90 | }, 91 | 92 | write : function(buffer) { 93 | for (var i = 0; i < this.data.length; i++) { 94 | 95 | var chars = this.data[i]; 96 | if (this.data[i+1]) { 97 | chars += this.data[i+1]; 98 | } 99 | if (this.data[i+2]) { 100 | chars += this.data[i+2]; 101 | } 102 | 103 | var bitLength = this.getBitLen(chars.length); 104 | buffer.put(parseInt(chars, 10), bitLength); 105 | 106 | i++; 107 | i++; 108 | } 109 | } 110 | }; 111 | 112 | //--------------------------------------------------------------------- 113 | // QRCode 114 | //--------------------------------------------------------------------- 115 | 116 | function QRCode(typeNumber, errorCorrectLevel, inputMode) { 117 | this.typeNumber = typeNumber; 118 | this.errorCorrectLevel = errorCorrectLevel; 119 | this.inputMode = inputMode; 120 | this.modules = null; 121 | this.moduleCount = 0; 122 | this.dataCache = null; 123 | this.dataList = new Array(); 124 | } 125 | 126 | QRCode.prototype = { 127 | 128 | addData : function(data) { 129 | var newData; 130 | if (this.inputMode === 'NUMBER') { 131 | newData = new NUMBER(data); 132 | } 133 | else if (this.inputMode === 'ALPHA_NUM') { 134 | newData = new ALPHA_NUM(data); 135 | } 136 | else { 137 | newData = new QR8bitByte(data); 138 | } 139 | 140 | this.dataList.push(newData); 141 | this.dataCache = null; 142 | }, 143 | 144 | isDark : function(row, col) { 145 | if (row < 0 || this.moduleCount <= row || col < 0 || this.moduleCount <= col) { 146 | throw new Error(row + "," + col); 147 | } 148 | return this.modules[row][col]; 149 | }, 150 | 151 | getModuleCount : function() { 152 | return this.moduleCount; 153 | }, 154 | 155 | make : function() { 156 | // Calculate automatically typeNumber if provided is < 1 157 | if (this.typeNumber < 1 ){ 158 | var typeNumber = 1; 159 | for (typeNumber = 1; typeNumber < 40; typeNumber++) { 160 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, this.errorCorrectLevel); 161 | var buffer = new QRBitBuffer(); 162 | var totalDataCount = 0; 163 | for (var i = 0; i < rsBlocks.length; i++) { 164 | totalDataCount += rsBlocks[i].dataCount; 165 | } 166 | 167 | for (var i = 0; i < this.dataList.length; i++) { 168 | var data = this.dataList[i]; 169 | buffer.put(data.mode, 4); 170 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) ); 171 | data.write(buffer); 172 | } 173 | if (buffer.getLengthInBits() <= totalDataCount * 8) 174 | break; 175 | } 176 | this.typeNumber = typeNumber; 177 | } 178 | this.makeImpl(false, this.getBestMaskPattern() ); 179 | }, 180 | 181 | makeImpl : function(test, maskPattern) { 182 | 183 | this.moduleCount = this.typeNumber * 4 + 17; 184 | this.modules = new Array(this.moduleCount); 185 | 186 | for (var row = 0; row < this.moduleCount; row++) { 187 | 188 | this.modules[row] = new Array(this.moduleCount); 189 | 190 | for (var col = 0; col < this.moduleCount; col++) { 191 | this.modules[row][col] = null;//(col + row) % 3; 192 | } 193 | } 194 | 195 | this.setupPositionProbePattern(0, 0); 196 | this.setupPositionProbePattern(this.moduleCount - 7, 0); 197 | this.setupPositionProbePattern(0, this.moduleCount - 7); 198 | this.setupPositionAdjustPattern(); 199 | this.setupTimingPattern(); 200 | this.setupTypeInfo(test, maskPattern); 201 | 202 | if (this.typeNumber >= 7) { 203 | this.setupTypeNumber(test); 204 | } 205 | 206 | if (this.dataCache == null) { 207 | this.dataCache = QRCode.createData(this.typeNumber, this.errorCorrectLevel, this.dataList); 208 | } 209 | 210 | this.mapData(this.dataCache, maskPattern); 211 | }, 212 | 213 | setupPositionProbePattern : function(row, col) { 214 | 215 | for (var r = -1; r <= 7; r++) { 216 | 217 | if (row + r <= -1 || this.moduleCount <= row + r) continue; 218 | 219 | for (var c = -1; c <= 7; c++) { 220 | 221 | if (col + c <= -1 || this.moduleCount <= col + c) continue; 222 | 223 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) ) 224 | || (0 <= c && c <= 6 && (r == 0 || r == 6) ) 225 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) { 226 | this.modules[row + r][col + c] = true; 227 | } else { 228 | this.modules[row + r][col + c] = false; 229 | } 230 | } 231 | } 232 | }, 233 | 234 | getBestMaskPattern : function() { 235 | 236 | var minLostPoint = 0; 237 | var pattern = 0; 238 | 239 | for (var i = 0; i < 8; i++) { 240 | 241 | this.makeImpl(true, i); 242 | 243 | var lostPoint = QRUtil.getLostPoint(this); 244 | 245 | if (i == 0 || minLostPoint > lostPoint) { 246 | minLostPoint = lostPoint; 247 | pattern = i; 248 | } 249 | } 250 | 251 | return pattern; 252 | }, 253 | 254 | createMovieClip : function(target_mc, instance_name, depth) { 255 | 256 | var qr_mc = target_mc.createEmptyMovieClip(instance_name, depth); 257 | var cs = 1; 258 | 259 | this.make(); 260 | 261 | for (var row = 0; row < this.modules.length; row++) { 262 | 263 | var y = row * cs; 264 | 265 | for (var col = 0; col < this.modules[row].length; col++) { 266 | 267 | var x = col * cs; 268 | var dark = this.modules[row][col]; 269 | 270 | if (dark) { 271 | qr_mc.beginFill(0, 100); 272 | qr_mc.moveTo(x, y); 273 | qr_mc.lineTo(x + cs, y); 274 | qr_mc.lineTo(x + cs, y + cs); 275 | qr_mc.lineTo(x, y + cs); 276 | qr_mc.endFill(); 277 | } 278 | } 279 | } 280 | 281 | return qr_mc; 282 | }, 283 | 284 | setupTimingPattern : function() { 285 | 286 | for (var r = 8; r < this.moduleCount - 8; r++) { 287 | if (this.modules[r][6] != null) { 288 | continue; 289 | } 290 | this.modules[r][6] = (r % 2 == 0); 291 | } 292 | 293 | for (var c = 8; c < this.moduleCount - 8; c++) { 294 | if (this.modules[6][c] != null) { 295 | continue; 296 | } 297 | this.modules[6][c] = (c % 2 == 0); 298 | } 299 | }, 300 | 301 | setupPositionAdjustPattern : function() { 302 | 303 | var pos = QRUtil.getPatternPosition(this.typeNumber); 304 | 305 | for (var i = 0; i < pos.length; i++) { 306 | 307 | for (var j = 0; j < pos.length; j++) { 308 | 309 | var row = pos[i]; 310 | var col = pos[j]; 311 | 312 | if (this.modules[row][col] != null) { 313 | continue; 314 | } 315 | 316 | for (var r = -2; r <= 2; r++) { 317 | 318 | for (var c = -2; c <= 2; c++) { 319 | 320 | if (r == -2 || r == 2 || c == -2 || c == 2 321 | || (r == 0 && c == 0) ) { 322 | this.modules[row + r][col + c] = true; 323 | } else { 324 | this.modules[row + r][col + c] = false; 325 | } 326 | } 327 | } 328 | } 329 | } 330 | }, 331 | 332 | setupTypeNumber : function(test) { 333 | 334 | var bits = QRUtil.getBCHTypeNumber(this.typeNumber); 335 | 336 | for (var i = 0; i < 18; i++) { 337 | var mod = (!test && ( (bits >> i) & 1) == 1); 338 | this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod; 339 | } 340 | 341 | for (var i = 0; i < 18; i++) { 342 | var mod = (!test && ( (bits >> i) & 1) == 1); 343 | this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod; 344 | } 345 | }, 346 | 347 | setupTypeInfo : function(test, maskPattern) { 348 | 349 | var data = (this.errorCorrectLevel << 3) | maskPattern; 350 | var bits = QRUtil.getBCHTypeInfo(data); 351 | 352 | // vertical 353 | for (var i = 0; i < 15; i++) { 354 | 355 | var mod = (!test && ( (bits >> i) & 1) == 1); 356 | 357 | if (i < 6) { 358 | this.modules[i][8] = mod; 359 | } else if (i < 8) { 360 | this.modules[i + 1][8] = mod; 361 | } else { 362 | this.modules[this.moduleCount - 15 + i][8] = mod; 363 | } 364 | } 365 | 366 | // horizontal 367 | for (var i = 0; i < 15; i++) { 368 | 369 | var mod = (!test && ( (bits >> i) & 1) == 1); 370 | 371 | if (i < 8) { 372 | this.modules[8][this.moduleCount - i - 1] = mod; 373 | } else if (i < 9) { 374 | this.modules[8][15 - i - 1 + 1] = mod; 375 | } else { 376 | this.modules[8][15 - i - 1] = mod; 377 | } 378 | } 379 | 380 | // fixed module 381 | this.modules[this.moduleCount - 8][8] = (!test); 382 | 383 | }, 384 | 385 | mapData : function(data, maskPattern) { 386 | 387 | var inc = -1; 388 | var row = this.moduleCount - 1; 389 | var bitIndex = 7; 390 | var byteIndex = 0; 391 | 392 | for (var col = this.moduleCount - 1; col > 0; col -= 2) { 393 | 394 | if (col == 6) col--; 395 | 396 | while (true) { 397 | 398 | for (var c = 0; c < 2; c++) { 399 | 400 | if (this.modules[row][col - c] == null) { 401 | 402 | var dark = false; 403 | 404 | if (byteIndex < data.length) { 405 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1); 406 | } 407 | 408 | var mask = QRUtil.getMask(maskPattern, row, col - c); 409 | 410 | if (mask) { 411 | dark = !dark; 412 | } 413 | 414 | this.modules[row][col - c] = dark; 415 | bitIndex--; 416 | 417 | if (bitIndex == -1) { 418 | byteIndex++; 419 | bitIndex = 7; 420 | } 421 | } 422 | } 423 | 424 | row += inc; 425 | 426 | if (row < 0 || this.moduleCount <= row) { 427 | row -= inc; 428 | inc = -inc; 429 | break; 430 | } 431 | } 432 | } 433 | 434 | } 435 | 436 | }; 437 | 438 | QRCode.PAD0 = 0xEC; 439 | QRCode.PAD1 = 0x11; 440 | 441 | QRCode.createData = function(typeNumber, errorCorrectLevel, dataList) { 442 | 443 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel); 444 | 445 | var buffer = new QRBitBuffer(); 446 | 447 | for (var i = 0; i < dataList.length; i++) { 448 | var data = dataList[i]; 449 | buffer.put(data.mode, 4); 450 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.mode, typeNumber) ); 451 | data.write(buffer); 452 | } 453 | 454 | // calc num max data. 455 | var totalDataCount = 0; 456 | for (var i = 0; i < rsBlocks.length; i++) { 457 | totalDataCount += rsBlocks[i].dataCount; 458 | } 459 | 460 | if (buffer.getLengthInBits() > totalDataCount * 8) { 461 | throw new Error("code length overflow. (" 462 | + buffer.getLengthInBits() 463 | + ">" 464 | + totalDataCount * 8 465 | + ")"); 466 | } 467 | 468 | // end code 469 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) { 470 | buffer.put(0, 4); 471 | } 472 | 473 | // padding 474 | while (buffer.getLengthInBits() % 8 != 0) { 475 | buffer.putBit(false); 476 | } 477 | 478 | // padding 479 | while (true) { 480 | 481 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 482 | break; 483 | } 484 | buffer.put(QRCode.PAD0, 8); 485 | 486 | if (buffer.getLengthInBits() >= totalDataCount * 8) { 487 | break; 488 | } 489 | buffer.put(QRCode.PAD1, 8); 490 | } 491 | 492 | return QRCode.createBytes(buffer, rsBlocks); 493 | } 494 | 495 | QRCode.createBytes = function(buffer, rsBlocks) { 496 | 497 | var offset = 0; 498 | 499 | var maxDcCount = 0; 500 | var maxEcCount = 0; 501 | 502 | var dcdata = new Array(rsBlocks.length); 503 | var ecdata = new Array(rsBlocks.length); 504 | 505 | for (var r = 0; r < rsBlocks.length; r++) { 506 | 507 | var dcCount = rsBlocks[r].dataCount; 508 | var ecCount = rsBlocks[r].totalCount - dcCount; 509 | 510 | maxDcCount = Math.max(maxDcCount, dcCount); 511 | maxEcCount = Math.max(maxEcCount, ecCount); 512 | 513 | dcdata[r] = new Array(dcCount); 514 | 515 | for (var i = 0; i < dcdata[r].length; i++) { 516 | dcdata[r][i] = 0xff & buffer.buffer[i + offset]; 517 | } 518 | offset += dcCount; 519 | 520 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); 521 | var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1); 522 | 523 | var modPoly = rawPoly.mod(rsPoly); 524 | ecdata[r] = new Array(rsPoly.getLength() - 1); 525 | for (var i = 0; i < ecdata[r].length; i++) { 526 | var modIndex = i + modPoly.getLength() - ecdata[r].length; 527 | ecdata[r][i] = (modIndex >= 0)? modPoly.get(modIndex) : 0; 528 | } 529 | 530 | } 531 | 532 | var totalCodeCount = 0; 533 | for (var i = 0; i < rsBlocks.length; i++) { 534 | totalCodeCount += rsBlocks[i].totalCount; 535 | } 536 | 537 | var data = new Array(totalCodeCount); 538 | var index = 0; 539 | 540 | for (var i = 0; i < maxDcCount; i++) { 541 | for (var r = 0; r < rsBlocks.length; r++) { 542 | if (i < dcdata[r].length) { 543 | data[index++] = dcdata[r][i]; 544 | } 545 | } 546 | } 547 | 548 | for (var i = 0; i < maxEcCount; i++) { 549 | for (var r = 0; r < rsBlocks.length; r++) { 550 | if (i < ecdata[r].length) { 551 | data[index++] = ecdata[r][i]; 552 | } 553 | } 554 | } 555 | 556 | return data; 557 | 558 | } 559 | 560 | //--------------------------------------------------------------------- 561 | // QRMode 562 | //--------------------------------------------------------------------- 563 | 564 | var QRMode = { 565 | MODE_NUMBER : 1 << 0, 566 | MODE_ALPHA_NUM : 1 << 1, 567 | MODE_8BIT_BYTE : 1 << 2, 568 | MODE_KANJI : 1 << 3 569 | }; 570 | 571 | //--------------------------------------------------------------------- 572 | // QRErrorCorrectLevel 573 | //--------------------------------------------------------------------- 574 | 575 | var QRErrorCorrectLevel = { 576 | L : 1, 577 | M : 0, 578 | Q : 3, 579 | H : 2 580 | }; 581 | 582 | //--------------------------------------------------------------------- 583 | // QRMaskPattern 584 | //--------------------------------------------------------------------- 585 | 586 | var QRMaskPattern = { 587 | PATTERN000 : 0, 588 | PATTERN001 : 1, 589 | PATTERN010 : 2, 590 | PATTERN011 : 3, 591 | PATTERN100 : 4, 592 | PATTERN101 : 5, 593 | PATTERN110 : 6, 594 | PATTERN111 : 7 595 | }; 596 | 597 | //--------------------------------------------------------------------- 598 | // QRUtil 599 | //--------------------------------------------------------------------- 600 | 601 | var QRUtil = { 602 | 603 | PATTERN_POSITION_TABLE : [ 604 | [], 605 | [6, 18], 606 | [6, 22], 607 | [6, 26], 608 | [6, 30], 609 | [6, 34], 610 | [6, 22, 38], 611 | [6, 24, 42], 612 | [6, 26, 46], 613 | [6, 28, 50], 614 | [6, 30, 54], 615 | [6, 32, 58], 616 | [6, 34, 62], 617 | [6, 26, 46, 66], 618 | [6, 26, 48, 70], 619 | [6, 26, 50, 74], 620 | [6, 30, 54, 78], 621 | [6, 30, 56, 82], 622 | [6, 30, 58, 86], 623 | [6, 34, 62, 90], 624 | [6, 28, 50, 72, 94], 625 | [6, 26, 50, 74, 98], 626 | [6, 30, 54, 78, 102], 627 | [6, 28, 54, 80, 106], 628 | [6, 32, 58, 84, 110], 629 | [6, 30, 58, 86, 114], 630 | [6, 34, 62, 90, 118], 631 | [6, 26, 50, 74, 98, 122], 632 | [6, 30, 54, 78, 102, 126], 633 | [6, 26, 52, 78, 104, 130], 634 | [6, 30, 56, 82, 108, 134], 635 | [6, 34, 60, 86, 112, 138], 636 | [6, 30, 58, 86, 114, 142], 637 | [6, 34, 62, 90, 118, 146], 638 | [6, 30, 54, 78, 102, 126, 150], 639 | [6, 24, 50, 76, 102, 128, 154], 640 | [6, 28, 54, 80, 106, 132, 158], 641 | [6, 32, 58, 84, 110, 136, 162], 642 | [6, 26, 54, 82, 110, 138, 166], 643 | [6, 30, 58, 86, 114, 142, 170] 644 | ], 645 | 646 | G15 : (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0), 647 | G18 : (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0), 648 | G15_MASK : (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), 649 | 650 | getBCHTypeInfo : function(data) { 651 | var d = data << 10; 652 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { 653 | d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) ); 654 | } 655 | return ( (data << 10) | d) ^ QRUtil.G15_MASK; 656 | }, 657 | 658 | getBCHTypeNumber : function(data) { 659 | var d = data << 12; 660 | while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { 661 | d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) ); 662 | } 663 | return (data << 12) | d; 664 | }, 665 | 666 | getBCHDigit : function(data) { 667 | 668 | var digit = 0; 669 | 670 | while (data != 0) { 671 | digit++; 672 | data >>>= 1; 673 | } 674 | 675 | return digit; 676 | }, 677 | 678 | getPatternPosition : function(typeNumber) { 679 | return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; 680 | }, 681 | 682 | getMask : function(maskPattern, i, j) { 683 | 684 | switch (maskPattern) { 685 | 686 | case QRMaskPattern.PATTERN000 : return (i + j) % 2 == 0; 687 | case QRMaskPattern.PATTERN001 : return i % 2 == 0; 688 | case QRMaskPattern.PATTERN010 : return j % 3 == 0; 689 | case QRMaskPattern.PATTERN011 : return (i + j) % 3 == 0; 690 | case QRMaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; 691 | case QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0; 692 | case QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; 693 | case QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; 694 | 695 | default : 696 | throw new Error("bad maskPattern:" + maskPattern); 697 | } 698 | }, 699 | 700 | getErrorCorrectPolynomial : function(errorCorrectLength) { 701 | 702 | var a = new QRPolynomial([1], 0); 703 | 704 | for (var i = 0; i < errorCorrectLength; i++) { 705 | a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0) ); 706 | } 707 | 708 | return a; 709 | }, 710 | 711 | getLengthInBits : function(mode, type) { 712 | 713 | if (1 <= type && type < 10) { 714 | 715 | // 1 - 9 716 | 717 | switch(mode) { 718 | case QRMode.MODE_NUMBER : return 10; 719 | case QRMode.MODE_ALPHA_NUM : return 9; 720 | case QRMode.MODE_8BIT_BYTE : return 8; 721 | case QRMode.MODE_KANJI : return 8; 722 | default : 723 | throw new Error("mode:" + mode); 724 | } 725 | 726 | } else if (type < 27) { 727 | 728 | // 10 - 26 729 | 730 | switch(mode) { 731 | case QRMode.MODE_NUMBER : return 12; 732 | case QRMode.MODE_ALPHA_NUM : return 11; 733 | case QRMode.MODE_8BIT_BYTE : return 16; 734 | case QRMode.MODE_KANJI : return 10; 735 | default : 736 | throw new Error("mode:" + mode); 737 | } 738 | 739 | } else if (type < 41) { 740 | 741 | // 27 - 40 742 | 743 | switch(mode) { 744 | case QRMode.MODE_NUMBER : return 14; 745 | case QRMode.MODE_ALPHA_NUM : return 13; 746 | case QRMode.MODE_8BIT_BYTE : return 16; 747 | case QRMode.MODE_KANJI : return 12; 748 | default : 749 | throw new Error("mode:" + mode); 750 | } 751 | 752 | } else { 753 | throw new Error("type:" + type); 754 | } 755 | }, 756 | 757 | getLostPoint : function(qrCode) { 758 | 759 | var moduleCount = qrCode.getModuleCount(); 760 | 761 | var lostPoint = 0; 762 | 763 | // LEVEL1 764 | 765 | for (var row = 0; row < moduleCount; row++) { 766 | 767 | for (var col = 0; col < moduleCount; col++) { 768 | 769 | var sameCount = 0; 770 | var dark = qrCode.isDark(row, col); 771 | 772 | for (var r = -1; r <= 1; r++) { 773 | 774 | if (row + r < 0 || moduleCount <= row + r) { 775 | continue; 776 | } 777 | 778 | for (var c = -1; c <= 1; c++) { 779 | 780 | if (col + c < 0 || moduleCount <= col + c) { 781 | continue; 782 | } 783 | 784 | if (r == 0 && c == 0) { 785 | continue; 786 | } 787 | 788 | if (dark == qrCode.isDark(row + r, col + c) ) { 789 | sameCount++; 790 | } 791 | } 792 | } 793 | 794 | if (sameCount > 5) { 795 | lostPoint += (3 + sameCount - 5); 796 | } 797 | } 798 | } 799 | 800 | // LEVEL2 801 | 802 | for (var row = 0; row < moduleCount - 1; row++) { 803 | for (var col = 0; col < moduleCount - 1; col++) { 804 | var count = 0; 805 | if (qrCode.isDark(row, col ) ) count++; 806 | if (qrCode.isDark(row + 1, col ) ) count++; 807 | if (qrCode.isDark(row, col + 1) ) count++; 808 | if (qrCode.isDark(row + 1, col + 1) ) count++; 809 | if (count == 0 || count == 4) { 810 | lostPoint += 3; 811 | } 812 | } 813 | } 814 | 815 | // LEVEL3 816 | 817 | for (var row = 0; row < moduleCount; row++) { 818 | for (var col = 0; col < moduleCount - 6; col++) { 819 | if (qrCode.isDark(row, col) 820 | && !qrCode.isDark(row, col + 1) 821 | && qrCode.isDark(row, col + 2) 822 | && qrCode.isDark(row, col + 3) 823 | && qrCode.isDark(row, col + 4) 824 | && !qrCode.isDark(row, col + 5) 825 | && qrCode.isDark(row, col + 6) ) { 826 | lostPoint += 40; 827 | } 828 | } 829 | } 830 | 831 | for (var col = 0; col < moduleCount; col++) { 832 | for (var row = 0; row < moduleCount - 6; row++) { 833 | if (qrCode.isDark(row, col) 834 | && !qrCode.isDark(row + 1, col) 835 | && qrCode.isDark(row + 2, col) 836 | && qrCode.isDark(row + 3, col) 837 | && qrCode.isDark(row + 4, col) 838 | && !qrCode.isDark(row + 5, col) 839 | && qrCode.isDark(row + 6, col) ) { 840 | lostPoint += 40; 841 | } 842 | } 843 | } 844 | 845 | // LEVEL4 846 | 847 | var darkCount = 0; 848 | 849 | for (var col = 0; col < moduleCount; col++) { 850 | for (var row = 0; row < moduleCount; row++) { 851 | if (qrCode.isDark(row, col) ) { 852 | darkCount++; 853 | } 854 | } 855 | } 856 | 857 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; 858 | lostPoint += ratio * 10; 859 | 860 | return lostPoint; 861 | } 862 | 863 | }; 864 | 865 | 866 | //--------------------------------------------------------------------- 867 | // QRMath 868 | //--------------------------------------------------------------------- 869 | 870 | var QRMath = { 871 | 872 | glog : function(n) { 873 | 874 | if (n < 1) { 875 | throw new Error("glog(" + n + ")"); 876 | } 877 | 878 | return QRMath.LOG_TABLE[n]; 879 | }, 880 | 881 | gexp : function(n) { 882 | 883 | while (n < 0) { 884 | n += 255; 885 | } 886 | 887 | while (n >= 256) { 888 | n -= 255; 889 | } 890 | 891 | return QRMath.EXP_TABLE[n]; 892 | }, 893 | 894 | EXP_TABLE : new Array(256), 895 | 896 | LOG_TABLE : new Array(256) 897 | 898 | }; 899 | 900 | for (var i = 0; i < 8; i++) { 901 | QRMath.EXP_TABLE[i] = 1 << i; 902 | } 903 | for (var i = 8; i < 256; i++) { 904 | QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] 905 | ^ QRMath.EXP_TABLE[i - 5] 906 | ^ QRMath.EXP_TABLE[i - 6] 907 | ^ QRMath.EXP_TABLE[i - 8]; 908 | } 909 | for (var i = 0; i < 255; i++) { 910 | QRMath.LOG_TABLE[QRMath.EXP_TABLE[i] ] = i; 911 | } 912 | 913 | //--------------------------------------------------------------------- 914 | // QRPolynomial 915 | //--------------------------------------------------------------------- 916 | 917 | function QRPolynomial(num, shift) { 918 | 919 | if (num.length == undefined) { 920 | throw new Error(num.length + "/" + shift); 921 | } 922 | 923 | var offset = 0; 924 | 925 | while (offset < num.length && num[offset] == 0) { 926 | offset++; 927 | } 928 | 929 | this.num = new Array(num.length - offset + shift); 930 | for (var i = 0; i < num.length - offset; i++) { 931 | this.num[i] = num[i + offset]; 932 | } 933 | } 934 | 935 | QRPolynomial.prototype = { 936 | 937 | get : function(index) { 938 | return this.num[index]; 939 | }, 940 | 941 | getLength : function() { 942 | return this.num.length; 943 | }, 944 | 945 | multiply : function(e) { 946 | 947 | var num = new Array(this.getLength() + e.getLength() - 1); 948 | 949 | for (var i = 0; i < this.getLength(); i++) { 950 | for (var j = 0; j < e.getLength(); j++) { 951 | num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i) ) + QRMath.glog(e.get(j) ) ); 952 | } 953 | } 954 | 955 | return new QRPolynomial(num, 0); 956 | }, 957 | 958 | mod : function(e) { 959 | 960 | if (this.getLength() - e.getLength() < 0) { 961 | return this; 962 | } 963 | 964 | var ratio = QRMath.glog(this.get(0) ) - QRMath.glog(e.get(0) ); 965 | 966 | var num = new Array(this.getLength() ); 967 | 968 | for (var i = 0; i < this.getLength(); i++) { 969 | num[i] = this.get(i); 970 | } 971 | 972 | for (var i = 0; i < e.getLength(); i++) { 973 | num[i] ^= QRMath.gexp(QRMath.glog(e.get(i) ) + ratio); 974 | } 975 | 976 | // recursive call 977 | return new QRPolynomial(num, 0).mod(e); 978 | } 979 | }; 980 | 981 | //--------------------------------------------------------------------- 982 | // QRRSBlock 983 | //--------------------------------------------------------------------- 984 | 985 | function QRRSBlock(totalCount, dataCount) { 986 | this.totalCount = totalCount; 987 | this.dataCount = dataCount; 988 | } 989 | 990 | QRRSBlock.RS_BLOCK_TABLE = [ 991 | 992 | // L 993 | // M 994 | // Q 995 | // H 996 | 997 | // 1 998 | [1, 26, 19], 999 | [1, 26, 16], 1000 | [1, 26, 13], 1001 | [1, 26, 9], 1002 | 1003 | // 2 1004 | [1, 44, 34], 1005 | [1, 44, 28], 1006 | [1, 44, 22], 1007 | [1, 44, 16], 1008 | 1009 | // 3 1010 | [1, 70, 55], 1011 | [1, 70, 44], 1012 | [2, 35, 17], 1013 | [2, 35, 13], 1014 | 1015 | // 4 1016 | [1, 100, 80], 1017 | [2, 50, 32], 1018 | [2, 50, 24], 1019 | [4, 25, 9], 1020 | 1021 | // 5 1022 | [1, 134, 108], 1023 | [2, 67, 43], 1024 | [2, 33, 15, 2, 34, 16], 1025 | [2, 33, 11, 2, 34, 12], 1026 | 1027 | // 6 1028 | [2, 86, 68], 1029 | [4, 43, 27], 1030 | [4, 43, 19], 1031 | [4, 43, 15], 1032 | 1033 | // 7 1034 | [2, 98, 78], 1035 | [4, 49, 31], 1036 | [2, 32, 14, 4, 33, 15], 1037 | [4, 39, 13, 1, 40, 14], 1038 | 1039 | // 8 1040 | [2, 121, 97], 1041 | [2, 60, 38, 2, 61, 39], 1042 | [4, 40, 18, 2, 41, 19], 1043 | [4, 40, 14, 2, 41, 15], 1044 | 1045 | // 9 1046 | [2, 146, 116], 1047 | [3, 58, 36, 2, 59, 37], 1048 | [4, 36, 16, 4, 37, 17], 1049 | [4, 36, 12, 4, 37, 13], 1050 | 1051 | // 10 1052 | [2, 86, 68, 2, 87, 69], 1053 | [4, 69, 43, 1, 70, 44], 1054 | [6, 43, 19, 2, 44, 20], 1055 | [6, 43, 15, 2, 44, 16], 1056 | 1057 | // 11 1058 | [4, 101, 81], 1059 | [1, 80, 50, 4, 81, 51], 1060 | [4, 50, 22, 4, 51, 23], 1061 | [3, 36, 12, 8, 37, 13], 1062 | 1063 | // 12 1064 | [2, 116, 92, 2, 117, 93], 1065 | [6, 58, 36, 2, 59, 37], 1066 | [4, 46, 20, 6, 47, 21], 1067 | [7, 42, 14, 4, 43, 15], 1068 | 1069 | // 13 1070 | [4, 133, 107], 1071 | [8, 59, 37, 1, 60, 38], 1072 | [8, 44, 20, 4, 45, 21], 1073 | [12, 33, 11, 4, 34, 12], 1074 | 1075 | // 14 1076 | [3, 145, 115, 1, 146, 116], 1077 | [4, 64, 40, 5, 65, 41], 1078 | [11, 36, 16, 5, 37, 17], 1079 | [11, 36, 12, 5, 37, 13], 1080 | 1081 | // 15 1082 | [5, 109, 87, 1, 110, 88], 1083 | [5, 65, 41, 5, 66, 42], 1084 | [5, 54, 24, 7, 55, 25], 1085 | [11, 36, 12], 1086 | 1087 | // 16 1088 | [5, 122, 98, 1, 123, 99], 1089 | [7, 73, 45, 3, 74, 46], 1090 | [15, 43, 19, 2, 44, 20], 1091 | [3, 45, 15, 13, 46, 16], 1092 | 1093 | // 17 1094 | [1, 135, 107, 5, 136, 108], 1095 | [10, 74, 46, 1, 75, 47], 1096 | [1, 50, 22, 15, 51, 23], 1097 | [2, 42, 14, 17, 43, 15], 1098 | 1099 | // 18 1100 | [5, 150, 120, 1, 151, 121], 1101 | [9, 69, 43, 4, 70, 44], 1102 | [17, 50, 22, 1, 51, 23], 1103 | [2, 42, 14, 19, 43, 15], 1104 | 1105 | // 19 1106 | [3, 141, 113, 4, 142, 114], 1107 | [3, 70, 44, 11, 71, 45], 1108 | [17, 47, 21, 4, 48, 22], 1109 | [9, 39, 13, 16, 40, 14], 1110 | 1111 | // 20 1112 | [3, 135, 107, 5, 136, 108], 1113 | [3, 67, 41, 13, 68, 42], 1114 | [15, 54, 24, 5, 55, 25], 1115 | [15, 43, 15, 10, 44, 16], 1116 | 1117 | // 21 1118 | [4, 144, 116, 4, 145, 117], 1119 | [17, 68, 42], 1120 | [17, 50, 22, 6, 51, 23], 1121 | [19, 46, 16, 6, 47, 17], 1122 | 1123 | // 22 1124 | [2, 139, 111, 7, 140, 112], 1125 | [17, 74, 46], 1126 | [7, 54, 24, 16, 55, 25], 1127 | [34, 37, 13], 1128 | 1129 | // 23 1130 | [4, 151, 121, 5, 152, 122], 1131 | [4, 75, 47, 14, 76, 48], 1132 | [11, 54, 24, 14, 55, 25], 1133 | [16, 45, 15, 14, 46, 16], 1134 | 1135 | // 24 1136 | [6, 147, 117, 4, 148, 118], 1137 | [6, 73, 45, 14, 74, 46], 1138 | [11, 54, 24, 16, 55, 25], 1139 | [30, 46, 16, 2, 47, 17], 1140 | 1141 | // 25 1142 | [8, 132, 106, 4, 133, 107], 1143 | [8, 75, 47, 13, 76, 48], 1144 | [7, 54, 24, 22, 55, 25], 1145 | [22, 45, 15, 13, 46, 16], 1146 | 1147 | // 26 1148 | [10, 142, 114, 2, 143, 115], 1149 | [19, 74, 46, 4, 75, 47], 1150 | [28, 50, 22, 6, 51, 23], 1151 | [33, 46, 16, 4, 47, 17], 1152 | 1153 | // 27 1154 | [8, 152, 122, 4, 153, 123], 1155 | [22, 73, 45, 3, 74, 46], 1156 | [8, 53, 23, 26, 54, 24], 1157 | [12, 45, 15, 28, 46, 16], 1158 | 1159 | // 28 1160 | [3, 147, 117, 10, 148, 118], 1161 | [3, 73, 45, 23, 74, 46], 1162 | [4, 54, 24, 31, 55, 25], 1163 | [11, 45, 15, 31, 46, 16], 1164 | 1165 | // 29 1166 | [7, 146, 116, 7, 147, 117], 1167 | [21, 73, 45, 7, 74, 46], 1168 | [1, 53, 23, 37, 54, 24], 1169 | [19, 45, 15, 26, 46, 16], 1170 | 1171 | // 30 1172 | [5, 145, 115, 10, 146, 116], 1173 | [19, 75, 47, 10, 76, 48], 1174 | [15, 54, 24, 25, 55, 25], 1175 | [23, 45, 15, 25, 46, 16], 1176 | 1177 | // 31 1178 | [13, 145, 115, 3, 146, 116], 1179 | [2, 74, 46, 29, 75, 47], 1180 | [42, 54, 24, 1, 55, 25], 1181 | [23, 45, 15, 28, 46, 16], 1182 | 1183 | // 32 1184 | [17, 145, 115], 1185 | [10, 74, 46, 23, 75, 47], 1186 | [10, 54, 24, 35, 55, 25], 1187 | [19, 45, 15, 35, 46, 16], 1188 | 1189 | // 33 1190 | [17, 145, 115, 1, 146, 116], 1191 | [14, 74, 46, 21, 75, 47], 1192 | [29, 54, 24, 19, 55, 25], 1193 | [11, 45, 15, 46, 46, 16], 1194 | 1195 | // 34 1196 | [13, 145, 115, 6, 146, 116], 1197 | [14, 74, 46, 23, 75, 47], 1198 | [44, 54, 24, 7, 55, 25], 1199 | [59, 46, 16, 1, 47, 17], 1200 | 1201 | // 35 1202 | [12, 151, 121, 7, 152, 122], 1203 | [12, 75, 47, 26, 76, 48], 1204 | [39, 54, 24, 14, 55, 25], 1205 | [22, 45, 15, 41, 46, 16], 1206 | 1207 | // 36 1208 | [6, 151, 121, 14, 152, 122], 1209 | [6, 75, 47, 34, 76, 48], 1210 | [46, 54, 24, 10, 55, 25], 1211 | [2, 45, 15, 64, 46, 16], 1212 | 1213 | // 37 1214 | [17, 152, 122, 4, 153, 123], 1215 | [29, 74, 46, 14, 75, 47], 1216 | [49, 54, 24, 10, 55, 25], 1217 | [24, 45, 15, 46, 46, 16], 1218 | 1219 | // 38 1220 | [4, 152, 122, 18, 153, 123], 1221 | [13, 74, 46, 32, 75, 47], 1222 | [48, 54, 24, 14, 55, 25], 1223 | [42, 45, 15, 32, 46, 16], 1224 | 1225 | // 39 1226 | [20, 147, 117, 4, 148, 118], 1227 | [40, 75, 47, 7, 76, 48], 1228 | [43, 54, 24, 22, 55, 25], 1229 | [10, 45, 15, 67, 46, 16], 1230 | 1231 | // 40 1232 | [19, 148, 118, 6, 149, 119], 1233 | [18, 75, 47, 31, 76, 48], 1234 | [34, 54, 24, 34, 55, 25], 1235 | [20, 45, 15, 61, 46, 16] 1236 | ]; 1237 | 1238 | QRRSBlock.getRSBlocks = function(typeNumber, errorCorrectLevel) { 1239 | 1240 | var rsBlock = QRRSBlock.getRsBlockTable(typeNumber, errorCorrectLevel); 1241 | 1242 | if (rsBlock == undefined) { 1243 | throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + errorCorrectLevel); 1244 | } 1245 | 1246 | var length = rsBlock.length / 3; 1247 | 1248 | var list = new Array(); 1249 | 1250 | for (var i = 0; i < length; i++) { 1251 | 1252 | var count = rsBlock[i * 3 + 0]; 1253 | var totalCount = rsBlock[i * 3 + 1]; 1254 | var dataCount = rsBlock[i * 3 + 2]; 1255 | 1256 | for (var j = 0; j < count; j++) { 1257 | list.push(new QRRSBlock(totalCount, dataCount) ); 1258 | } 1259 | } 1260 | 1261 | return list; 1262 | } 1263 | 1264 | QRRSBlock.getRsBlockTable = function(typeNumber, errorCorrectLevel) { 1265 | 1266 | switch(errorCorrectLevel) { 1267 | case QRErrorCorrectLevel.L : 1268 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0]; 1269 | case QRErrorCorrectLevel.M : 1270 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1]; 1271 | case QRErrorCorrectLevel.Q : 1272 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2]; 1273 | case QRErrorCorrectLevel.H : 1274 | return QRRSBlock.RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3]; 1275 | default : 1276 | return undefined; 1277 | } 1278 | } 1279 | 1280 | //--------------------------------------------------------------------- 1281 | // QRBitBuffer 1282 | //--------------------------------------------------------------------- 1283 | 1284 | function QRBitBuffer() { 1285 | this.buffer = new Array(); 1286 | this.length = 0; 1287 | } 1288 | 1289 | QRBitBuffer.prototype = { 1290 | 1291 | get : function(index) { 1292 | var bufIndex = Math.floor(index / 8); 1293 | return ( (this.buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1; 1294 | }, 1295 | 1296 | put : function(num, length) { 1297 | for (var i = 0; i < length; i++) { 1298 | this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1); 1299 | } 1300 | }, 1301 | 1302 | getLengthInBits : function() { 1303 | return this.length; 1304 | }, 1305 | 1306 | putBit : function(bit) { 1307 | 1308 | var bufIndex = Math.floor(this.length / 8); 1309 | if (this.buffer.length <= bufIndex) { 1310 | this.buffer.push(0); 1311 | } 1312 | 1313 | if (bit) { 1314 | this.buffer[bufIndex] |= (0x80 >>> (this.length % 8) ); 1315 | } 1316 | 1317 | this.length++; 1318 | } 1319 | }; 1320 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-qr", 3 | "version": "0.2.0", 4 | "description": "QR code generator for AngularJS", 5 | "keywords": ["qr", "qrcode", "angular"], 6 | "authors": ["Jan Antala "], 7 | "license": "MIT", 8 | "homepage": "https://github.com/janantala/angular-qr", 9 | "main": "./src/angular-qr.js", 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "gulp": "~3.5.0", 13 | "gulp-util": "~2.2.9", 14 | "gulp-uglify": "~0.2.0", 15 | "gulp-header": "~1.0.2", 16 | "gulp-concat": "~2.1.7", 17 | "gulp-rename": "~0.2.2", 18 | "gulp-jshint": "~1.3.4", 19 | "gulp-karma": "~0.0.2", 20 | "karma": "~0.12.1", 21 | "karma-jasmine": "~0.2.2", 22 | "karma-chrome-launcher": "~0.1.2", 23 | "karma-firefox-launcher": "~0.1.3", 24 | "conventional-changelog": "~0.0.11" 25 | }, 26 | "scripts": {}, 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/janantala/angular-qr.git" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/angular-qr.js: -------------------------------------------------------------------------------- 1 | (function(QRCode){ 2 | 'use strict'; 3 | 4 | angular.module('ja.qr', []) 5 | .controller('QrCtrl', ['$scope', function($scope){ 6 | $scope.getTypeNumeber = function(){ 7 | return $scope.typeNumber || 0; 8 | }; 9 | 10 | $scope.getCorrection = function(){ 11 | var levels = { 12 | 'L': 1, 13 | 'M': 0, 14 | 'Q': 3, 15 | 'H': 2 16 | }; 17 | 18 | var correctionLevel = $scope.correctionLevel || 0; 19 | return levels[correctionLevel] || 0; 20 | }; 21 | 22 | $scope.getText = function(){ 23 | return $scope.text || ''; 24 | }; 25 | 26 | $scope.getSize = function(){ 27 | return $scope.size || 250; 28 | }; 29 | 30 | $scope.isNUMBER = function(text){ 31 | var ALLOWEDCHARS = /^[0-9]*$/; 32 | return ALLOWEDCHARS.test(text); 33 | }; 34 | 35 | $scope.isALPHA_NUM = function(text){ 36 | var ALLOWEDCHARS = /^[0-9A-Z $%*+\-./:]*$/; 37 | return ALLOWEDCHARS.test(text); 38 | }; 39 | 40 | $scope.is8bit = function(text){ 41 | for (var i = 0; i < text.length; i++) { 42 | var code = text.charCodeAt(i); 43 | if (code > 255) { 44 | return false; 45 | } 46 | } 47 | return true; 48 | }; 49 | 50 | $scope.checkInputMode = function(inputMode, text){ 51 | if (inputMode === 'NUMBER' && !$scope.isNUMBER(text)) { 52 | throw new Error('The `NUMBER` input mode is invalid for text.'); 53 | } 54 | else if (inputMode === 'ALPHA_NUM' && !$scope.isALPHA_NUM(text)) { 55 | throw new Error('The `ALPHA_NUM` input mode is invalid for text.'); 56 | } 57 | else if (inputMode === '8bit' && !$scope.is8bit(text)) { 58 | throw new Error('The `8bit` input mode is invalid for text.'); 59 | } 60 | else if (!$scope.is8bit(text)) { 61 | throw new Error('Input mode is invalid for text.'); 62 | } 63 | 64 | return true; 65 | }; 66 | 67 | $scope.getInputMode = function(text){ 68 | var inputMode = $scope.inputMode; 69 | inputMode = inputMode || ($scope.isNUMBER(text) ? 'NUMBER' : undefined); 70 | inputMode = inputMode || ($scope.isALPHA_NUM(text) ? 'ALPHA_NUM' : undefined); 71 | inputMode = inputMode || ($scope.is8bit(text) ? '8bit' : ''); 72 | 73 | return $scope.checkInputMode(inputMode, text) ? inputMode : ''; 74 | }; 75 | }]) 76 | .directive('qr', ['$timeout', '$window', function($timeout, $window){ 77 | 78 | return { 79 | restrict: 'E', 80 | template: '', 81 | scope: { 82 | typeNumber: '=', 83 | correctionLevel: '=', 84 | inputMode: '=', 85 | size: '=', 86 | text: '=', 87 | image: '=' 88 | }, 89 | controller: 'QrCtrl', 90 | link: function postlink(scope, element, attrs){ 91 | 92 | if (scope.text === undefined) { 93 | throw new Error('The `text` attribute is required.'); 94 | } 95 | 96 | var canvas = element.find('canvas')[0]; 97 | var canvas2D = !!$window.CanvasRenderingContext2D; 98 | 99 | scope.TYPE_NUMBER = scope.getTypeNumeber(); 100 | scope.TEXT = scope.getText(); 101 | scope.CORRECTION = scope.getCorrection(); 102 | scope.SIZE = scope.getSize(); 103 | scope.INPUT_MODE = scope.getInputMode(scope.TEXT); 104 | scope.canvasImage = ''; 105 | 106 | var draw = function(context, qr, modules, tile){ 107 | for (var row = 0; row < modules; row++) { 108 | for (var col = 0; col < modules; col++) { 109 | var w = (Math.ceil((col + 1) * tile) - Math.floor(col * tile)), 110 | h = (Math.ceil((row + 1) * tile) - Math.floor(row * tile)); 111 | context.fillStyle = qr.isDark(row, col) ? '#000' : '#fff'; 112 | context.fillRect(Math.round(col * tile), Math.round(row * tile), w, h); 113 | } 114 | } 115 | }; 116 | 117 | var render = function(canvas, value, typeNumber, correction, size, inputMode){ 118 | var trim = /^\s+|\s+$/g; 119 | var text = value.replace(trim, ''); 120 | 121 | var qr = new QRCode(typeNumber, correction, inputMode); 122 | qr.addData(text); 123 | qr.make(); 124 | 125 | var context = canvas.getContext('2d'); 126 | 127 | var modules = qr.getModuleCount(); 128 | var tile = size / modules; 129 | canvas.width = canvas.height = size; 130 | 131 | if (canvas2D) { 132 | draw(context, qr, modules, tile); 133 | scope.canvasImage = canvas.toDataURL() || ''; 134 | } 135 | }; 136 | 137 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 138 | 139 | $timeout(function(){ 140 | scope.$watch('text', function(value, old){ 141 | if (value !== old) { 142 | scope.TEXT = scope.getText(); 143 | scope.INPUT_MODE = scope.getInputMode(scope.TEXT); 144 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 145 | } 146 | }); 147 | 148 | scope.$watch('correctionLevel', function(value, old){ 149 | if (value !== old) { 150 | scope.CORRECTION = scope.getCorrection(); 151 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 152 | } 153 | }); 154 | 155 | scope.$watch('typeNumber', function(value, old){ 156 | if (value !== old) { 157 | scope.TYPE_NUMBER = scope.getTypeNumeber(); 158 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 159 | } 160 | }); 161 | 162 | scope.$watch('size', function(value, old){ 163 | if (value !== old) { 164 | scope.SIZE = scope.getSize(); 165 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 166 | } 167 | }); 168 | 169 | scope.$watch('inputMode', function(value, old){ 170 | if (value !== old) { 171 | scope.INPUT_MODE = scope.getInputMode(scope.TEXT); 172 | render(canvas, scope.TEXT, scope.TYPE_NUMBER, scope.CORRECTION, scope.SIZE, scope.INPUT_MODE); 173 | } 174 | }); 175 | }); 176 | 177 | } 178 | }; 179 | }]); 180 | 181 | })(window.QRCode); 182 | -------------------------------------------------------------------------------- /test/unit.spec.js: -------------------------------------------------------------------------------- 1 | describe('ja.qr', function() { 2 | 3 | beforeEach(module('ja.qr')); 4 | 5 | // var elm, scope, ctrl; 6 | 7 | // beforeEach(inject(function($rootScope, $compile) { 8 | // elm = angular.element(''); 9 | // scope = $rootScope; 10 | 11 | // $compile(elm)(scope); 12 | // scope.$digest(); 13 | // })); 14 | 15 | describe('QrCtrl', function() { 16 | 17 | var scope, ctrl; 18 | beforeEach(inject(function($rootScope, $controller) { 19 | scope = $rootScope.$new(); 20 | ctrl = $controller('QrCtrl', {$scope: scope }); 21 | })); 22 | 23 | it('should detect NUMBER text', function() { 24 | expect(scope.isNUMBER('123')).toBe(true); 25 | expect(scope.isALPHA_NUM('123')).toBe(true); 26 | expect(scope.is8bit('123')).toBe(true); 27 | }); 28 | 29 | it('should detect ALPHA_NUM text', function() { 30 | expect(scope.isNUMBER('A123')).toBe(false); 31 | expect(scope.isALPHA_NUM('A123')).toBe(true); 32 | expect(scope.is8bit('A123')).toBe(true); 33 | }); 34 | 35 | it('should detect 8bit text', function() { 36 | expect(scope.isNUMBER('aA123')).toBe(false); 37 | expect(scope.isALPHA_NUM('aA123')).toBe(false); 38 | expect(scope.is8bit('aA123')).toBe(true); 39 | }); 40 | 41 | it('should detect non 8bit text', function() { 42 | expect(scope.isNUMBER('čaA123')).toBe(false); 43 | expect(scope.isALPHA_NUM('čaA123')).toBe(false); 44 | expect(scope.is8bit('čaA123')).toBe(false); 45 | }); 46 | 47 | it('should check text input mode', function() { 48 | expect(scope.checkInputMode('NUMBER', '123')).toBe(true); 49 | expect(scope.checkInputMode('ALPHA_NUM', '123')).toBe(true); 50 | expect(scope.checkInputMode('8bit', '123')).toBe(true); 51 | 52 | expect(scope.checkInputMode('ALPHA_NUM', 'A123')).toBe(true); 53 | expect(scope.checkInputMode('8bit', 'A123')).toBe(true); 54 | 55 | expect(scope.checkInputMode('8bit', 'aA123')).toBe(true); 56 | }); 57 | 58 | it('should get the simpliest input mode', function() { 59 | expect(scope.getInputMode('123')).toBe('NUMBER'); 60 | expect(scope.getInputMode('123')).not.toBe('ALPHA_NUM'); 61 | expect(scope.getInputMode('123')).not.toBe('8bit'); 62 | 63 | expect(scope.getInputMode('A123')).not.toBe('NUMBER'); 64 | expect(scope.getInputMode('A123')).toBe('ALPHA_NUM'); 65 | expect(scope.getInputMode('A123')).not.toBe('8bit'); 66 | 67 | expect(scope.getInputMode('aA123')).not.toBe('NUMBER'); 68 | expect(scope.getInputMode('aA123')).not.toBe('ALPHA_NUM'); 69 | expect(scope.getInputMode('aA123')).toBe('8bit'); 70 | 71 | expect(scope.getInputMode('A,123')).not.toBe('NUMBER'); 72 | expect(scope.getInputMode('A,123')).not.toBe('ALPHA_NUM'); 73 | expect(scope.getInputMode('A,123')).toBe('8bit'); 74 | }); 75 | 76 | }); 77 | }); --------------------------------------------------------------------------------