master
1function(context, args) { // qr:<string>
2 var caller = context.caller;
3 var l = #s.scripts.lib();
4
5 if (!args || !args.qr) {
6 return { ok:false, msg:context.this_script + " { qr:<string> }"};
7 }
8
9 var qr = args.qr.split('\n');
10
11 function decode(code) {
12
13 var pattern = { ' ': [ 0, 0 ],
14 '\u2580': [1,0],
15 '\u2584': [0,1],
16 '\u2588': [1,1]
17 };
18
19 function bit(x,y) {
20 return pattern[code[y>>1][x]][y&1];
21 }
22
23 var info = {};
24 info.dimension = code[0].length;
25 info.version = (info.dimension - 17) >> 2;
26
27 var tmp = 0;
28 var i;
29 for (i = 0; i < 5; i++) {
30 tmp = (tmp << 1) | bit(i,8);
31 }
32 tmp ^= 0x15;
33 info.ecl = tmp >> 3;
34 info.mask = tmp % 0x8;
35
36 var masks = [
37 function (x,y) { return ((x + y) & 0x1) === 0;},
38 function (x,y) { return (x & 0x1) === 0;},
39 function (x,y) { return (y % 3) === 0;},
40 function (x,y) { return ((x+y) % 3) === 0;},
41// function (x,y) { return (((x>>1) + Math.floor(y / 3)) & 0x1) === 0;},
42 function (x,y) { return (((y>>1) + Math.floor(x / 3)) & 0x1) === 0;},
43 function (x,y) { return (((x*y) & 0x1) + ((x*y) % 3)) === 0;},
44 function (x,y) { return ((((x*y) & 0x1) + ((x*y) % 3)) & 0x1) === 0;},
45 function (x,y) { return (((((x+y) & 0x1) + ((x*y) % 3)) & 0x1) === 0);}
46 ];
47
48 function databit(x,y) {
49 return masks[info.mask](x,y) ^ bit(x,y);
50 }
51
52 function get_alignment(version) {
53 var result = [];
54 var step = 28 - (Math.floor(168/ (version + 7)) & 0xfe);
55
56 var i = 4 * version + 10;
57 do {
58 result.unshift(i);
59 i -= step;
60 } while ( i > 6);
61 result.unshift(6);
62 return result;
63 }
64 var alignment = get_alignment(info.version);
65
66 function is_data(x,y) {
67 if ((x == 6) || (y == 6)) return true;
68 if ((x < 9) && (y < 9)) return true;
69 if ((x < 9) && (y > info.dimension - 9 )) return true;
70 if ((x > info.dimension - 9) && (y < 9 )) return true;
71 if (info.version > 6) {
72 if ((x < 7) && (y > info.dimension - 12 )) return true;
73 if ((x > info.dimension - 12) && (y < 7 )) return true;
74 }
75 var max = alignment.length;
76 for (var i = 0; i < max; i++) {
77 for (var j = 0; j < max; j++) {
78 if ((i === 0 && (j === 0 || j == max -1)) || (i == max -1 && j === 0)) {
79 continue;
80 }
81 if ((Math.abs(x - alignment[i]) < 3) && (Math.abs(y - alignment[j]) < 3)) {
82 return true;
83 }
84 }
85 }
86 return false;
87 }
88
89 function get_codewords (count) {
90 var result = [];
91
92 var up = true;
93 var bits = 0;
94 var byte = 0;
95 for (var x = info.dimension - 1; x > 0; x -= 2) {
96 if (x == 6) x--;
97 for (var z = 0; z < info.dimension; z++) {
98 var y = up?info.dimension - z -1: z;
99 for (var col= 0; col < 2; col++) {
100 if (!is_data(x-col,y)) {
101 bits++;
102 byte <<= 1;
103 if(databit(x-col,y)) {
104 byte |= 1;
105 }
106 if (bits == 8) {
107 result.push(byte);
108 bits = 0;
109 byte = 0;
110 if (--count === 0) {
111 return result;
112 }
113 }
114 }
115 }
116 }
117 up = !up;
118 }
119 return result;
120 }
121
122 var blocks = [[
123 // Medium
124 null, [1, 16], [ 1, 28], [ 1, 44], [ 2, 64], [ 2, 86], [ 4, 108], [ 4, 124],
125 [ 4, 154], [ 5, 182], [ 5, 216], [ 5, 254], [ 8, 290], [ 9, 334],
126 [ 9, 365], [ 10, 415], [ 10, 453], [ 11, 507], [ 13, 563], [ 14, 627],
127 [ 16, 669], [ 17, 714], [ 17, 782], [ 18, 860], [ 20, 914], [ 21, 1000],
128 [ 23, 1062], [ 25, 1128], [ 26, 1193], [ 28, 1267], [ 29, 1373],
129 [ 31, 1455], [ 33, 1541], [ 35, 1631], [ 37, 1725], [ 38, 1812],
130 [ 40, 1914], [ 43, 1992], [ 45, 2102], [ 47, 2216], [ 49, 2334]
131 ],[
132 // Low
133 null, [ 1, 19], [ 1, 34], [ 1, 55], [ 1, 80], [ 1, 108], [ 2, 136],
134 [ 2, 156], [ 2, 194], [ 2, 232], [ 4, 274], [ 4, 324], [ 4, 370],
135 [ 4, 428], [ 4, 461], [ 6, 523], [ 6, 589], [ 6, 647], [ 6, 721],
136 [ 7, 795], [ 8, 861], [ 8, 932], [ 9, 1006], [ 9, 1094], [ 10, 1174],
137 [ 12, 1276], [ 12, 1370], [ 12, 1468], [ 13, 1531], [ 14, 1631],
138 [ 15, 1735], [ 16, 1843], [ 17, 1955], [ 18, 2071], [ 19, 2191],
139 [ 19, 2306], [ 20, 2434], [ 21, 2566], [ 22, 2702], [ 24, 2812],
140 [ 25, 2956]
141 ],[
142 // High
143 null, [ 1, 9], [ 1, 16], [ 2, 26], [ 4, 36], [ 4, 46], [ 4, 60], [ 5, 66],
144 [ 6, 86], [ 8, 100], [ 8, 122], [ 11, 140], [ 11, 158], [ 16, 180],
145 [ 16, 197], [ 18, 223], [ 16, 253], [ 19, 283], [ 21, 313], [ 25, 341],
146 [ 25, 385], [ 25, 406], [ 34, 442], [ 30, 464], [ 32, 514], [ 35, 538],
147 [ 37, 596], [ 40, 628], [ 42, 661], [ 45, 701], [ 48, 745], [ 51, 793],
148 [ 54, 845], [ 57, 901], [ 60, 961], [ 63, 986], [ 66, 1054], [ 70, 1096],
149 [ 74, 1142], [ 77, 1222], [ 81, 1276]
150 ],[
151 // Quater
152 null, [1, 13], [ 1, 22], [ 2, 34], [ 2, 48], [ 4, 62], [ 4, 76], [ 6, 88],
153 [ 6, 110], [ 8, 132], [ 8, 154], [ 8, 180], [ 10, 206], [ 12, 244],
154 [ 16, 261], [ 12, 295], [ 17, 325], [ 16, 367], [ 18, 397], [ 21, 445],
155 [ 20, 485], [ 23, 512], [ 23, 568], [ 25, 614], [ 27, 664], [ 29, 718],
156 [ 34, 754], [ 34, 808], [ 35, 871], [ 38, 911], [ 40, 985], [ 43, 1033],
157 [ 45, 1115], [ 48, 1171], [ 51, 1231], [ 53, 1286], [ 56, 1354],
158 [ 59, 1426], [ 62, 1502], [ 65, 1582], [ 68, 1666]
159 ]];
160
161 var counts = blocks[info.ecl][info.version];
162
163 var words = get_codewords(counts[1]);
164
165// var [ c, all ] = counts;
166 var c = counts[0];
167 var all = counts[1];
168 tmp = [];
169 for (i = 0; i < c; i++) {
170 tmp.push([]);
171 }
172 var remain = all % c;
173 for (i = 0; i < all - remain; i++) {
174 tmp[i % c].push(words[i]);
175 }
176 for (i = remain; i > 0; i--) {
177 tmp[c-i].push(words[all-i]);
178 }
179 blocks = [];
180 for (i = 0; i < c; i++) {
181 blocks = blocks.concat(tmp[i]);
182 }
183
184 var cursor = 0;
185 function getbits(count) {
186 var result = 0;
187 while ( count > 0) {
188 var tmp = Math.min(count,(8 - (cursor & 0x7)));
189 result = (result << tmp) | ((blocks[cursor >> 3] >> (8 - (cursor & 0x7) -tmp)) & ((1<<tmp) -1));
190 cursor += tmp;
191 count -= tmp;
192 }
193 return result;
194 }
195
196 function getbytes() {
197 var count;
198 if (info.version < 10) {
199 count = getbits(8);
200 } else {
201 count = getbits(16);
202 }
203 var result = "";
204 while(count--) {
205 result += String.fromCharCode(getbits(8));
206 }
207 return result;
208 }
209
210 var results = [];
211 while (cursor / 8 < blocks.length) {
212 var encoding = getbits(4);
213 if (encoding === 0) {
214 return results;
215 } else if (encoding == 4) {
216 results.push(getbytes());
217 } else {
218 return results;
219 }
220 }
221
222 return results;
223 }
224
225 return decode(qr);
226}