master
Raw Download raw file
  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}