• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1var QRMode = require('./QRMode');
2var QRPolynomial = require('./QRPolynomial');
3var QRMath = require('./QRMath');
4var QRMaskPattern = require('./QRMaskPattern');
5
6var QRUtil = {
7
8    PATTERN_POSITION_TABLE : [
9        [],
10        [6, 18],
11        [6, 22],
12        [6, 26],
13        [6, 30],
14        [6, 34],
15        [6, 22, 38],
16        [6, 24, 42],
17        [6, 26, 46],
18        [6, 28, 50],
19        [6, 30, 54],
20        [6, 32, 58],
21        [6, 34, 62],
22        [6, 26, 46, 66],
23        [6, 26, 48, 70],
24        [6, 26, 50, 74],
25        [6, 30, 54, 78],
26        [6, 30, 56, 82],
27        [6, 30, 58, 86],
28        [6, 34, 62, 90],
29        [6, 28, 50, 72, 94],
30        [6, 26, 50, 74, 98],
31        [6, 30, 54, 78, 102],
32        [6, 28, 54, 80, 106],
33        [6, 32, 58, 84, 110],
34        [6, 30, 58, 86, 114],
35        [6, 34, 62, 90, 118],
36        [6, 26, 50, 74, 98, 122],
37        [6, 30, 54, 78, 102, 126],
38        [6, 26, 52, 78, 104, 130],
39        [6, 30, 56, 82, 108, 134],
40        [6, 34, 60, 86, 112, 138],
41        [6, 30, 58, 86, 114, 142],
42        [6, 34, 62, 90, 118, 146],
43        [6, 30, 54, 78, 102, 126, 150],
44        [6, 24, 50, 76, 102, 128, 154],
45        [6, 28, 54, 80, 106, 132, 158],
46        [6, 32, 58, 84, 110, 136, 162],
47        [6, 26, 54, 82, 110, 138, 166],
48        [6, 30, 58, 86, 114, 142, 170]
49    ],
50
51    G15 : (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
52    G18 : (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
53    G15_MASK : (1 << 14) | (1 << 12) | (1 << 10)    | (1 << 4) | (1 << 1),
54
55    getBCHTypeInfo : function(data) {
56        var d = data << 10;
57        while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
58            d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) ) );
59        }
60        return ( (data << 10) | d) ^ QRUtil.G15_MASK;
61    },
62
63    getBCHTypeNumber : function(data) {
64        var d = data << 12;
65        while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
66            d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) ) );
67        }
68        return (data << 12) | d;
69    },
70
71    getBCHDigit : function(data) {
72
73        var digit = 0;
74
75        while (data !== 0) {
76            digit++;
77            data >>>= 1;
78        }
79
80        return digit;
81    },
82
83    getPatternPosition : function(typeNumber) {
84        return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
85    },
86
87    getMask : function(maskPattern, i, j) {
88
89        switch (maskPattern) {
90
91        case QRMaskPattern.PATTERN000 : return (i + j) % 2 === 0;
92        case QRMaskPattern.PATTERN001 : return i % 2 === 0;
93        case QRMaskPattern.PATTERN010 : return j % 3 === 0;
94        case QRMaskPattern.PATTERN011 : return (i + j) % 3 === 0;
95        case QRMaskPattern.PATTERN100 : return (Math.floor(i / 2) + Math.floor(j / 3) ) % 2 === 0;
96        case QRMaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 === 0;
97        case QRMaskPattern.PATTERN110 : return ( (i * j) % 2 + (i * j) % 3) % 2 === 0;
98        case QRMaskPattern.PATTERN111 : return ( (i * j) % 3 + (i + j) % 2) % 2 === 0;
99
100        default :
101            throw new Error("bad maskPattern:" + maskPattern);
102        }
103    },
104
105    getErrorCorrectPolynomial : function(errorCorrectLength) {
106
107        var a = new QRPolynomial([1], 0);
108
109        for (var i = 0; i < errorCorrectLength; i++) {
110            a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0) );
111        }
112
113        return a;
114    },
115
116    getLengthInBits : function(mode, type) {
117
118        if (1 <= type && type < 10) {
119
120            // 1 - 9
121
122            switch(mode) {
123            case QRMode.MODE_NUMBER     : return 10;
124            case QRMode.MODE_ALPHA_NUM  : return 9;
125            case QRMode.MODE_8BIT_BYTE  : return 8;
126            case QRMode.MODE_KANJI      : return 8;
127            default :
128                throw new Error("mode:" + mode);
129            }
130
131        } else if (type < 27) {
132
133            // 10 - 26
134
135            switch(mode) {
136            case QRMode.MODE_NUMBER     : return 12;
137            case QRMode.MODE_ALPHA_NUM  : return 11;
138            case QRMode.MODE_8BIT_BYTE  : return 16;
139            case QRMode.MODE_KANJI      : return 10;
140            default :
141                throw new Error("mode:" + mode);
142            }
143
144        } else if (type < 41) {
145
146            // 27 - 40
147
148            switch(mode) {
149            case QRMode.MODE_NUMBER     : return 14;
150            case QRMode.MODE_ALPHA_NUM  : return 13;
151            case QRMode.MODE_8BIT_BYTE  : return 16;
152            case QRMode.MODE_KANJI      : return 12;
153            default :
154                throw new Error("mode:" + mode);
155            }
156
157        } else {
158            throw new Error("type:" + type);
159        }
160    },
161
162    getLostPoint : function(qrCode) {
163
164        var moduleCount = qrCode.getModuleCount();
165        var lostPoint = 0;
166        var row = 0;
167        var col = 0;
168
169
170        // LEVEL1
171
172        for (row = 0; row < moduleCount; row++) {
173
174            for (col = 0; col < moduleCount; col++) {
175
176                var sameCount = 0;
177                var dark = qrCode.isDark(row, col);
178
179                for (var r = -1; r <= 1; r++) {
180
181                    if (row + r < 0 || moduleCount <= row + r) {
182                        continue;
183                    }
184
185                    for (var c = -1; c <= 1; c++) {
186
187                        if (col + c < 0 || moduleCount <= col + c) {
188                            continue;
189                        }
190
191                        if (r === 0 && c === 0) {
192                            continue;
193                        }
194
195                        if (dark === qrCode.isDark(row + r, col + c) ) {
196                            sameCount++;
197                        }
198                    }
199                }
200
201                if (sameCount > 5) {
202                    lostPoint += (3 + sameCount - 5);
203                }
204            }
205        }
206
207        // LEVEL2
208
209        for (row = 0; row < moduleCount - 1; row++) {
210            for (col = 0; col < moduleCount - 1; col++) {
211                var count = 0;
212                if (qrCode.isDark(row,     col    ) ) count++;
213                if (qrCode.isDark(row + 1, col    ) ) count++;
214                if (qrCode.isDark(row,     col + 1) ) count++;
215                if (qrCode.isDark(row + 1, col + 1) ) count++;
216                if (count === 0 || count === 4) {
217                    lostPoint += 3;
218                }
219            }
220        }
221
222        // LEVEL3
223
224        for (row = 0; row < moduleCount; row++) {
225            for (col = 0; col < moduleCount - 6; col++) {
226                if (qrCode.isDark(row, col) &&
227                        !qrCode.isDark(row, col + 1) &&
228                         qrCode.isDark(row, col + 2) &&
229                         qrCode.isDark(row, col + 3) &&
230                         qrCode.isDark(row, col + 4) &&
231                        !qrCode.isDark(row, col + 5) &&
232                         qrCode.isDark(row, col + 6) ) {
233                    lostPoint += 40;
234                }
235            }
236        }
237
238        for (col = 0; col < moduleCount; col++) {
239            for (row = 0; row < moduleCount - 6; row++) {
240                if (qrCode.isDark(row, col) &&
241                        !qrCode.isDark(row + 1, col) &&
242                         qrCode.isDark(row + 2, col) &&
243                         qrCode.isDark(row + 3, col) &&
244                         qrCode.isDark(row + 4, col) &&
245                        !qrCode.isDark(row + 5, col) &&
246                         qrCode.isDark(row + 6, col) ) {
247                    lostPoint += 40;
248                }
249            }
250        }
251
252        // LEVEL4
253
254        var darkCount = 0;
255
256        for (col = 0; col < moduleCount; col++) {
257            for (row = 0; row < moduleCount; row++) {
258                if (qrCode.isDark(row, col) ) {
259                    darkCount++;
260                }
261            }
262        }
263
264        var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
265        lostPoint += ratio * 10;
266
267        return lostPoint;
268    }
269
270};
271
272module.exports = QRUtil;
273