├── demo
├── demo.png
└── weapp-demo
│ ├── pages
│ ├── index
│ │ ├── index.json
│ │ ├── index.wxml
│ │ ├── index.js
│ │ └── index.wxss
│ └── logs
│ │ ├── logs.json
│ │ ├── logs.wxss
│ │ ├── logs.wxml
│ │ └── logs.js
│ ├── app.wxss
│ ├── app.json
│ ├── utils
│ ├── util.js
│ └── weapp-qrcode.js
│ ├── project.config.json
│ └── app.js
├── README.md
└── weapp-qrcode.js
/demo/demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pudon/weapp-qrcode-base64/HEAD/demo/demo.png
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "二维码页面"
3 | }
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/logs/logs.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "查看启动日志"
3 | }
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/logs/logs.wxss:
--------------------------------------------------------------------------------
1 | .log-list {
2 | display: flex;
3 | flex-direction: column;
4 | padding: 40rpx;
5 | }
6 | .log-item {
7 | margin: 10rpx;
8 | }
9 |
--------------------------------------------------------------------------------
/demo/weapp-demo/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | padding: 50rpx 20rpx;
7 | box-sizing: border-box;
8 | }
9 |
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/logs/logs.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{index + 1}}. {{log}}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/weapp-demo/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages":[
3 | "pages/index/index",
4 | "pages/logs/logs"
5 | ],
6 | "window":{
7 | "backgroundTextStyle":"light",
8 | "navigationBarBackgroundColor": "#f5f5f5",
9 | "navigationBarTitleText": "WeChat",
10 | "navigationBarTextStyle":"black"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/logs/logs.js:
--------------------------------------------------------------------------------
1 | //logs.js
2 | const util = require('../../utils/util.js')
3 |
4 | Page({
5 | data: {
6 | logs: []
7 | },
8 | onLoad: function () {
9 | this.setData({
10 | logs: (wx.getStorageSync('logs') || []).map(log => {
11 | return util.formatTime(new Date(log))
12 | })
13 | })
14 | }
15 | })
16 |
--------------------------------------------------------------------------------
/demo/weapp-demo/utils/util.js:
--------------------------------------------------------------------------------
1 | const formatTime = date => {
2 | const year = date.getFullYear()
3 | const month = date.getMonth() + 1
4 | const day = date.getDate()
5 | const hour = date.getHours()
6 | const minute = date.getMinutes()
7 | const second = date.getSeconds()
8 |
9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
10 | }
11 |
12 | const formatNumber = n => {
13 | n = n.toString()
14 | return n[1] ? n : '0' + n
15 | }
16 |
17 | module.exports = {
18 | formatTime: formatTime
19 | }
20 |
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/index/index.js:
--------------------------------------------------------------------------------
1 | //index.js
2 | //获取应用实例
3 | const app = getApp()
4 | const QR = require('../../utils/weapp-qrcode.js')
5 |
6 | Page({
7 | data: {
8 | motto: 'Hello World',
9 | qrcodeURL: "",
10 | codeText: "github.com/Pudon",
11 | },
12 | onLoad: function () {
13 | this.drawImg();
14 | },
15 | setText: function (e) {
16 | this.setData({
17 | codeText: e.detail.value
18 | })
19 | },
20 | drawImg: function () {
21 | console.log(this.data.codeText);
22 | var imgData = QR.drawImg(this.data.codeText, {
23 | typeNumber: 4,
24 | errorCorrectLevel: 'M',
25 | size: 500
26 | })
27 | this.setData({
28 | qrcodeURL: imgData
29 | })
30 | }
31 | })
32 |
--------------------------------------------------------------------------------
/demo/weapp-demo/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | page {
3 | height: 100%;
4 | }
5 | .container {
6 | background: #f5f5f5;
7 | }
8 | .qrcode-wrap {
9 | background: #fff;
10 | border-radius: 33rpx;
11 | }
12 | .qrcode-container {
13 | padding-top: 80rpx;
14 | padding-bottom: 50rpx;
15 | text-align: center;
16 | }
17 | .qrcode-img {
18 | width: 500rpx;
19 | height: 500rpx;
20 | }
21 | .text-container {
22 | padding: 50rpx;
23 | display: flex;
24 | align-items: center;
25 | justify-content: space-between;
26 | border-top: 2rpx solid #f0f0f0;
27 | }
28 | .text-input {
29 | border: 2rpx solid #f5f5f5;
30 | border-radius: 10rpx;
31 | margin-right: 10rpx;
32 | padding: 20rpx;
33 | }
34 | .change-btn {
35 | width: 200rpx;
36 | color: #fff;
37 | padding: 0 50rpx;
38 | }
--------------------------------------------------------------------------------
/demo/weapp-demo/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": true,
8 | "es6": true,
9 | "postcss": true,
10 | "minified": true,
11 | "newFeature": true
12 | },
13 | "compileType": "miniprogram",
14 | "libVersion": "2.2.5",
15 | "appid": "wxd523c798b0abef2b",
16 | "projectname": "%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%94%9F%E6%88%90%E4%BA%8C%E7%BB%B4%E7%A0%81",
17 | "debugOptions": {
18 | "hidedInDevtools": []
19 | },
20 | "isGameTourist": false,
21 | "condition": {
22 | "search": {
23 | "current": -1,
24 | "list": []
25 | },
26 | "conversation": {
27 | "current": -1,
28 | "list": []
29 | },
30 | "game": {
31 | "currentL": -1,
32 | "list": []
33 | },
34 | "miniprogram": {
35 | "current": -1,
36 | "list": []
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # weapp-qrcode
2 | Generating the QR code in the form of Base64
3 | 微信小程序生成二维码的插件,基于base64编码输出二维码,不依赖canvas 理论支持全平台
4 | >PS: 主要在`node-yaqrcode`项目基础上进行改造适应微信小程序
5 |
6 | ## 说明
7 | 只需要在 wxml 文件中增加个`image`标签动态引用base64编码即可
8 | ```
9 |
10 | ```
11 |
12 | 使用NPM
13 | ```
14 | npm install qrcode-base64
15 | ```
16 |
17 | JS调用例子:
18 | ```
19 | import QR from 'qrcode-base64'
20 |
21 | var imgData = QR.drawImg(this.data.codeText, {
22 | typeNumber: 4,
23 | errorCorrectLevel: 'M',
24 | size: 500
25 | })
26 | // 返回输出base64编码imgData
27 |
28 | ```
29 |
30 | JS调用例子:
31 | ```
32 | const QR = require('../../utils/weapp-qrcode.js')
33 | var imgData = QR.drawImg(this.data.codeText, {
34 | typeNumber: 4,
35 | errorCorrectLevel: 'M',
36 | size: 500
37 | })
38 | // 返回输出base64编码imgData
39 |
40 | ```
41 |
42 | ## DEMO示例图
43 |
44 | 
45 |
46 | ## TODO
47 | 1. 组件化,适应 `mpvue` , `wepy`
48 | 2. 更多配置项,灵活多样
49 | 3. 样式自定义化,增加更丰富的样式
50 |
--------------------------------------------------------------------------------
/demo/weapp-demo/app.js:
--------------------------------------------------------------------------------
1 | //app.js
2 | App({
3 | onLaunch: function () {
4 | // 展示本地存储能力
5 | var logs = wx.getStorageSync('logs') || []
6 | logs.unshift(Date.now())
7 | wx.setStorageSync('logs', logs)
8 |
9 | // 登录
10 | wx.login({
11 | success: res => {
12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId
13 | }
14 | })
15 | // 获取用户信息
16 | wx.getSetting({
17 | success: res => {
18 | if (res.authSetting['scope.userInfo']) {
19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
20 | wx.getUserInfo({
21 | success: res => {
22 | // 可以将 res 发送给后台解码出 unionId
23 | this.globalData.userInfo = res.userInfo
24 |
25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
26 | // 所以此处加入 callback 以防止这种情况
27 | if (this.userInfoReadyCallback) {
28 | this.userInfoReadyCallback(res)
29 | }
30 | }
31 | })
32 | }
33 | }
34 | })
35 | },
36 | globalData: {
37 | userInfo: null
38 | }
39 | })
--------------------------------------------------------------------------------
/weapp-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 | //---------------微信小程序基于base64生成二维码插件修改-------------------
19 | /*
20 | * @Modified: Pudon
21 | * @demoURL: https://github.com/Pudon/weapp-qrcode
22 | * @Date: 2018-09-11 14:00:05
23 | * @Last Modified by: Pudon
24 | * @Last Modified time: 2018-09-12 16:33:19
25 | */
26 | //---------------------------------------------------------------------
27 |
28 | /**
29 | * qrcode
30 | * @param typeNumber 1 to 40
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 | _moduleCount = _typeNumber * 4 + 17;
50 | _modules = function(moduleCount) {
51 | var modules = new Array(moduleCount);
52 | for (var row = 0; row < moduleCount; row += 1) {
53 | modules[row] = new Array(moduleCount);
54 | for (var col = 0; col < moduleCount; col += 1) {
55 | modules[row][col] = null;
56 | }
57 | }
58 | return modules;
59 | }(_moduleCount);
60 |
61 | setupPositionProbePattern(0, 0);
62 | setupPositionProbePattern(_moduleCount - 7, 0);
63 | setupPositionProbePattern(0, _moduleCount - 7);
64 | setupPositionAdjustPattern();
65 | setupTimingPattern();
66 | setupTypeInfo(test, maskPattern);
67 |
68 | if (_typeNumber >= 7) {
69 | setupTypeNumber(test);
70 | }
71 |
72 | if (_dataCache == null) {
73 | _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
74 | }
75 |
76 | mapData(_dataCache, maskPattern);
77 | };
78 |
79 | var setupPositionProbePattern = function(row, col) {
80 |
81 | for (var r = -1; r <= 7; r += 1) {
82 |
83 | if (row + r <= -1 || _moduleCount <= row + r) continue;
84 |
85 | for (var c = -1; c <= 7; c += 1) {
86 |
87 | if (col + c <= -1 || _moduleCount <= col + c) continue;
88 |
89 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
90 | || (0 <= c && c <= 6 && (r == 0 || r == 6) )
91 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
92 | _modules[row + r][col + c] = true;
93 | } else {
94 | _modules[row + r][col + c] = false;
95 | }
96 | }
97 | }
98 | };
99 |
100 | var getBestMaskPattern = function() {
101 |
102 | var minLostPoint = 0;
103 | var pattern = 0;
104 |
105 | for (var i = 0; i < 8; i += 1) {
106 |
107 | makeImpl(true, i);
108 |
109 | var lostPoint = QRUtil.getLostPoint(_this);
110 |
111 | if (i == 0 || minLostPoint > lostPoint) {
112 | minLostPoint = lostPoint;
113 | pattern = i;
114 | }
115 | }
116 |
117 | return pattern;
118 | };
119 |
120 | var setupTimingPattern = function() {
121 |
122 | for (var r = 8; r < _moduleCount - 8; r += 1) {
123 | if (_modules[r][6] != null) {
124 | continue;
125 | }
126 | _modules[r][6] = (r % 2 == 0);
127 | }
128 |
129 | for (var c = 8; c < _moduleCount - 8; c += 1) {
130 | if (_modules[6][c] != null) {
131 | continue;
132 | }
133 | _modules[6][c] = (c % 2 == 0);
134 | }
135 | };
136 |
137 | var setupPositionAdjustPattern = function() {
138 |
139 | var pos = QRUtil.getPatternPosition(_typeNumber);
140 |
141 | for (var i = 0; i < pos.length; i += 1) {
142 |
143 | for (var j = 0; j < pos.length; j += 1) {
144 |
145 | var row = pos[i];
146 | var col = pos[j];
147 |
148 | if (_modules[row][col] != null) {
149 | continue;
150 | }
151 |
152 | for (var r = -2; r <= 2; r += 1) {
153 |
154 | for (var c = -2; c <= 2; c += 1) {
155 |
156 | if (r == -2 || r == 2 || c == -2 || c == 2
157 | || (r == 0 && c == 0) ) {
158 | _modules[row + r][col + c] = true;
159 | } else {
160 | _modules[row + r][col + c] = false;
161 | }
162 | }
163 | }
164 | }
165 | }
166 | };
167 |
168 | var setupTypeNumber = function(test) {
169 |
170 | var bits = QRUtil.getBCHTypeNumber(_typeNumber);
171 |
172 | for (var i = 0; i < 18; i += 1) {
173 | var mod = (!test && ( (bits >> i) & 1) == 1);
174 | _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
175 | }
176 |
177 | for (var i = 0; i < 18; i += 1) {
178 | var mod = (!test && ( (bits >> i) & 1) == 1);
179 | _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
180 | }
181 | };
182 |
183 | var setupTypeInfo = function(test, maskPattern) {
184 |
185 | var data = (_errorCorrectLevel << 3) | maskPattern;
186 | var bits = QRUtil.getBCHTypeInfo(data);
187 |
188 | // vertical
189 | for (var i = 0; i < 15; i += 1) {
190 |
191 | var mod = (!test && ( (bits >> i) & 1) == 1);
192 |
193 | if (i < 6) {
194 | _modules[i][8] = mod;
195 | } else if (i < 8) {
196 | _modules[i + 1][8] = mod;
197 | } else {
198 | _modules[_moduleCount - 15 + i][8] = mod;
199 | }
200 | }
201 |
202 | // horizontal
203 | for (var i = 0; i < 15; i += 1) {
204 |
205 | var mod = (!test && ( (bits >> i) & 1) == 1);
206 |
207 | if (i < 8) {
208 | _modules[8][_moduleCount - i - 1] = mod;
209 | } else if (i < 9) {
210 | _modules[8][15 - i - 1 + 1] = mod;
211 | } else {
212 | _modules[8][15 - i - 1] = mod;
213 | }
214 | }
215 |
216 | // fixed module
217 | _modules[_moduleCount - 8][8] = (!test);
218 | };
219 |
220 | var mapData = function(data, maskPattern) {
221 |
222 | var inc = -1;
223 | var row = _moduleCount - 1;
224 | var bitIndex = 7;
225 | var byteIndex = 0;
226 | var maskFunc = QRUtil.getMaskFunction(maskPattern);
227 |
228 | for (var col = _moduleCount - 1; col > 0; col -= 2) {
229 |
230 | if (col == 6) col -= 1;
231 |
232 | while (true) {
233 |
234 | for (var c = 0; c < 2; c += 1) {
235 |
236 | if (_modules[row][col - c] == null) {
237 |
238 | var dark = false;
239 |
240 | if (byteIndex < data.length) {
241 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
242 | }
243 |
244 | var mask = maskFunc(row, col - c);
245 |
246 | if (mask) {
247 | dark = !dark;
248 | }
249 |
250 | _modules[row][col - c] = dark;
251 | bitIndex -= 1;
252 |
253 | if (bitIndex == -1) {
254 | byteIndex += 1;
255 | bitIndex = 7;
256 | }
257 | }
258 | }
259 |
260 | row += inc;
261 |
262 | if (row < 0 || _moduleCount <= row) {
263 | row -= inc;
264 | inc = -inc;
265 | break;
266 | }
267 | }
268 | }
269 | };
270 |
271 | var createBytes = function(buffer, rsBlocks) {
272 |
273 | var offset = 0;
274 |
275 | var maxDcCount = 0;
276 | var maxEcCount = 0;
277 |
278 | var dcdata = new Array(rsBlocks.length);
279 | var ecdata = new Array(rsBlocks.length);
280 |
281 | for (var r = 0; r < rsBlocks.length; r += 1) {
282 |
283 | var dcCount = rsBlocks[r].dataCount;
284 | var ecCount = rsBlocks[r].totalCount - dcCount;
285 |
286 | maxDcCount = Math.max(maxDcCount, dcCount);
287 | maxEcCount = Math.max(maxEcCount, ecCount);
288 |
289 | dcdata[r] = new Array(dcCount);
290 |
291 | for (var i = 0; i < dcdata[r].length; i += 1) {
292 | dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
293 | }
294 | offset += dcCount;
295 |
296 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
297 | var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
298 |
299 | var modPoly = rawPoly.mod(rsPoly);
300 | ecdata[r] = new Array(rsPoly.getLength() - 1);
301 | for (var i = 0; i < ecdata[r].length; i += 1) {
302 | var modIndex = i + modPoly.getLength() - ecdata[r].length;
303 | ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
304 | }
305 | }
306 |
307 | var totalCodeCount = 0;
308 | for (var i = 0; i < rsBlocks.length; i += 1) {
309 | totalCodeCount += rsBlocks[i].totalCount;
310 | }
311 |
312 | var data = new Array(totalCodeCount);
313 | var index = 0;
314 |
315 | for (var i = 0; i < maxDcCount; i += 1) {
316 | for (var r = 0; r < rsBlocks.length; r += 1) {
317 | if (i < dcdata[r].length) {
318 | data[index] = dcdata[r][i];
319 | index += 1;
320 | }
321 | }
322 | }
323 |
324 | for (var i = 0; i < maxEcCount; i += 1) {
325 | for (var r = 0; r < rsBlocks.length; r += 1) {
326 | if (i < ecdata[r].length) {
327 | data[index] = ecdata[r][i];
328 | index += 1;
329 | }
330 | }
331 | }
332 |
333 | return data;
334 | };
335 |
336 | var createData = function(typeNumber, errorCorrectLevel, dataList) {
337 |
338 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
339 |
340 | var buffer = qrBitBuffer();
341 |
342 | for (var i = 0; i < dataList.length; i += 1) {
343 | var data = dataList[i];
344 | buffer.put(data.getMode(), 4);
345 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
346 | data.write(buffer);
347 | }
348 |
349 | // calc num max data.
350 | var totalDataCount = 0;
351 | for (var i = 0; i < rsBlocks.length; i += 1) {
352 | totalDataCount += rsBlocks[i].dataCount;
353 | }
354 |
355 | if (buffer.getLengthInBits() > totalDataCount * 8) {
356 | throw new Error('code length overflow. ('
357 | + buffer.getLengthInBits()
358 | + '>'
359 | + totalDataCount * 8
360 | + ')');
361 | }
362 |
363 | // end code
364 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
365 | buffer.put(0, 4);
366 | }
367 |
368 | // padding
369 | while (buffer.getLengthInBits() % 8 != 0) {
370 | buffer.putBit(false);
371 | }
372 |
373 | // padding
374 | while (true) {
375 |
376 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
377 | break;
378 | }
379 | buffer.put(PAD0, 8);
380 |
381 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
382 | break;
383 | }
384 | buffer.put(PAD1, 8);
385 | }
386 |
387 | return createBytes(buffer, rsBlocks);
388 | };
389 |
390 | _this.addData = function(data) {
391 | var newData = qr8BitByte(data);
392 | _dataList.push(newData);
393 | _dataCache = null;
394 | };
395 |
396 | _this.isDark = function(row, col) {
397 | if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
398 | throw new Error(row + ',' + col);
399 | }
400 | return _modules[row][col];
401 | };
402 |
403 | _this.getModuleCount = function() {
404 | return _moduleCount;
405 | };
406 |
407 | _this.make = function() {
408 | makeImpl(false, getBestMaskPattern() );
409 | };
410 |
411 | _this.createTableTag = function(cellSize, margin) {
412 |
413 | cellSize = cellSize || 2;
414 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
415 |
416 | var qrHtml = '';
417 |
418 | qrHtml += '
';
423 | qrHtml += '';
424 |
425 | for (var r = 0; r < _this.getModuleCount(); r += 1) {
426 |
427 | qrHtml += '';
428 |
429 | for (var c = 0; c < _this.getModuleCount(); c += 1) {
430 | qrHtml += ' | ';
440 | }
441 |
442 | qrHtml += '
';
443 | }
444 |
445 | qrHtml += '';
446 | qrHtml += '
';
447 |
448 | return qrHtml;
449 | };
450 |
451 | _this.createImgTag = function(cellSize, margin, size) {
452 |
453 | cellSize = cellSize || 2;
454 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
455 |
456 | var min = margin;
457 | var max = _this.getModuleCount() * cellSize + margin;
458 |
459 | return createImgTag(size, size, function(x, y) {
460 | if (min <= x && x < max && min <= y && y < max) {
461 | var c = Math.floor( (x - min) / cellSize);
462 | var r = Math.floor( (y - min) / cellSize);
463 | return _this.isDark(r, c)? 0 : 1;
464 | } else {
465 | return 1;
466 | }
467 | } );
468 | };
469 |
470 | return _this;
471 | };
472 |
473 | //---------------------------------------------------------------------
474 | // qrcode.stringToBytes
475 | //---------------------------------------------------------------------
476 |
477 | qrcode.stringToBytes = function(s) {
478 | var bytes = new Array();
479 | for (var i = 0; i < s.length; i += 1) {
480 | var c = s.charCodeAt(i);
481 | bytes.push(c & 0xff);
482 | }
483 | return bytes;
484 | };
485 |
486 | //---------------------------------------------------------------------
487 | // qrcode.createStringToBytes
488 | //---------------------------------------------------------------------
489 |
490 | /**
491 | * @param unicodeData base64 string of byte array.
492 | * [16bit Unicode],[16bit Bytes], ...
493 | * @param numChars
494 | */
495 | qrcode.createStringToBytes = function(unicodeData, numChars) {
496 |
497 | // create conversion map.
498 |
499 | var unicodeMap = function() {
500 |
501 | var bin = base64DecodeInputStream(unicodeData);
502 | var read = function() {
503 | var b = bin.read();
504 | if (b == -1) throw new Error();
505 | return b;
506 | };
507 |
508 | var count = 0;
509 | var unicodeMap = {};
510 | while (true) {
511 | var b0 = bin.read();
512 | if (b0 == -1) break;
513 | var b1 = read();
514 | var b2 = read();
515 | var b3 = read();
516 | var k = String.fromCharCode( (b0 << 8) | b1);
517 | var v = (b2 << 8) | b3;
518 | unicodeMap[k] = v;
519 | count += 1;
520 | }
521 | if (count != numChars) {
522 | throw new Error(count + ' != ' + numChars);
523 | }
524 |
525 | return unicodeMap;
526 | }();
527 |
528 | var unknownChar = '?'.charCodeAt(0);
529 |
530 | return function(s) {
531 | var bytes = new Array();
532 | for (var i = 0; i < s.length; i += 1) {
533 | var c = s.charCodeAt(i);
534 | if (c < 128) {
535 | bytes.push(c);
536 | } else {
537 | var b = unicodeMap[s.charAt(i)];
538 | if (typeof b == 'number') {
539 | if ( (b & 0xff) == b) {
540 | // 1byte
541 | bytes.push(b);
542 | } else {
543 | // 2bytes
544 | bytes.push(b >>> 8);
545 | bytes.push(b & 0xff);
546 | }
547 | } else {
548 | bytes.push(unknownChar);
549 | }
550 | }
551 | }
552 | return bytes;
553 | };
554 | };
555 |
556 | //---------------------------------------------------------------------
557 | // QRMode
558 | //---------------------------------------------------------------------
559 |
560 | var QRMode = {
561 | MODE_NUMBER : 1 << 0,
562 | MODE_ALPHA_NUM : 1 << 1,
563 | MODE_8BIT_BYTE : 1 << 2,
564 | MODE_KANJI : 1 << 3
565 | };
566 |
567 | //---------------------------------------------------------------------
568 | // QRErrorCorrectLevel
569 | //---------------------------------------------------------------------
570 |
571 | var QRErrorCorrectLevel = {
572 | L : 1,
573 | M : 0,
574 | Q : 3,
575 | H : 2
576 | };
577 |
578 | //---------------------------------------------------------------------
579 | // QRMaskPattern
580 | //---------------------------------------------------------------------
581 |
582 | var QRMaskPattern = {
583 | PATTERN000 : 0,
584 | PATTERN001 : 1,
585 | PATTERN010 : 2,
586 | PATTERN011 : 3,
587 | PATTERN100 : 4,
588 | PATTERN101 : 5,
589 | PATTERN110 : 6,
590 | PATTERN111 : 7
591 | };
592 |
593 | //---------------------------------------------------------------------
594 | // QRUtil
595 | //---------------------------------------------------------------------
596 |
597 | var QRUtil = function() {
598 |
599 | var PATTERN_POSITION_TABLE = [
600 | [],
601 | [6, 18],
602 | [6, 22],
603 | [6, 26],
604 | [6, 30],
605 | [6, 34],
606 | [6, 22, 38],
607 | [6, 24, 42],
608 | [6, 26, 46],
609 | [6, 28, 50],
610 | [6, 30, 54],
611 | [6, 32, 58],
612 | [6, 34, 62],
613 | [6, 26, 46, 66],
614 | [6, 26, 48, 70],
615 | [6, 26, 50, 74],
616 | [6, 30, 54, 78],
617 | [6, 30, 56, 82],
618 | [6, 30, 58, 86],
619 | [6, 34, 62, 90],
620 | [6, 28, 50, 72, 94],
621 | [6, 26, 50, 74, 98],
622 | [6, 30, 54, 78, 102],
623 | [6, 28, 54, 80, 106],
624 | [6, 32, 58, 84, 110],
625 | [6, 30, 58, 86, 114],
626 | [6, 34, 62, 90, 118],
627 | [6, 26, 50, 74, 98, 122],
628 | [6, 30, 54, 78, 102, 126],
629 | [6, 26, 52, 78, 104, 130],
630 | [6, 30, 56, 82, 108, 134],
631 | [6, 34, 60, 86, 112, 138],
632 | [6, 30, 58, 86, 114, 142],
633 | [6, 34, 62, 90, 118, 146],
634 | [6, 30, 54, 78, 102, 126, 150],
635 | [6, 24, 50, 76, 102, 128, 154],
636 | [6, 28, 54, 80, 106, 132, 158],
637 | [6, 32, 58, 84, 110, 136, 162],
638 | [6, 26, 54, 82, 110, 138, 166],
639 | [6, 30, 58, 86, 114, 142, 170]
640 | ];
641 | var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
642 | var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
643 | var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
644 |
645 | var _this = {};
646 |
647 | var getBCHDigit = function(data) {
648 | var digit = 0;
649 | while (data != 0) {
650 | digit += 1;
651 | data >>>= 1;
652 | }
653 | return digit;
654 | };
655 |
656 | _this.getBCHTypeInfo = function(data) {
657 | var d = data << 10;
658 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
659 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
660 | }
661 | return ( (data << 10) | d) ^ G15_MASK;
662 | };
663 |
664 | _this.getBCHTypeNumber = function(data) {
665 | var d = data << 12;
666 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
667 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
668 | }
669 | return (data << 12) | d;
670 | };
671 |
672 | _this.getPatternPosition = function(typeNumber) {
673 | return PATTERN_POSITION_TABLE[typeNumber - 1];
674 | };
675 |
676 | _this.getMaskFunction = function(maskPattern) {
677 |
678 | switch (maskPattern) {
679 |
680 | case QRMaskPattern.PATTERN000 :
681 | return function(i, j) { return (i + j) % 2 == 0; };
682 | case QRMaskPattern.PATTERN001 :
683 | return function(i, j) { return i % 2 == 0; };
684 | case QRMaskPattern.PATTERN010 :
685 | return function(i, j) { return j % 3 == 0; };
686 | case QRMaskPattern.PATTERN011 :
687 | return function(i, j) { return (i + j) % 3 == 0; };
688 | case QRMaskPattern.PATTERN100 :
689 | return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
690 | case QRMaskPattern.PATTERN101 :
691 | return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
692 | case QRMaskPattern.PATTERN110 :
693 | return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
694 | case QRMaskPattern.PATTERN111 :
695 | return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
696 |
697 | default :
698 | throw new Error('bad maskPattern:' + maskPattern);
699 | }
700 | };
701 |
702 | _this.getErrorCorrectPolynomial = function(errorCorrectLength) {
703 | var a = qrPolynomial([1], 0);
704 | for (var i = 0; i < errorCorrectLength; i += 1) {
705 | a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
706 | }
707 | return a;
708 | };
709 |
710 | _this.getLengthInBits = function(mode, type) {
711 |
712 | if (1 <= type && type < 10) {
713 |
714 | // 1 - 9
715 |
716 | switch(mode) {
717 | case QRMode.MODE_NUMBER : return 10;
718 | case QRMode.MODE_ALPHA_NUM : return 9;
719 | case QRMode.MODE_8BIT_BYTE : return 8;
720 | case QRMode.MODE_KANJI : return 8;
721 | default :
722 | throw new Error('mode:' + mode);
723 | }
724 |
725 | } else if (type < 27) {
726 |
727 | // 10 - 26
728 |
729 | switch(mode) {
730 | case QRMode.MODE_NUMBER : return 12;
731 | case QRMode.MODE_ALPHA_NUM : return 11;
732 | case QRMode.MODE_8BIT_BYTE : return 16;
733 | case QRMode.MODE_KANJI : return 10;
734 | default :
735 | throw new Error('mode:' + mode);
736 | }
737 |
738 | } else if (type < 41) {
739 |
740 | // 27 - 40
741 |
742 | switch(mode) {
743 | case QRMode.MODE_NUMBER : return 14;
744 | case QRMode.MODE_ALPHA_NUM : return 13;
745 | case QRMode.MODE_8BIT_BYTE : return 16;
746 | case QRMode.MODE_KANJI : return 12;
747 | default :
748 | throw new Error('mode:' + mode);
749 | }
750 |
751 | } else {
752 | throw new Error('type:' + type);
753 | }
754 | };
755 |
756 | _this.getLostPoint = function(qrcode) {
757 |
758 | var moduleCount = qrcode.getModuleCount();
759 |
760 | var lostPoint = 0;
761 |
762 | // LEVEL1
763 |
764 | for (var row = 0; row < moduleCount; row += 1) {
765 | for (var col = 0; col < moduleCount; col += 1) {
766 |
767 | var sameCount = 0;
768 | var dark = qrcode.isDark(row, col);
769 |
770 | for (var r = -1; r <= 1; r += 1) {
771 |
772 | if (row + r < 0 || moduleCount <= row + r) {
773 | continue;
774 | }
775 |
776 | for (var c = -1; c <= 1; c += 1) {
777 |
778 | if (col + c < 0 || moduleCount <= col + c) {
779 | continue;
780 | }
781 |
782 | if (r == 0 && c == 0) {
783 | continue;
784 | }
785 |
786 | if (dark == qrcode.isDark(row + r, col + c) ) {
787 | sameCount += 1;
788 | }
789 | }
790 | }
791 |
792 | if (sameCount > 5) {
793 | lostPoint += (3 + sameCount - 5);
794 | }
795 | }
796 | };
797 |
798 | // LEVEL2
799 |
800 | for (var row = 0; row < moduleCount - 1; row += 1) {
801 | for (var col = 0; col < moduleCount - 1; col += 1) {
802 | var count = 0;
803 | if (qrcode.isDark(row, col) ) count += 1;
804 | if (qrcode.isDark(row + 1, col) ) count += 1;
805 | if (qrcode.isDark(row, col + 1) ) count += 1;
806 | if (qrcode.isDark(row + 1, col + 1) ) count += 1;
807 | if (count == 0 || count == 4) {
808 | lostPoint += 3;
809 | }
810 | }
811 | }
812 |
813 | // LEVEL3
814 |
815 | for (var row = 0; row < moduleCount; row += 1) {
816 | for (var col = 0; col < moduleCount - 6; col += 1) {
817 | if (qrcode.isDark(row, col)
818 | && !qrcode.isDark(row, col + 1)
819 | && qrcode.isDark(row, col + 2)
820 | && qrcode.isDark(row, col + 3)
821 | && qrcode.isDark(row, col + 4)
822 | && !qrcode.isDark(row, col + 5)
823 | && qrcode.isDark(row, col + 6) ) {
824 | lostPoint += 40;
825 | }
826 | }
827 | }
828 |
829 | for (var col = 0; col < moduleCount; col += 1) {
830 | for (var row = 0; row < moduleCount - 6; row += 1) {
831 | if (qrcode.isDark(row, col)
832 | && !qrcode.isDark(row + 1, col)
833 | && qrcode.isDark(row + 2, col)
834 | && qrcode.isDark(row + 3, col)
835 | && qrcode.isDark(row + 4, col)
836 | && !qrcode.isDark(row + 5, col)
837 | && qrcode.isDark(row + 6, col) ) {
838 | lostPoint += 40;
839 | }
840 | }
841 | }
842 |
843 | // LEVEL4
844 |
845 | var darkCount = 0;
846 |
847 | for (var col = 0; col < moduleCount; col += 1) {
848 | for (var row = 0; row < moduleCount; row += 1) {
849 | if (qrcode.isDark(row, col) ) {
850 | darkCount += 1;
851 | }
852 | }
853 | }
854 |
855 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
856 | lostPoint += ratio * 10;
857 |
858 | return lostPoint;
859 | };
860 |
861 | return _this;
862 | }();
863 |
864 | //---------------------------------------------------------------------
865 | // QRMath
866 | //---------------------------------------------------------------------
867 |
868 | var QRMath = function() {
869 |
870 | var EXP_TABLE = new Array(256);
871 | var LOG_TABLE = new Array(256);
872 |
873 | // initialize tables
874 | for (var i = 0; i < 8; i += 1) {
875 | EXP_TABLE[i] = 1 << i;
876 | }
877 | for (var i = 8; i < 256; i += 1) {
878 | EXP_TABLE[i] = EXP_TABLE[i - 4]
879 | ^ EXP_TABLE[i - 5]
880 | ^ EXP_TABLE[i - 6]
881 | ^ EXP_TABLE[i - 8];
882 | }
883 | for (var i = 0; i < 255; i += 1) {
884 | LOG_TABLE[EXP_TABLE[i] ] = i;
885 | }
886 |
887 | var _this = {};
888 |
889 | _this.glog = function(n) {
890 |
891 | if (n < 1) {
892 | throw new Error('glog(' + n + ')');
893 | }
894 |
895 | return LOG_TABLE[n];
896 | };
897 |
898 | _this.gexp = function(n) {
899 |
900 | while (n < 0) {
901 | n += 255;
902 | }
903 |
904 | while (n >= 256) {
905 | n -= 255;
906 | }
907 |
908 | return EXP_TABLE[n];
909 | };
910 |
911 | return _this;
912 | }();
913 |
914 | //---------------------------------------------------------------------
915 | // qrPolynomial
916 | //---------------------------------------------------------------------
917 |
918 | function qrPolynomial(num, shift) {
919 |
920 | if (typeof num.length == 'undefined') {
921 | throw new Error(num.length + '/' + shift);
922 | }
923 |
924 | var _num = function() {
925 | var offset = 0;
926 | while (offset < num.length && num[offset] == 0) {
927 | offset += 1;
928 | }
929 | var _num = new Array(num.length - offset + shift);
930 | for (var i = 0; i < num.length - offset; i += 1) {
931 | _num[i] = num[i + offset];
932 | }
933 | return _num;
934 | }();
935 |
936 | var _this = {};
937 |
938 | _this.getAt = function(index) {
939 | return _num[index];
940 | };
941 |
942 | _this.getLength = function() {
943 | return _num.length;
944 | };
945 |
946 | _this.multiply = function(e) {
947 |
948 | var num = new Array(_this.getLength() + e.getLength() - 1);
949 |
950 | for (var i = 0; i < _this.getLength(); i += 1) {
951 | for (var j = 0; j < e.getLength(); j += 1) {
952 | num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
953 | }
954 | }
955 |
956 | return qrPolynomial(num, 0);
957 | };
958 |
959 | _this.mod = function(e) {
960 |
961 | if (_this.getLength() - e.getLength() < 0) {
962 | return _this;
963 | }
964 |
965 | var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
966 |
967 | var num = new Array(_this.getLength() );
968 | for (var i = 0; i < _this.getLength(); i += 1) {
969 | num[i] = _this.getAt(i);
970 | }
971 |
972 | for (var i = 0; i < e.getLength(); i += 1) {
973 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
974 | }
975 |
976 | // recursive call
977 | return qrPolynomial(num, 0).mod(e);
978 | };
979 |
980 | return _this;
981 | };
982 |
983 | //---------------------------------------------------------------------
984 | // QRRSBlock
985 | //---------------------------------------------------------------------
986 |
987 | var QRRSBlock = function() {
988 |
989 |
990 | // [1: [L, M, Q, H], ..]
991 | var RS_BLOCK_TABLE=[[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],[4,101,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],[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]];
992 |
993 | var qrRSBlock = function(totalCount, dataCount) {
994 | var _this = {};
995 | _this.totalCount = totalCount;
996 | _this.dataCount = dataCount;
997 | return _this;
998 | };
999 |
1000 | var _this = {};
1001 |
1002 | var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
1003 |
1004 | switch(errorCorrectLevel) {
1005 | case QRErrorCorrectLevel.L :
1006 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
1007 | case QRErrorCorrectLevel.M :
1008 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
1009 | case QRErrorCorrectLevel.Q :
1010 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
1011 | case QRErrorCorrectLevel.H :
1012 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
1013 | default :
1014 | return undefined;
1015 | }
1016 | };
1017 |
1018 | _this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
1019 |
1020 | var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
1021 |
1022 | if (typeof rsBlock == 'undefined') {
1023 | throw new Error('bad rs block @ typeNumber:' + typeNumber +
1024 | '/errorCorrectLevel:' + errorCorrectLevel);
1025 | }
1026 |
1027 | var length = rsBlock.length / 3;
1028 |
1029 | var list = new Array();
1030 |
1031 | for (var i = 0; i < length; i += 1) {
1032 |
1033 | var count = rsBlock[i * 3 + 0];
1034 | var totalCount = rsBlock[i * 3 + 1];
1035 | var dataCount = rsBlock[i * 3 + 2];
1036 |
1037 | for (var j = 0; j < count; j += 1) {
1038 | list.push(qrRSBlock(totalCount, dataCount) );
1039 | }
1040 | }
1041 |
1042 | return list;
1043 | };
1044 |
1045 | return _this;
1046 | }();
1047 |
1048 | //---------------------------------------------------------------------
1049 | // qrBitBuffer
1050 | //---------------------------------------------------------------------
1051 |
1052 | var qrBitBuffer = function() {
1053 |
1054 | var _buffer = new Array();
1055 | var _length = 0;
1056 |
1057 | var _this = {};
1058 |
1059 | _this.getBuffer = function() {
1060 | return _buffer;
1061 | };
1062 |
1063 | _this.getAt = function(index) {
1064 | var bufIndex = Math.floor(index / 8);
1065 | return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
1066 | };
1067 |
1068 | _this.put = function(num, length) {
1069 | for (var i = 0; i < length; i += 1) {
1070 | _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
1071 | }
1072 | };
1073 |
1074 | _this.getLengthInBits = function() {
1075 | return _length;
1076 | };
1077 |
1078 | _this.putBit = function(bit) {
1079 |
1080 | var bufIndex = Math.floor(_length / 8);
1081 | if (_buffer.length <= bufIndex) {
1082 | _buffer.push(0);
1083 | }
1084 |
1085 | if (bit) {
1086 | _buffer[bufIndex] |= (0x80 >>> (_length % 8) );
1087 | }
1088 |
1089 | _length += 1;
1090 | };
1091 |
1092 | return _this;
1093 | };
1094 |
1095 | //---------------------------------------------------------------------
1096 | // qr8BitByte
1097 | //---------------------------------------------------------------------
1098 |
1099 | var qr8BitByte = function(data) {
1100 |
1101 | var _mode = QRMode.MODE_8BIT_BYTE;
1102 | var _data = data;
1103 | var _parsedData = [];
1104 |
1105 | var _this = {};
1106 |
1107 |
1108 | // Added to support UTF-8 Characters
1109 | for (var i = 0, l = _data.length; i < l; i++) {
1110 | var byteArray = [];
1111 | var code = _data.charCodeAt(i);
1112 |
1113 | if (code > 0x10000) {
1114 | byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
1115 | byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
1116 | byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
1117 | byteArray[3] = 0x80 | (code & 0x3F);
1118 | } else if (code > 0x800) {
1119 | byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
1120 | byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
1121 | byteArray[2] = 0x80 | (code & 0x3F);
1122 | } else if (code > 0x80) {
1123 | byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
1124 | byteArray[1] = 0x80 | (code & 0x3F);
1125 | } else {
1126 | byteArray[0] = code;
1127 | }
1128 |
1129 | // Fix Unicode corruption bug
1130 | _parsedData.push(byteArray);
1131 | }
1132 |
1133 | _parsedData = Array.prototype.concat.apply([], _parsedData);
1134 |
1135 | if (_parsedData.length != _data.length) {
1136 | _parsedData.unshift(191);
1137 | _parsedData.unshift(187);
1138 | _parsedData.unshift(239);
1139 | }
1140 |
1141 | var _bytes = _parsedData;
1142 |
1143 | _this.getMode = function() {
1144 | return _mode;
1145 | };
1146 |
1147 | _this.getLength = function(buffer) {
1148 | return _bytes.length;
1149 | };
1150 |
1151 | _this.write = function(buffer) {
1152 | for (var i = 0; i < _bytes.length; i += 1) {
1153 | buffer.put(_bytes[i], 8);
1154 | }
1155 | };
1156 |
1157 | return _this;
1158 | };
1159 |
1160 | //=====================================================================
1161 | // GIF Support etc.
1162 | //
1163 |
1164 | //---------------------------------------------------------------------
1165 | // byteArrayOutputStream
1166 | //---------------------------------------------------------------------
1167 |
1168 | var byteArrayOutputStream = function() {
1169 |
1170 | var _bytes = new Array();
1171 |
1172 | var _this = {};
1173 |
1174 | _this.writeByte = function(b) {
1175 | _bytes.push(b & 0xff);
1176 | };
1177 |
1178 | _this.writeShort = function(i) {
1179 | _this.writeByte(i);
1180 | _this.writeByte(i >>> 8);
1181 | };
1182 |
1183 | _this.writeBytes = function(b, off, len) {
1184 | off = off || 0;
1185 | len = len || b.length;
1186 | for (var i = 0; i < len; i += 1) {
1187 | _this.writeByte(b[i + off]);
1188 | }
1189 | };
1190 |
1191 | _this.writeString = function(s) {
1192 | for (var i = 0; i < s.length; i += 1) {
1193 | _this.writeByte(s.charCodeAt(i) );
1194 | }
1195 | };
1196 |
1197 | _this.toByteArray = function() {
1198 | return _bytes;
1199 | };
1200 |
1201 | _this.toString = function() {
1202 | var s = '';
1203 | s += '[';
1204 | for (var i = 0; i < _bytes.length; i += 1) {
1205 | if (i > 0) {
1206 | s += ',';
1207 | }
1208 | s += _bytes[i];
1209 | }
1210 | s += ']';
1211 | return s;
1212 | };
1213 |
1214 | return _this;
1215 | };
1216 |
1217 | //---------------------------------------------------------------------
1218 | // base64EncodeOutputStream
1219 | //---------------------------------------------------------------------
1220 |
1221 | var base64EncodeOutputStream = function() {
1222 |
1223 | var _buffer = 0;
1224 | var _buflen = 0;
1225 | var _length = 0;
1226 | var _base64 = '';
1227 |
1228 | var _this = {};
1229 |
1230 | var writeEncoded = function(b) {
1231 | _base64 += String.fromCharCode(encode(b & 0x3f) );
1232 | };
1233 |
1234 | var encode = function(n) {
1235 | if (n < 0) {
1236 | // error.
1237 | } else if (n < 26) {
1238 | return 0x41 + n;
1239 | } else if (n < 52) {
1240 | return 0x61 + (n - 26);
1241 | } else if (n < 62) {
1242 | return 0x30 + (n - 52);
1243 | } else if (n == 62) {
1244 | return 0x2b;
1245 | } else if (n == 63) {
1246 | return 0x2f;
1247 | }
1248 | throw new Error('n:' + n);
1249 | };
1250 |
1251 | _this.writeByte = function(n) {
1252 |
1253 | _buffer = (_buffer << 8) | (n & 0xff);
1254 | _buflen += 8;
1255 | _length += 1;
1256 |
1257 | while (_buflen >= 6) {
1258 | writeEncoded(_buffer >>> (_buflen - 6) );
1259 | _buflen -= 6;
1260 | }
1261 | };
1262 |
1263 | _this.flush = function() {
1264 |
1265 | if (_buflen > 0) {
1266 | writeEncoded(_buffer << (6 - _buflen) );
1267 | _buffer = 0;
1268 | _buflen = 0;
1269 | }
1270 |
1271 | if (_length % 3 != 0) {
1272 | // padding
1273 | var padlen = 3 - _length % 3;
1274 | for (var i = 0; i < padlen; i += 1) {
1275 | _base64 += '=';
1276 | }
1277 | }
1278 | };
1279 |
1280 | _this.toString = function() {
1281 | return _base64;
1282 | };
1283 |
1284 | return _this;
1285 | };
1286 |
1287 | //---------------------------------------------------------------------
1288 | // base64DecodeInputStream
1289 | //---------------------------------------------------------------------
1290 |
1291 | var base64DecodeInputStream = function(str) {
1292 |
1293 | var _str = str;
1294 | var _pos = 0;
1295 | var _buffer = 0;
1296 | var _buflen = 0;
1297 |
1298 | var _this = {};
1299 |
1300 | _this.read = function() {
1301 |
1302 | while (_buflen < 8) {
1303 |
1304 | if (_pos >= _str.length) {
1305 | if (_buflen == 0) {
1306 | return -1;
1307 | }
1308 | throw new Error('unexpected end of file./' + _buflen);
1309 | }
1310 |
1311 | var c = _str.charAt(_pos);
1312 | _pos += 1;
1313 |
1314 | if (c == '=') {
1315 | _buflen = 0;
1316 | return -1;
1317 | } else if (c.match(/^\s$/) ) {
1318 | // ignore if whitespace.
1319 | continue;
1320 | }
1321 |
1322 | _buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
1323 | _buflen += 6;
1324 | }
1325 |
1326 | var n = (_buffer >>> (_buflen - 8) ) & 0xff;
1327 | _buflen -= 8;
1328 | return n;
1329 | };
1330 |
1331 | var decode = function(c) {
1332 | if (0x41 <= c && c <= 0x5a) {
1333 | return c - 0x41;
1334 | } else if (0x61 <= c && c <= 0x7a) {
1335 | return c - 0x61 + 26;
1336 | } else if (0x30 <= c && c <= 0x39) {
1337 | return c - 0x30 + 52;
1338 | } else if (c == 0x2b) {
1339 | return 62;
1340 | } else if (c == 0x2f) {
1341 | return 63;
1342 | } else {
1343 | throw new Error('c:' + c);
1344 | }
1345 | };
1346 |
1347 | return _this;
1348 | };
1349 |
1350 | //---------------------------------------------------------------------
1351 | // gifImage (B/W)
1352 | //---------------------------------------------------------------------
1353 |
1354 | var gifImage = function(width, height) {
1355 |
1356 | var _width = width;
1357 | var _height = height;
1358 | var _data = new Array(width * height);
1359 |
1360 | var _this = {};
1361 |
1362 | _this.setPixel = function(x, y, pixel) {
1363 | _data[y * _width + x] = pixel;
1364 | };
1365 |
1366 | _this.write = function(out) {
1367 |
1368 | //---------------------------------
1369 | // GIF Signature
1370 |
1371 | out.writeString('GIF87a');
1372 |
1373 | //---------------------------------
1374 | // Screen Descriptor
1375 |
1376 | out.writeShort(_width);
1377 | out.writeShort(_height);
1378 |
1379 | out.writeByte(0x80); // 2bit
1380 | out.writeByte(0);
1381 | out.writeByte(0);
1382 |
1383 | //---------------------------------
1384 | // Global Color Map
1385 |
1386 | // black
1387 | out.writeByte(0x00);
1388 | out.writeByte(0x00);
1389 | out.writeByte(0x00);
1390 |
1391 | // white
1392 | out.writeByte(0xff);
1393 | out.writeByte(0xff);
1394 | out.writeByte(0xff);
1395 |
1396 | //---------------------------------
1397 | // Image Descriptor
1398 |
1399 | out.writeString(',');
1400 | out.writeShort(0);
1401 | out.writeShort(0);
1402 | out.writeShort(_width);
1403 | out.writeShort(_height);
1404 | out.writeByte(0);
1405 |
1406 | //---------------------------------
1407 | // Local Color Map
1408 |
1409 | //---------------------------------
1410 | // Raster Data
1411 |
1412 | var lzwMinCodeSize = 2;
1413 | var raster = getLZWRaster(lzwMinCodeSize);
1414 |
1415 | out.writeByte(lzwMinCodeSize);
1416 |
1417 | var offset = 0;
1418 |
1419 | while (raster.length - offset > 255) {
1420 | out.writeByte(255);
1421 | out.writeBytes(raster, offset, 255);
1422 | offset += 255;
1423 | }
1424 |
1425 | out.writeByte(raster.length - offset);
1426 | out.writeBytes(raster, offset, raster.length - offset);
1427 | out.writeByte(0x00);
1428 |
1429 | //---------------------------------
1430 | // GIF Terminator
1431 | out.writeString(';');
1432 | };
1433 |
1434 | var bitOutputStream = function(out) {
1435 |
1436 | var _out = out;
1437 | var _bitLength = 0;
1438 | var _bitBuffer = 0;
1439 |
1440 | var _this = {};
1441 |
1442 | _this.write = function(data, length) {
1443 |
1444 | if ( (data >>> length) != 0) {
1445 | throw new Error('length over');
1446 | }
1447 |
1448 | while (_bitLength + length >= 8) {
1449 | _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
1450 | length -= (8 - _bitLength);
1451 | data >>>= (8 - _bitLength);
1452 | _bitBuffer = 0;
1453 | _bitLength = 0;
1454 | }
1455 |
1456 | _bitBuffer = (data << _bitLength) | _bitBuffer;
1457 | _bitLength = _bitLength + length;
1458 | };
1459 |
1460 | _this.flush = function() {
1461 | if (_bitLength > 0) {
1462 | _out.writeByte(_bitBuffer);
1463 | }
1464 | };
1465 |
1466 | return _this;
1467 | };
1468 |
1469 | var getLZWRaster = function(lzwMinCodeSize) {
1470 |
1471 | var clearCode = 1 << lzwMinCodeSize;
1472 | var endCode = (1 << lzwMinCodeSize) + 1;
1473 | var bitLength = lzwMinCodeSize + 1;
1474 |
1475 | // Setup LZWTable
1476 | var table = lzwTable();
1477 |
1478 | for (var i = 0; i < clearCode; i += 1) {
1479 | table.add(String.fromCharCode(i) );
1480 | }
1481 | table.add(String.fromCharCode(clearCode) );
1482 | table.add(String.fromCharCode(endCode) );
1483 |
1484 | var byteOut = byteArrayOutputStream();
1485 | var bitOut = bitOutputStream(byteOut);
1486 |
1487 | // clear code
1488 | bitOut.write(clearCode, bitLength);
1489 |
1490 | var dataIndex = 0;
1491 |
1492 | var s = String.fromCharCode(_data[dataIndex]);
1493 | dataIndex += 1;
1494 |
1495 | while (dataIndex < _data.length) {
1496 |
1497 | var c = String.fromCharCode(_data[dataIndex]);
1498 | dataIndex += 1;
1499 |
1500 | if (table.contains(s + c) ) {
1501 |
1502 | s = s + c;
1503 |
1504 | } else {
1505 |
1506 | bitOut.write(table.indexOf(s), bitLength);
1507 |
1508 | if (table.size() < 0xfff) {
1509 |
1510 | if (table.size() == (1 << bitLength) ) {
1511 | bitLength += 1;
1512 | }
1513 |
1514 | table.add(s + c);
1515 | }
1516 |
1517 | s = c;
1518 | }
1519 | }
1520 |
1521 | bitOut.write(table.indexOf(s), bitLength);
1522 |
1523 | // end code
1524 | bitOut.write(endCode, bitLength);
1525 |
1526 | bitOut.flush();
1527 |
1528 | return byteOut.toByteArray();
1529 | };
1530 |
1531 | var lzwTable = function() {
1532 |
1533 | var _map = {};
1534 | var _size = 0;
1535 |
1536 | var _this = {};
1537 |
1538 | _this.add = function(key) {
1539 | if (_this.contains(key) ) {
1540 | throw new Error('dup key:' + key);
1541 | }
1542 | _map[key] = _size;
1543 | _size += 1;
1544 | };
1545 |
1546 | _this.size = function() {
1547 | return _size;
1548 | };
1549 |
1550 | _this.indexOf = function(key) {
1551 | return _map[key];
1552 | };
1553 |
1554 | _this.contains = function(key) {
1555 | return typeof _map[key] != 'undefined';
1556 | };
1557 |
1558 | return _this;
1559 | };
1560 |
1561 | return _this;
1562 | };
1563 |
1564 | var createImgTag = function(width, height, getPixel, alt) {
1565 |
1566 | var gif = gifImage(width, height);
1567 | for (var y = 0; y < height; y += 1) {
1568 | for (var x = 0; x < width; x += 1) {
1569 | gif.setPixel(x, y, getPixel(x, y) );
1570 | }
1571 | }
1572 |
1573 | var b = byteArrayOutputStream();
1574 | gif.write(b);
1575 |
1576 | var base64 = base64EncodeOutputStream();
1577 | var bytes = b.toByteArray();
1578 | for (var i = 0; i < bytes.length; i += 1) {
1579 | base64.writeByte(bytes[i]);
1580 | }
1581 | base64.flush();
1582 |
1583 | var img = '';
1584 | img += 'data:image/gif;base64,';
1585 | img += base64;
1586 |
1587 | return img;
1588 | };
1589 |
1590 | //---------------------------------------------------------------------
1591 | // returns qrcode function.
1592 |
1593 | var drawImg = function(text, options) {
1594 | options = options || {};
1595 | var typeNumber = options.typeNumber || 4;
1596 | var errorCorrectLevel = options.errorCorrectLevel || 'M';
1597 | var size = options.size || 500;
1598 |
1599 | var qr;
1600 |
1601 | try {
1602 | qr = qrcode(typeNumber, errorCorrectLevel || 'M');
1603 | qr.addData(text);
1604 | qr.make();
1605 | } catch (e) {
1606 | if(typeNumber >= 40) {
1607 | throw new Error('Text too long to encode');
1608 | } else {
1609 | return drawImg(text, {
1610 | size: size,
1611 | errorCorrectLevel: errorCorrectLevel,
1612 | typeNumber: typeNumber + 1
1613 | });
1614 | }
1615 | }
1616 |
1617 | // calc cellsize and margin
1618 | var cellsize = parseInt(size / qr.getModuleCount());
1619 | var margin = parseInt((size - qr.getModuleCount() * cellsize) / 2);
1620 |
1621 | return qr.createImgTag(cellsize, margin, size);
1622 | };
1623 | module.exports = {
1624 | drawImg: drawImg
1625 | };
--------------------------------------------------------------------------------
/demo/weapp-demo/utils/weapp-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 | //---------------微信小程序基于base64生成二维码插件修改-------------------
19 | /*
20 | * @Modified: Pudon
21 | * @demoURL: https://github.com/Pudon/weapp-qrcode
22 | * @Date: 2018-09-11 14:00:05
23 | * @Last Modified by: Pudon
24 | * @Last Modified time: 2018-09-12 16:33:19
25 | */
26 | //---------------------------------------------------------------------
27 |
28 | /**
29 | * qrcode
30 | * @param typeNumber 1 to 40
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 | _moduleCount = _typeNumber * 4 + 17;
50 | _modules = function(moduleCount) {
51 | var modules = new Array(moduleCount);
52 | for (var row = 0; row < moduleCount; row += 1) {
53 | modules[row] = new Array(moduleCount);
54 | for (var col = 0; col < moduleCount; col += 1) {
55 | modules[row][col] = null;
56 | }
57 | }
58 | return modules;
59 | }(_moduleCount);
60 |
61 | setupPositionProbePattern(0, 0);
62 | setupPositionProbePattern(_moduleCount - 7, 0);
63 | setupPositionProbePattern(0, _moduleCount - 7);
64 | setupPositionAdjustPattern();
65 | setupTimingPattern();
66 | setupTypeInfo(test, maskPattern);
67 |
68 | if (_typeNumber >= 7) {
69 | setupTypeNumber(test);
70 | }
71 |
72 | if (_dataCache == null) {
73 | _dataCache = createData(_typeNumber, _errorCorrectLevel, _dataList);
74 | }
75 |
76 | mapData(_dataCache, maskPattern);
77 | };
78 |
79 | var setupPositionProbePattern = function(row, col) {
80 |
81 | for (var r = -1; r <= 7; r += 1) {
82 |
83 | if (row + r <= -1 || _moduleCount <= row + r) continue;
84 |
85 | for (var c = -1; c <= 7; c += 1) {
86 |
87 | if (col + c <= -1 || _moduleCount <= col + c) continue;
88 |
89 | if ( (0 <= r && r <= 6 && (c == 0 || c == 6) )
90 | || (0 <= c && c <= 6 && (r == 0 || r == 6) )
91 | || (2 <= r && r <= 4 && 2 <= c && c <= 4) ) {
92 | _modules[row + r][col + c] = true;
93 | } else {
94 | _modules[row + r][col + c] = false;
95 | }
96 | }
97 | }
98 | };
99 |
100 | var getBestMaskPattern = function() {
101 |
102 | var minLostPoint = 0;
103 | var pattern = 0;
104 |
105 | for (var i = 0; i < 8; i += 1) {
106 |
107 | makeImpl(true, i);
108 |
109 | var lostPoint = QRUtil.getLostPoint(_this);
110 |
111 | if (i == 0 || minLostPoint > lostPoint) {
112 | minLostPoint = lostPoint;
113 | pattern = i;
114 | }
115 | }
116 |
117 | return pattern;
118 | };
119 |
120 | var setupTimingPattern = function() {
121 |
122 | for (var r = 8; r < _moduleCount - 8; r += 1) {
123 | if (_modules[r][6] != null) {
124 | continue;
125 | }
126 | _modules[r][6] = (r % 2 == 0);
127 | }
128 |
129 | for (var c = 8; c < _moduleCount - 8; c += 1) {
130 | if (_modules[6][c] != null) {
131 | continue;
132 | }
133 | _modules[6][c] = (c % 2 == 0);
134 | }
135 | };
136 |
137 | var setupPositionAdjustPattern = function() {
138 |
139 | var pos = QRUtil.getPatternPosition(_typeNumber);
140 |
141 | for (var i = 0; i < pos.length; i += 1) {
142 |
143 | for (var j = 0; j < pos.length; j += 1) {
144 |
145 | var row = pos[i];
146 | var col = pos[j];
147 |
148 | if (_modules[row][col] != null) {
149 | continue;
150 | }
151 |
152 | for (var r = -2; r <= 2; r += 1) {
153 |
154 | for (var c = -2; c <= 2; c += 1) {
155 |
156 | if (r == -2 || r == 2 || c == -2 || c == 2
157 | || (r == 0 && c == 0) ) {
158 | _modules[row + r][col + c] = true;
159 | } else {
160 | _modules[row + r][col + c] = false;
161 | }
162 | }
163 | }
164 | }
165 | }
166 | };
167 |
168 | var setupTypeNumber = function(test) {
169 |
170 | var bits = QRUtil.getBCHTypeNumber(_typeNumber);
171 |
172 | for (var i = 0; i < 18; i += 1) {
173 | var mod = (!test && ( (bits >> i) & 1) == 1);
174 | _modules[Math.floor(i / 3)][i % 3 + _moduleCount - 8 - 3] = mod;
175 | }
176 |
177 | for (var i = 0; i < 18; i += 1) {
178 | var mod = (!test && ( (bits >> i) & 1) == 1);
179 | _modules[i % 3 + _moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
180 | }
181 | };
182 |
183 | var setupTypeInfo = function(test, maskPattern) {
184 |
185 | var data = (_errorCorrectLevel << 3) | maskPattern;
186 | var bits = QRUtil.getBCHTypeInfo(data);
187 |
188 | // vertical
189 | for (var i = 0; i < 15; i += 1) {
190 |
191 | var mod = (!test && ( (bits >> i) & 1) == 1);
192 |
193 | if (i < 6) {
194 | _modules[i][8] = mod;
195 | } else if (i < 8) {
196 | _modules[i + 1][8] = mod;
197 | } else {
198 | _modules[_moduleCount - 15 + i][8] = mod;
199 | }
200 | }
201 |
202 | // horizontal
203 | for (var i = 0; i < 15; i += 1) {
204 |
205 | var mod = (!test && ( (bits >> i) & 1) == 1);
206 |
207 | if (i < 8) {
208 | _modules[8][_moduleCount - i - 1] = mod;
209 | } else if (i < 9) {
210 | _modules[8][15 - i - 1 + 1] = mod;
211 | } else {
212 | _modules[8][15 - i - 1] = mod;
213 | }
214 | }
215 |
216 | // fixed module
217 | _modules[_moduleCount - 8][8] = (!test);
218 | };
219 |
220 | var mapData = function(data, maskPattern) {
221 |
222 | var inc = -1;
223 | var row = _moduleCount - 1;
224 | var bitIndex = 7;
225 | var byteIndex = 0;
226 | var maskFunc = QRUtil.getMaskFunction(maskPattern);
227 |
228 | for (var col = _moduleCount - 1; col > 0; col -= 2) {
229 |
230 | if (col == 6) col -= 1;
231 |
232 | while (true) {
233 |
234 | for (var c = 0; c < 2; c += 1) {
235 |
236 | if (_modules[row][col - c] == null) {
237 |
238 | var dark = false;
239 |
240 | if (byteIndex < data.length) {
241 | dark = ( ( (data[byteIndex] >>> bitIndex) & 1) == 1);
242 | }
243 |
244 | var mask = maskFunc(row, col - c);
245 |
246 | if (mask) {
247 | dark = !dark;
248 | }
249 |
250 | _modules[row][col - c] = dark;
251 | bitIndex -= 1;
252 |
253 | if (bitIndex == -1) {
254 | byteIndex += 1;
255 | bitIndex = 7;
256 | }
257 | }
258 | }
259 |
260 | row += inc;
261 |
262 | if (row < 0 || _moduleCount <= row) {
263 | row -= inc;
264 | inc = -inc;
265 | break;
266 | }
267 | }
268 | }
269 | };
270 |
271 | var createBytes = function(buffer, rsBlocks) {
272 |
273 | var offset = 0;
274 |
275 | var maxDcCount = 0;
276 | var maxEcCount = 0;
277 |
278 | var dcdata = new Array(rsBlocks.length);
279 | var ecdata = new Array(rsBlocks.length);
280 |
281 | for (var r = 0; r < rsBlocks.length; r += 1) {
282 |
283 | var dcCount = rsBlocks[r].dataCount;
284 | var ecCount = rsBlocks[r].totalCount - dcCount;
285 |
286 | maxDcCount = Math.max(maxDcCount, dcCount);
287 | maxEcCount = Math.max(maxEcCount, ecCount);
288 |
289 | dcdata[r] = new Array(dcCount);
290 |
291 | for (var i = 0; i < dcdata[r].length; i += 1) {
292 | dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
293 | }
294 | offset += dcCount;
295 |
296 | var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
297 | var rawPoly = qrPolynomial(dcdata[r], rsPoly.getLength() - 1);
298 |
299 | var modPoly = rawPoly.mod(rsPoly);
300 | ecdata[r] = new Array(rsPoly.getLength() - 1);
301 | for (var i = 0; i < ecdata[r].length; i += 1) {
302 | var modIndex = i + modPoly.getLength() - ecdata[r].length;
303 | ecdata[r][i] = (modIndex >= 0)? modPoly.getAt(modIndex) : 0;
304 | }
305 | }
306 |
307 | var totalCodeCount = 0;
308 | for (var i = 0; i < rsBlocks.length; i += 1) {
309 | totalCodeCount += rsBlocks[i].totalCount;
310 | }
311 |
312 | var data = new Array(totalCodeCount);
313 | var index = 0;
314 |
315 | for (var i = 0; i < maxDcCount; i += 1) {
316 | for (var r = 0; r < rsBlocks.length; r += 1) {
317 | if (i < dcdata[r].length) {
318 | data[index] = dcdata[r][i];
319 | index += 1;
320 | }
321 | }
322 | }
323 |
324 | for (var i = 0; i < maxEcCount; i += 1) {
325 | for (var r = 0; r < rsBlocks.length; r += 1) {
326 | if (i < ecdata[r].length) {
327 | data[index] = ecdata[r][i];
328 | index += 1;
329 | }
330 | }
331 | }
332 |
333 | return data;
334 | };
335 |
336 | var createData = function(typeNumber, errorCorrectLevel, dataList) {
337 |
338 | var rsBlocks = QRRSBlock.getRSBlocks(typeNumber, errorCorrectLevel);
339 |
340 | var buffer = qrBitBuffer();
341 |
342 | for (var i = 0; i < dataList.length; i += 1) {
343 | var data = dataList[i];
344 | buffer.put(data.getMode(), 4);
345 | buffer.put(data.getLength(), QRUtil.getLengthInBits(data.getMode(), typeNumber) );
346 | data.write(buffer);
347 | }
348 |
349 | // calc num max data.
350 | var totalDataCount = 0;
351 | for (var i = 0; i < rsBlocks.length; i += 1) {
352 | totalDataCount += rsBlocks[i].dataCount;
353 | }
354 |
355 | if (buffer.getLengthInBits() > totalDataCount * 8) {
356 | throw new Error('code length overflow. ('
357 | + buffer.getLengthInBits()
358 | + '>'
359 | + totalDataCount * 8
360 | + ')');
361 | }
362 |
363 | // end code
364 | if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
365 | buffer.put(0, 4);
366 | }
367 |
368 | // padding
369 | while (buffer.getLengthInBits() % 8 != 0) {
370 | buffer.putBit(false);
371 | }
372 |
373 | // padding
374 | while (true) {
375 |
376 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
377 | break;
378 | }
379 | buffer.put(PAD0, 8);
380 |
381 | if (buffer.getLengthInBits() >= totalDataCount * 8) {
382 | break;
383 | }
384 | buffer.put(PAD1, 8);
385 | }
386 |
387 | return createBytes(buffer, rsBlocks);
388 | };
389 |
390 | _this.addData = function(data) {
391 | var newData = qr8BitByte(data);
392 | _dataList.push(newData);
393 | _dataCache = null;
394 | };
395 |
396 | _this.isDark = function(row, col) {
397 | if (row < 0 || _moduleCount <= row || col < 0 || _moduleCount <= col) {
398 | throw new Error(row + ',' + col);
399 | }
400 | return _modules[row][col];
401 | };
402 |
403 | _this.getModuleCount = function() {
404 | return _moduleCount;
405 | };
406 |
407 | _this.make = function() {
408 | makeImpl(false, getBestMaskPattern() );
409 | };
410 |
411 | _this.createTableTag = function(cellSize, margin) {
412 |
413 | cellSize = cellSize || 2;
414 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
415 |
416 | var qrHtml = '';
417 |
418 | qrHtml += '';
423 | qrHtml += '';
424 |
425 | for (var r = 0; r < _this.getModuleCount(); r += 1) {
426 |
427 | qrHtml += '';
428 |
429 | for (var c = 0; c < _this.getModuleCount(); c += 1) {
430 | qrHtml += ' | ';
440 | }
441 |
442 | qrHtml += '
';
443 | }
444 |
445 | qrHtml += '';
446 | qrHtml += '
';
447 |
448 | return qrHtml;
449 | };
450 |
451 | _this.createImgTag = function(cellSize, margin, size) {
452 |
453 | cellSize = cellSize || 2;
454 | margin = (typeof margin == 'undefined')? cellSize * 4 : margin;
455 |
456 | var min = margin;
457 | var max = _this.getModuleCount() * cellSize + margin;
458 |
459 | return createImgTag(size, size, function(x, y) {
460 | if (min <= x && x < max && min <= y && y < max) {
461 | var c = Math.floor( (x - min) / cellSize);
462 | var r = Math.floor( (y - min) / cellSize);
463 | return _this.isDark(r, c)? 0 : 1;
464 | } else {
465 | return 1;
466 | }
467 | } );
468 | };
469 |
470 | return _this;
471 | };
472 |
473 | //---------------------------------------------------------------------
474 | // qrcode.stringToBytes
475 | //---------------------------------------------------------------------
476 |
477 | qrcode.stringToBytes = function(s) {
478 | var bytes = new Array();
479 | for (var i = 0; i < s.length; i += 1) {
480 | var c = s.charCodeAt(i);
481 | bytes.push(c & 0xff);
482 | }
483 | return bytes;
484 | };
485 |
486 | //---------------------------------------------------------------------
487 | // qrcode.createStringToBytes
488 | //---------------------------------------------------------------------
489 |
490 | /**
491 | * @param unicodeData base64 string of byte array.
492 | * [16bit Unicode],[16bit Bytes], ...
493 | * @param numChars
494 | */
495 | qrcode.createStringToBytes = function(unicodeData, numChars) {
496 |
497 | // create conversion map.
498 |
499 | var unicodeMap = function() {
500 |
501 | var bin = base64DecodeInputStream(unicodeData);
502 | var read = function() {
503 | var b = bin.read();
504 | if (b == -1) throw new Error();
505 | return b;
506 | };
507 |
508 | var count = 0;
509 | var unicodeMap = {};
510 | while (true) {
511 | var b0 = bin.read();
512 | if (b0 == -1) break;
513 | var b1 = read();
514 | var b2 = read();
515 | var b3 = read();
516 | var k = String.fromCharCode( (b0 << 8) | b1);
517 | var v = (b2 << 8) | b3;
518 | unicodeMap[k] = v;
519 | count += 1;
520 | }
521 | if (count != numChars) {
522 | throw new Error(count + ' != ' + numChars);
523 | }
524 |
525 | return unicodeMap;
526 | }();
527 |
528 | var unknownChar = '?'.charCodeAt(0);
529 |
530 | return function(s) {
531 | var bytes = new Array();
532 | for (var i = 0; i < s.length; i += 1) {
533 | var c = s.charCodeAt(i);
534 | if (c < 128) {
535 | bytes.push(c);
536 | } else {
537 | var b = unicodeMap[s.charAt(i)];
538 | if (typeof b == 'number') {
539 | if ( (b & 0xff) == b) {
540 | // 1byte
541 | bytes.push(b);
542 | } else {
543 | // 2bytes
544 | bytes.push(b >>> 8);
545 | bytes.push(b & 0xff);
546 | }
547 | } else {
548 | bytes.push(unknownChar);
549 | }
550 | }
551 | }
552 | return bytes;
553 | };
554 | };
555 |
556 | //---------------------------------------------------------------------
557 | // QRMode
558 | //---------------------------------------------------------------------
559 |
560 | var QRMode = {
561 | MODE_NUMBER : 1 << 0,
562 | MODE_ALPHA_NUM : 1 << 1,
563 | MODE_8BIT_BYTE : 1 << 2,
564 | MODE_KANJI : 1 << 3
565 | };
566 |
567 | //---------------------------------------------------------------------
568 | // QRErrorCorrectLevel
569 | //---------------------------------------------------------------------
570 |
571 | var QRErrorCorrectLevel = {
572 | L : 1,
573 | M : 0,
574 | Q : 3,
575 | H : 2
576 | };
577 |
578 | //---------------------------------------------------------------------
579 | // QRMaskPattern
580 | //---------------------------------------------------------------------
581 |
582 | var QRMaskPattern = {
583 | PATTERN000 : 0,
584 | PATTERN001 : 1,
585 | PATTERN010 : 2,
586 | PATTERN011 : 3,
587 | PATTERN100 : 4,
588 | PATTERN101 : 5,
589 | PATTERN110 : 6,
590 | PATTERN111 : 7
591 | };
592 |
593 | //---------------------------------------------------------------------
594 | // QRUtil
595 | //---------------------------------------------------------------------
596 |
597 | var QRUtil = function() {
598 |
599 | var PATTERN_POSITION_TABLE = [
600 | [],
601 | [6, 18],
602 | [6, 22],
603 | [6, 26],
604 | [6, 30],
605 | [6, 34],
606 | [6, 22, 38],
607 | [6, 24, 42],
608 | [6, 26, 46],
609 | [6, 28, 50],
610 | [6, 30, 54],
611 | [6, 32, 58],
612 | [6, 34, 62],
613 | [6, 26, 46, 66],
614 | [6, 26, 48, 70],
615 | [6, 26, 50, 74],
616 | [6, 30, 54, 78],
617 | [6, 30, 56, 82],
618 | [6, 30, 58, 86],
619 | [6, 34, 62, 90],
620 | [6, 28, 50, 72, 94],
621 | [6, 26, 50, 74, 98],
622 | [6, 30, 54, 78, 102],
623 | [6, 28, 54, 80, 106],
624 | [6, 32, 58, 84, 110],
625 | [6, 30, 58, 86, 114],
626 | [6, 34, 62, 90, 118],
627 | [6, 26, 50, 74, 98, 122],
628 | [6, 30, 54, 78, 102, 126],
629 | [6, 26, 52, 78, 104, 130],
630 | [6, 30, 56, 82, 108, 134],
631 | [6, 34, 60, 86, 112, 138],
632 | [6, 30, 58, 86, 114, 142],
633 | [6, 34, 62, 90, 118, 146],
634 | [6, 30, 54, 78, 102, 126, 150],
635 | [6, 24, 50, 76, 102, 128, 154],
636 | [6, 28, 54, 80, 106, 132, 158],
637 | [6, 32, 58, 84, 110, 136, 162],
638 | [6, 26, 54, 82, 110, 138, 166],
639 | [6, 30, 58, 86, 114, 142, 170]
640 | ];
641 | var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
642 | var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
643 | var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
644 |
645 | var _this = {};
646 |
647 | var getBCHDigit = function(data) {
648 | var digit = 0;
649 | while (data != 0) {
650 | digit += 1;
651 | data >>>= 1;
652 | }
653 | return digit;
654 | };
655 |
656 | _this.getBCHTypeInfo = function(data) {
657 | var d = data << 10;
658 | while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
659 | d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15) ) );
660 | }
661 | return ( (data << 10) | d) ^ G15_MASK;
662 | };
663 |
664 | _this.getBCHTypeNumber = function(data) {
665 | var d = data << 12;
666 | while (getBCHDigit(d) - getBCHDigit(G18) >= 0) {
667 | d ^= (G18 << (getBCHDigit(d) - getBCHDigit(G18) ) );
668 | }
669 | return (data << 12) | d;
670 | };
671 |
672 | _this.getPatternPosition = function(typeNumber) {
673 | return PATTERN_POSITION_TABLE[typeNumber - 1];
674 | };
675 |
676 | _this.getMaskFunction = function(maskPattern) {
677 |
678 | switch (maskPattern) {
679 |
680 | case QRMaskPattern.PATTERN000 :
681 | return function(i, j) { return (i + j) % 2 == 0; };
682 | case QRMaskPattern.PATTERN001 :
683 | return function(i, j) { return i % 2 == 0; };
684 | case QRMaskPattern.PATTERN010 :
685 | return function(i, j) { return j % 3 == 0; };
686 | case QRMaskPattern.PATTERN011 :
687 | return function(i, j) { return (i + j) % 3 == 0; };
688 | case QRMaskPattern.PATTERN100 :
689 | return function(i, j) { return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 == 0; };
690 | case QRMaskPattern.PATTERN101 :
691 | return function(i, j) { return (i * j) % 2 + (i * j) % 3 == 0; };
692 | case QRMaskPattern.PATTERN110 :
693 | return function(i, j) { return ( (i * j) % 2 + (i * j) % 3) % 2 == 0; };
694 | case QRMaskPattern.PATTERN111 :
695 | return function(i, j) { return ( (i * j) % 3 + (i + j) % 2) % 2 == 0; };
696 |
697 | default :
698 | throw new Error('bad maskPattern:' + maskPattern);
699 | }
700 | };
701 |
702 | _this.getErrorCorrectPolynomial = function(errorCorrectLength) {
703 | var a = qrPolynomial([1], 0);
704 | for (var i = 0; i < errorCorrectLength; i += 1) {
705 | a = a.multiply(qrPolynomial([1, QRMath.gexp(i)], 0) );
706 | }
707 | return a;
708 | };
709 |
710 | _this.getLengthInBits = function(mode, type) {
711 |
712 | if (1 <= type && type < 10) {
713 |
714 | // 1 - 9
715 |
716 | switch(mode) {
717 | case QRMode.MODE_NUMBER : return 10;
718 | case QRMode.MODE_ALPHA_NUM : return 9;
719 | case QRMode.MODE_8BIT_BYTE : return 8;
720 | case QRMode.MODE_KANJI : return 8;
721 | default :
722 | throw new Error('mode:' + mode);
723 | }
724 |
725 | } else if (type < 27) {
726 |
727 | // 10 - 26
728 |
729 | switch(mode) {
730 | case QRMode.MODE_NUMBER : return 12;
731 | case QRMode.MODE_ALPHA_NUM : return 11;
732 | case QRMode.MODE_8BIT_BYTE : return 16;
733 | case QRMode.MODE_KANJI : return 10;
734 | default :
735 | throw new Error('mode:' + mode);
736 | }
737 |
738 | } else if (type < 41) {
739 |
740 | // 27 - 40
741 |
742 | switch(mode) {
743 | case QRMode.MODE_NUMBER : return 14;
744 | case QRMode.MODE_ALPHA_NUM : return 13;
745 | case QRMode.MODE_8BIT_BYTE : return 16;
746 | case QRMode.MODE_KANJI : return 12;
747 | default :
748 | throw new Error('mode:' + mode);
749 | }
750 |
751 | } else {
752 | throw new Error('type:' + type);
753 | }
754 | };
755 |
756 | _this.getLostPoint = function(qrcode) {
757 |
758 | var moduleCount = qrcode.getModuleCount();
759 |
760 | var lostPoint = 0;
761 |
762 | // LEVEL1
763 |
764 | for (var row = 0; row < moduleCount; row += 1) {
765 | for (var col = 0; col < moduleCount; col += 1) {
766 |
767 | var sameCount = 0;
768 | var dark = qrcode.isDark(row, col);
769 |
770 | for (var r = -1; r <= 1; r += 1) {
771 |
772 | if (row + r < 0 || moduleCount <= row + r) {
773 | continue;
774 | }
775 |
776 | for (var c = -1; c <= 1; c += 1) {
777 |
778 | if (col + c < 0 || moduleCount <= col + c) {
779 | continue;
780 | }
781 |
782 | if (r == 0 && c == 0) {
783 | continue;
784 | }
785 |
786 | if (dark == qrcode.isDark(row + r, col + c) ) {
787 | sameCount += 1;
788 | }
789 | }
790 | }
791 |
792 | if (sameCount > 5) {
793 | lostPoint += (3 + sameCount - 5);
794 | }
795 | }
796 | };
797 |
798 | // LEVEL2
799 |
800 | for (var row = 0; row < moduleCount - 1; row += 1) {
801 | for (var col = 0; col < moduleCount - 1; col += 1) {
802 | var count = 0;
803 | if (qrcode.isDark(row, col) ) count += 1;
804 | if (qrcode.isDark(row + 1, col) ) count += 1;
805 | if (qrcode.isDark(row, col + 1) ) count += 1;
806 | if (qrcode.isDark(row + 1, col + 1) ) count += 1;
807 | if (count == 0 || count == 4) {
808 | lostPoint += 3;
809 | }
810 | }
811 | }
812 |
813 | // LEVEL3
814 |
815 | for (var row = 0; row < moduleCount; row += 1) {
816 | for (var col = 0; col < moduleCount - 6; col += 1) {
817 | if (qrcode.isDark(row, col)
818 | && !qrcode.isDark(row, col + 1)
819 | && qrcode.isDark(row, col + 2)
820 | && qrcode.isDark(row, col + 3)
821 | && qrcode.isDark(row, col + 4)
822 | && !qrcode.isDark(row, col + 5)
823 | && qrcode.isDark(row, col + 6) ) {
824 | lostPoint += 40;
825 | }
826 | }
827 | }
828 |
829 | for (var col = 0; col < moduleCount; col += 1) {
830 | for (var row = 0; row < moduleCount - 6; row += 1) {
831 | if (qrcode.isDark(row, col)
832 | && !qrcode.isDark(row + 1, col)
833 | && qrcode.isDark(row + 2, col)
834 | && qrcode.isDark(row + 3, col)
835 | && qrcode.isDark(row + 4, col)
836 | && !qrcode.isDark(row + 5, col)
837 | && qrcode.isDark(row + 6, col) ) {
838 | lostPoint += 40;
839 | }
840 | }
841 | }
842 |
843 | // LEVEL4
844 |
845 | var darkCount = 0;
846 |
847 | for (var col = 0; col < moduleCount; col += 1) {
848 | for (var row = 0; row < moduleCount; row += 1) {
849 | if (qrcode.isDark(row, col) ) {
850 | darkCount += 1;
851 | }
852 | }
853 | }
854 |
855 | var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
856 | lostPoint += ratio * 10;
857 |
858 | return lostPoint;
859 | };
860 |
861 | return _this;
862 | }();
863 |
864 | //---------------------------------------------------------------------
865 | // QRMath
866 | //---------------------------------------------------------------------
867 |
868 | var QRMath = function() {
869 |
870 | var EXP_TABLE = new Array(256);
871 | var LOG_TABLE = new Array(256);
872 |
873 | // initialize tables
874 | for (var i = 0; i < 8; i += 1) {
875 | EXP_TABLE[i] = 1 << i;
876 | }
877 | for (var i = 8; i < 256; i += 1) {
878 | EXP_TABLE[i] = EXP_TABLE[i - 4]
879 | ^ EXP_TABLE[i - 5]
880 | ^ EXP_TABLE[i - 6]
881 | ^ EXP_TABLE[i - 8];
882 | }
883 | for (var i = 0; i < 255; i += 1) {
884 | LOG_TABLE[EXP_TABLE[i] ] = i;
885 | }
886 |
887 | var _this = {};
888 |
889 | _this.glog = function(n) {
890 |
891 | if (n < 1) {
892 | throw new Error('glog(' + n + ')');
893 | }
894 |
895 | return LOG_TABLE[n];
896 | };
897 |
898 | _this.gexp = function(n) {
899 |
900 | while (n < 0) {
901 | n += 255;
902 | }
903 |
904 | while (n >= 256) {
905 | n -= 255;
906 | }
907 |
908 | return EXP_TABLE[n];
909 | };
910 |
911 | return _this;
912 | }();
913 |
914 | //---------------------------------------------------------------------
915 | // qrPolynomial
916 | //---------------------------------------------------------------------
917 |
918 | function qrPolynomial(num, shift) {
919 |
920 | if (typeof num.length == 'undefined') {
921 | throw new Error(num.length + '/' + shift);
922 | }
923 |
924 | var _num = function() {
925 | var offset = 0;
926 | while (offset < num.length && num[offset] == 0) {
927 | offset += 1;
928 | }
929 | var _num = new Array(num.length - offset + shift);
930 | for (var i = 0; i < num.length - offset; i += 1) {
931 | _num[i] = num[i + offset];
932 | }
933 | return _num;
934 | }();
935 |
936 | var _this = {};
937 |
938 | _this.getAt = function(index) {
939 | return _num[index];
940 | };
941 |
942 | _this.getLength = function() {
943 | return _num.length;
944 | };
945 |
946 | _this.multiply = function(e) {
947 |
948 | var num = new Array(_this.getLength() + e.getLength() - 1);
949 |
950 | for (var i = 0; i < _this.getLength(); i += 1) {
951 | for (var j = 0; j < e.getLength(); j += 1) {
952 | num[i + j] ^= QRMath.gexp(QRMath.glog(_this.getAt(i) ) + QRMath.glog(e.getAt(j) ) );
953 | }
954 | }
955 |
956 | return qrPolynomial(num, 0);
957 | };
958 |
959 | _this.mod = function(e) {
960 |
961 | if (_this.getLength() - e.getLength() < 0) {
962 | return _this;
963 | }
964 |
965 | var ratio = QRMath.glog(_this.getAt(0) ) - QRMath.glog(e.getAt(0) );
966 |
967 | var num = new Array(_this.getLength() );
968 | for (var i = 0; i < _this.getLength(); i += 1) {
969 | num[i] = _this.getAt(i);
970 | }
971 |
972 | for (var i = 0; i < e.getLength(); i += 1) {
973 | num[i] ^= QRMath.gexp(QRMath.glog(e.getAt(i) ) + ratio);
974 | }
975 |
976 | // recursive call
977 | return qrPolynomial(num, 0).mod(e);
978 | };
979 |
980 | return _this;
981 | };
982 |
983 | //---------------------------------------------------------------------
984 | // QRRSBlock
985 | //---------------------------------------------------------------------
986 |
987 | var QRRSBlock = function() {
988 |
989 |
990 | // [1: [L, M, Q, H], ..]
991 | var RS_BLOCK_TABLE=[[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],[4,101,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],[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]];
992 |
993 | var qrRSBlock = function(totalCount, dataCount) {
994 | var _this = {};
995 | _this.totalCount = totalCount;
996 | _this.dataCount = dataCount;
997 | return _this;
998 | };
999 |
1000 | var _this = {};
1001 |
1002 | var getRsBlockTable = function(typeNumber, errorCorrectLevel) {
1003 |
1004 | switch(errorCorrectLevel) {
1005 | case QRErrorCorrectLevel.L :
1006 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
1007 | case QRErrorCorrectLevel.M :
1008 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
1009 | case QRErrorCorrectLevel.Q :
1010 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
1011 | case QRErrorCorrectLevel.H :
1012 | return RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
1013 | default :
1014 | return undefined;
1015 | }
1016 | };
1017 |
1018 | _this.getRSBlocks = function(typeNumber, errorCorrectLevel) {
1019 |
1020 | var rsBlock = getRsBlockTable(typeNumber, errorCorrectLevel);
1021 |
1022 | if (typeof rsBlock == 'undefined') {
1023 | throw new Error('bad rs block @ typeNumber:' + typeNumber +
1024 | '/errorCorrectLevel:' + errorCorrectLevel);
1025 | }
1026 |
1027 | var length = rsBlock.length / 3;
1028 |
1029 | var list = new Array();
1030 |
1031 | for (var i = 0; i < length; i += 1) {
1032 |
1033 | var count = rsBlock[i * 3 + 0];
1034 | var totalCount = rsBlock[i * 3 + 1];
1035 | var dataCount = rsBlock[i * 3 + 2];
1036 |
1037 | for (var j = 0; j < count; j += 1) {
1038 | list.push(qrRSBlock(totalCount, dataCount) );
1039 | }
1040 | }
1041 |
1042 | return list;
1043 | };
1044 |
1045 | return _this;
1046 | }();
1047 |
1048 | //---------------------------------------------------------------------
1049 | // qrBitBuffer
1050 | //---------------------------------------------------------------------
1051 |
1052 | var qrBitBuffer = function() {
1053 |
1054 | var _buffer = new Array();
1055 | var _length = 0;
1056 |
1057 | var _this = {};
1058 |
1059 | _this.getBuffer = function() {
1060 | return _buffer;
1061 | };
1062 |
1063 | _this.getAt = function(index) {
1064 | var bufIndex = Math.floor(index / 8);
1065 | return ( (_buffer[bufIndex] >>> (7 - index % 8) ) & 1) == 1;
1066 | };
1067 |
1068 | _this.put = function(num, length) {
1069 | for (var i = 0; i < length; i += 1) {
1070 | _this.putBit( ( (num >>> (length - i - 1) ) & 1) == 1);
1071 | }
1072 | };
1073 |
1074 | _this.getLengthInBits = function() {
1075 | return _length;
1076 | };
1077 |
1078 | _this.putBit = function(bit) {
1079 |
1080 | var bufIndex = Math.floor(_length / 8);
1081 | if (_buffer.length <= bufIndex) {
1082 | _buffer.push(0);
1083 | }
1084 |
1085 | if (bit) {
1086 | _buffer[bufIndex] |= (0x80 >>> (_length % 8) );
1087 | }
1088 |
1089 | _length += 1;
1090 | };
1091 |
1092 | return _this;
1093 | };
1094 |
1095 | //---------------------------------------------------------------------
1096 | // qr8BitByte
1097 | //---------------------------------------------------------------------
1098 |
1099 | var qr8BitByte = function(data) {
1100 |
1101 | var _mode = QRMode.MODE_8BIT_BYTE;
1102 | var _data = data;
1103 | var _parsedData = [];
1104 |
1105 | var _this = {};
1106 |
1107 |
1108 | // Added to support UTF-8 Characters
1109 | for (var i = 0, l = _data.length; i < l; i++) {
1110 | var byteArray = [];
1111 | var code = _data.charCodeAt(i);
1112 |
1113 | if (code > 0x10000) {
1114 | byteArray[0] = 0xF0 | ((code & 0x1C0000) >>> 18);
1115 | byteArray[1] = 0x80 | ((code & 0x3F000) >>> 12);
1116 | byteArray[2] = 0x80 | ((code & 0xFC0) >>> 6);
1117 | byteArray[3] = 0x80 | (code & 0x3F);
1118 | } else if (code > 0x800) {
1119 | byteArray[0] = 0xE0 | ((code & 0xF000) >>> 12);
1120 | byteArray[1] = 0x80 | ((code & 0xFC0) >>> 6);
1121 | byteArray[2] = 0x80 | (code & 0x3F);
1122 | } else if (code > 0x80) {
1123 | byteArray[0] = 0xC0 | ((code & 0x7C0) >>> 6);
1124 | byteArray[1] = 0x80 | (code & 0x3F);
1125 | } else {
1126 | byteArray[0] = code;
1127 | }
1128 |
1129 | // Fix Unicode corruption bug
1130 | _parsedData.push(byteArray);
1131 | }
1132 |
1133 | _parsedData = Array.prototype.concat.apply([], _parsedData);
1134 |
1135 | if (_parsedData.length != _data.length) {
1136 | _parsedData.unshift(191);
1137 | _parsedData.unshift(187);
1138 | _parsedData.unshift(239);
1139 | }
1140 |
1141 | var _bytes = _parsedData;
1142 |
1143 | _this.getMode = function() {
1144 | return _mode;
1145 | };
1146 |
1147 | _this.getLength = function(buffer) {
1148 | return _bytes.length;
1149 | };
1150 |
1151 | _this.write = function(buffer) {
1152 | for (var i = 0; i < _bytes.length; i += 1) {
1153 | buffer.put(_bytes[i], 8);
1154 | }
1155 | };
1156 |
1157 | return _this;
1158 | };
1159 |
1160 | //=====================================================================
1161 | // GIF Support etc.
1162 | //
1163 |
1164 | //---------------------------------------------------------------------
1165 | // byteArrayOutputStream
1166 | //---------------------------------------------------------------------
1167 |
1168 | var byteArrayOutputStream = function() {
1169 |
1170 | var _bytes = new Array();
1171 |
1172 | var _this = {};
1173 |
1174 | _this.writeByte = function(b) {
1175 | _bytes.push(b & 0xff);
1176 | };
1177 |
1178 | _this.writeShort = function(i) {
1179 | _this.writeByte(i);
1180 | _this.writeByte(i >>> 8);
1181 | };
1182 |
1183 | _this.writeBytes = function(b, off, len) {
1184 | off = off || 0;
1185 | len = len || b.length;
1186 | for (var i = 0; i < len; i += 1) {
1187 | _this.writeByte(b[i + off]);
1188 | }
1189 | };
1190 |
1191 | _this.writeString = function(s) {
1192 | for (var i = 0; i < s.length; i += 1) {
1193 | _this.writeByte(s.charCodeAt(i) );
1194 | }
1195 | };
1196 |
1197 | _this.toByteArray = function() {
1198 | return _bytes;
1199 | };
1200 |
1201 | _this.toString = function() {
1202 | var s = '';
1203 | s += '[';
1204 | for (var i = 0; i < _bytes.length; i += 1) {
1205 | if (i > 0) {
1206 | s += ',';
1207 | }
1208 | s += _bytes[i];
1209 | }
1210 | s += ']';
1211 | return s;
1212 | };
1213 |
1214 | return _this;
1215 | };
1216 |
1217 | //---------------------------------------------------------------------
1218 | // base64EncodeOutputStream
1219 | //---------------------------------------------------------------------
1220 |
1221 | var base64EncodeOutputStream = function() {
1222 |
1223 | var _buffer = 0;
1224 | var _buflen = 0;
1225 | var _length = 0;
1226 | var _base64 = '';
1227 |
1228 | var _this = {};
1229 |
1230 | var writeEncoded = function(b) {
1231 | _base64 += String.fromCharCode(encode(b & 0x3f) );
1232 | };
1233 |
1234 | var encode = function(n) {
1235 | if (n < 0) {
1236 | // error.
1237 | } else if (n < 26) {
1238 | return 0x41 + n;
1239 | } else if (n < 52) {
1240 | return 0x61 + (n - 26);
1241 | } else if (n < 62) {
1242 | return 0x30 + (n - 52);
1243 | } else if (n == 62) {
1244 | return 0x2b;
1245 | } else if (n == 63) {
1246 | return 0x2f;
1247 | }
1248 | throw new Error('n:' + n);
1249 | };
1250 |
1251 | _this.writeByte = function(n) {
1252 |
1253 | _buffer = (_buffer << 8) | (n & 0xff);
1254 | _buflen += 8;
1255 | _length += 1;
1256 |
1257 | while (_buflen >= 6) {
1258 | writeEncoded(_buffer >>> (_buflen - 6) );
1259 | _buflen -= 6;
1260 | }
1261 | };
1262 |
1263 | _this.flush = function() {
1264 |
1265 | if (_buflen > 0) {
1266 | writeEncoded(_buffer << (6 - _buflen) );
1267 | _buffer = 0;
1268 | _buflen = 0;
1269 | }
1270 |
1271 | if (_length % 3 != 0) {
1272 | // padding
1273 | var padlen = 3 - _length % 3;
1274 | for (var i = 0; i < padlen; i += 1) {
1275 | _base64 += '=';
1276 | }
1277 | }
1278 | };
1279 |
1280 | _this.toString = function() {
1281 | return _base64;
1282 | };
1283 |
1284 | return _this;
1285 | };
1286 |
1287 | //---------------------------------------------------------------------
1288 | // base64DecodeInputStream
1289 | //---------------------------------------------------------------------
1290 |
1291 | var base64DecodeInputStream = function(str) {
1292 |
1293 | var _str = str;
1294 | var _pos = 0;
1295 | var _buffer = 0;
1296 | var _buflen = 0;
1297 |
1298 | var _this = {};
1299 |
1300 | _this.read = function() {
1301 |
1302 | while (_buflen < 8) {
1303 |
1304 | if (_pos >= _str.length) {
1305 | if (_buflen == 0) {
1306 | return -1;
1307 | }
1308 | throw new Error('unexpected end of file./' + _buflen);
1309 | }
1310 |
1311 | var c = _str.charAt(_pos);
1312 | _pos += 1;
1313 |
1314 | if (c == '=') {
1315 | _buflen = 0;
1316 | return -1;
1317 | } else if (c.match(/^\s$/) ) {
1318 | // ignore if whitespace.
1319 | continue;
1320 | }
1321 |
1322 | _buffer = (_buffer << 6) | decode(c.charCodeAt(0) );
1323 | _buflen += 6;
1324 | }
1325 |
1326 | var n = (_buffer >>> (_buflen - 8) ) & 0xff;
1327 | _buflen -= 8;
1328 | return n;
1329 | };
1330 |
1331 | var decode = function(c) {
1332 | if (0x41 <= c && c <= 0x5a) {
1333 | return c - 0x41;
1334 | } else if (0x61 <= c && c <= 0x7a) {
1335 | return c - 0x61 + 26;
1336 | } else if (0x30 <= c && c <= 0x39) {
1337 | return c - 0x30 + 52;
1338 | } else if (c == 0x2b) {
1339 | return 62;
1340 | } else if (c == 0x2f) {
1341 | return 63;
1342 | } else {
1343 | throw new Error('c:' + c);
1344 | }
1345 | };
1346 |
1347 | return _this;
1348 | };
1349 |
1350 | //---------------------------------------------------------------------
1351 | // gifImage (B/W)
1352 | //---------------------------------------------------------------------
1353 |
1354 | var gifImage = function(width, height) {
1355 |
1356 | var _width = width;
1357 | var _height = height;
1358 | var _data = new Array(width * height);
1359 |
1360 | var _this = {};
1361 |
1362 | _this.setPixel = function(x, y, pixel) {
1363 | _data[y * _width + x] = pixel;
1364 | };
1365 |
1366 | _this.write = function(out) {
1367 |
1368 | //---------------------------------
1369 | // GIF Signature
1370 |
1371 | out.writeString('GIF87a');
1372 |
1373 | //---------------------------------
1374 | // Screen Descriptor
1375 |
1376 | out.writeShort(_width);
1377 | out.writeShort(_height);
1378 |
1379 | out.writeByte(0x80); // 2bit
1380 | out.writeByte(0);
1381 | out.writeByte(0);
1382 |
1383 | //---------------------------------
1384 | // Global Color Map
1385 |
1386 | // black
1387 | out.writeByte(0x00);
1388 | out.writeByte(0x00);
1389 | out.writeByte(0x00);
1390 |
1391 | // white
1392 | out.writeByte(0xff);
1393 | out.writeByte(0xff);
1394 | out.writeByte(0xff);
1395 |
1396 | //---------------------------------
1397 | // Image Descriptor
1398 |
1399 | out.writeString(',');
1400 | out.writeShort(0);
1401 | out.writeShort(0);
1402 | out.writeShort(_width);
1403 | out.writeShort(_height);
1404 | out.writeByte(0);
1405 |
1406 | //---------------------------------
1407 | // Local Color Map
1408 |
1409 | //---------------------------------
1410 | // Raster Data
1411 |
1412 | var lzwMinCodeSize = 2;
1413 | var raster = getLZWRaster(lzwMinCodeSize);
1414 |
1415 | out.writeByte(lzwMinCodeSize);
1416 |
1417 | var offset = 0;
1418 |
1419 | while (raster.length - offset > 255) {
1420 | out.writeByte(255);
1421 | out.writeBytes(raster, offset, 255);
1422 | offset += 255;
1423 | }
1424 |
1425 | out.writeByte(raster.length - offset);
1426 | out.writeBytes(raster, offset, raster.length - offset);
1427 | out.writeByte(0x00);
1428 |
1429 | //---------------------------------
1430 | // GIF Terminator
1431 | out.writeString(';');
1432 | };
1433 |
1434 | var bitOutputStream = function(out) {
1435 |
1436 | var _out = out;
1437 | var _bitLength = 0;
1438 | var _bitBuffer = 0;
1439 |
1440 | var _this = {};
1441 |
1442 | _this.write = function(data, length) {
1443 |
1444 | if ( (data >>> length) != 0) {
1445 | throw new Error('length over');
1446 | }
1447 |
1448 | while (_bitLength + length >= 8) {
1449 | _out.writeByte(0xff & ( (data << _bitLength) | _bitBuffer) );
1450 | length -= (8 - _bitLength);
1451 | data >>>= (8 - _bitLength);
1452 | _bitBuffer = 0;
1453 | _bitLength = 0;
1454 | }
1455 |
1456 | _bitBuffer = (data << _bitLength) | _bitBuffer;
1457 | _bitLength = _bitLength + length;
1458 | };
1459 |
1460 | _this.flush = function() {
1461 | if (_bitLength > 0) {
1462 | _out.writeByte(_bitBuffer);
1463 | }
1464 | };
1465 |
1466 | return _this;
1467 | };
1468 |
1469 | var getLZWRaster = function(lzwMinCodeSize) {
1470 |
1471 | var clearCode = 1 << lzwMinCodeSize;
1472 | var endCode = (1 << lzwMinCodeSize) + 1;
1473 | var bitLength = lzwMinCodeSize + 1;
1474 |
1475 | // Setup LZWTable
1476 | var table = lzwTable();
1477 |
1478 | for (var i = 0; i < clearCode; i += 1) {
1479 | table.add(String.fromCharCode(i) );
1480 | }
1481 | table.add(String.fromCharCode(clearCode) );
1482 | table.add(String.fromCharCode(endCode) );
1483 |
1484 | var byteOut = byteArrayOutputStream();
1485 | var bitOut = bitOutputStream(byteOut);
1486 |
1487 | // clear code
1488 | bitOut.write(clearCode, bitLength);
1489 |
1490 | var dataIndex = 0;
1491 |
1492 | var s = String.fromCharCode(_data[dataIndex]);
1493 | dataIndex += 1;
1494 |
1495 | while (dataIndex < _data.length) {
1496 |
1497 | var c = String.fromCharCode(_data[dataIndex]);
1498 | dataIndex += 1;
1499 |
1500 | if (table.contains(s + c) ) {
1501 |
1502 | s = s + c;
1503 |
1504 | } else {
1505 |
1506 | bitOut.write(table.indexOf(s), bitLength);
1507 |
1508 | if (table.size() < 0xfff) {
1509 |
1510 | if (table.size() == (1 << bitLength) ) {
1511 | bitLength += 1;
1512 | }
1513 |
1514 | table.add(s + c);
1515 | }
1516 |
1517 | s = c;
1518 | }
1519 | }
1520 |
1521 | bitOut.write(table.indexOf(s), bitLength);
1522 |
1523 | // end code
1524 | bitOut.write(endCode, bitLength);
1525 |
1526 | bitOut.flush();
1527 |
1528 | return byteOut.toByteArray();
1529 | };
1530 |
1531 | var lzwTable = function() {
1532 |
1533 | var _map = {};
1534 | var _size = 0;
1535 |
1536 | var _this = {};
1537 |
1538 | _this.add = function(key) {
1539 | if (_this.contains(key) ) {
1540 | throw new Error('dup key:' + key);
1541 | }
1542 | _map[key] = _size;
1543 | _size += 1;
1544 | };
1545 |
1546 | _this.size = function() {
1547 | return _size;
1548 | };
1549 |
1550 | _this.indexOf = function(key) {
1551 | return _map[key];
1552 | };
1553 |
1554 | _this.contains = function(key) {
1555 | return typeof _map[key] != 'undefined';
1556 | };
1557 |
1558 | return _this;
1559 | };
1560 |
1561 | return _this;
1562 | };
1563 |
1564 | var createImgTag = function(width, height, getPixel, alt) {
1565 |
1566 | var gif = gifImage(width, height);
1567 | for (var y = 0; y < height; y += 1) {
1568 | for (var x = 0; x < width; x += 1) {
1569 | gif.setPixel(x, y, getPixel(x, y) );
1570 | }
1571 | }
1572 |
1573 | var b = byteArrayOutputStream();
1574 | gif.write(b);
1575 |
1576 | var base64 = base64EncodeOutputStream();
1577 | var bytes = b.toByteArray();
1578 | for (var i = 0; i < bytes.length; i += 1) {
1579 | base64.writeByte(bytes[i]);
1580 | }
1581 | base64.flush();
1582 |
1583 | var img = '';
1584 | img += 'data:image/gif;base64,';
1585 | img += base64;
1586 |
1587 | return img;
1588 | };
1589 |
1590 | //---------------------------------------------------------------------
1591 | // returns qrcode function.
1592 |
1593 | var drawImg = function(text, options) {
1594 | options = options || {};
1595 | var typeNumber = options.typeNumber || 4;
1596 | var errorCorrectLevel = options.errorCorrectLevel || 'M';
1597 | var size = options.size || 500;
1598 |
1599 | var qr;
1600 |
1601 | try {
1602 | qr = qrcode(typeNumber, errorCorrectLevel || 'M');
1603 | qr.addData(text);
1604 | qr.make();
1605 | } catch (e) {
1606 | if(typeNumber >= 40) {
1607 | throw new Error('Text too long to encode');
1608 | } else {
1609 | return drawImg(text, {
1610 | size: size,
1611 | errorCorrectLevel: errorCorrectLevel,
1612 | typeNumber: typeNumber + 1
1613 | });
1614 | }
1615 | }
1616 |
1617 | // calc cellsize and margin
1618 | var cellsize = parseInt(size / qr.getModuleCount());
1619 | var margin = parseInt((size - qr.getModuleCount() * cellsize) / 2);
1620 |
1621 | return qr.createImgTag(cellsize, margin, size);
1622 | };
1623 | module.exports = {
1624 | drawImg: drawImg
1625 | };
--------------------------------------------------------------------------------