(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define('qrious', factory) : (global.qrious = factory()); }(this, function () { 'use strict'; var classcallcheck = function (instance, constructor) { if (!(instance instanceof constructor)) { throw new typeerror("cannot call a class as a function"); } }; var createclass = function () { function defineproperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; object.defineproperty(target, descriptor.key, descriptor); } } return function (constructor, protoprops, staticprops) { if (protoprops) defineproperties(constructor.prototype, protoprops); if (staticprops) defineproperties(constructor, staticprops); return constructor; }; }(); var inherits = function (subclass, superclass) { if (typeof superclass !== "function" && superclass !== null) { throw new typeerror("super expression must either be null or a function, not " + typeof superclass); } subclass.prototype = object.create(superclass && superclass.prototype, { constructor: { value: subclass, enumerable: false, writable: true, configurable: true } }); if (superclass) object.setprototypeof ? object.setprototypeof(subclass, superclass) : subclass.__proto__ = superclass; }; var possibleconstructorreturn = function (self, call) { if (!self) { throw new referenceerror("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }; var utilities = function () { function utilities() { classcallcheck(this, utilities); } createclass(utilities, null, [{ key: 'privatize', value: function privatize(target, source) { for (var key in source) { if (source.hasownproperty(key)) { target['_' + key] = source[key]; } } return target; } }, { key: 'setter', value: function setter(object, fieldname, value, defaultvalue, transformer) { var oldvalue = object[fieldname]; var newvalue = value != null ? value : defaultvalue; if (typeof transformer === 'function') { newvalue = transformer(newvalue); } object[fieldname] = newvalue; return newvalue !== oldvalue; } }, { key: 'throwunimplemented', value: function throwunimplemented(classname, methodname) { throw new error('"' + methodname + '" method must be implemented on the ' + classname + ' class'); } }, { key: 'touppercase', value: function touppercase(string) { return string != null && string.touppercase(); } }]); return utilities; }(); var service = function () { function service() { classcallcheck(this, service); } createclass(service, [{ key: 'getname', value: function getname() { utilities.throwunimplemented('service', 'getname'); } }]); return service; }(); var elementservice = function (_service) { inherits(elementservice, _service); function elementservice() { classcallcheck(this, elementservice); return possibleconstructorreturn(this, object.getprototypeof(elementservice).apply(this, arguments)); } createclass(elementservice, [{ key: 'createcanvas', value: function createcanvas() { utilities.throwunimplemented('elementservice', 'createcanvas'); } }, { key: 'createimage', value: function createimage() { utilities.throwunimplemented('elementservice', 'createimage'); } /** * @override */ }, { key: 'getname', value: function getname() { return 'element'; } /** * returns whether the specified element is a canvas. * * @param {*} element - the element to be checked * @return {boolean} true if element is a canvas; otherwise false. * @public */ }, { key: 'iscanvas', value: function iscanvas(element) { utilities.throwunimplemented('elementservice', 'iscanvas'); } /** * returns whether the specified element is an image. * * @param {*} element - the element to be checked * @return {boolean} true if element is an image; otherwise false. * @public */ }, { key: 'isimage', value: function isimage(element) { utilities.throwunimplemented('elementservice', 'isimage'); } }]); return elementservice; }(service); /** * an implementation of {@link elementservice} intended for use within a browser environment. * * @public * @extends elementservice */ var browserelementservice = function (_elementservice) { inherits(browserelementservice, _elementservice); function browserelementservice() { classcallcheck(this, browserelementservice); return possibleconstructorreturn(this, object.getprototypeof(browserelementservice).apply(this, arguments)); } createclass(browserelementservice, [{ key: 'createcanvas', /** * @override */ value: function createcanvas() { return document.createelement('canvas'); } /** * @override */ }, { key: 'createimage', value: function createimage() { return document.createelement('img'); } /** * @override */ }, { key: 'iscanvas', value: function iscanvas(element) { return element instanceof htmlcanvaselement; } /** * @override */ }, { key: 'isimage', value: function isimage(element) { return element instanceof htmlimageelement; } }]); return browserelementservice; }(elementservice); /** * responsible for rendering a qr code {@link frame} on a specific type of element. * * a renderer may be dependant on the rendering of another element, so ordering of their execution is important. * * @public */ var renderer = function () { /** * creates a new instance of {@link renderer} for the qrious instance provided. * * @param {qrious} qrious - the {@link qrious} instance to be used * @public */ function renderer(qrious) { classcallcheck(this, renderer); /** * the {@link qrious} instance. * * @protected * @type {qrious} */ this.qrious = qrious; } /** * draws the specified qr code frame on the underlying element. * * implementations of {@link renderer} must override this method with their own specific logic. * * @param {frame} frame - the {@link frame} to be drawn * @protected */ createclass(renderer, [{ key: 'draw', value: function draw(frame) { utilities.throwunimplemented('renderer', 'draw'); } /** * calculates the size (in pixel units) to represent an individual module within the qr code based on the * frame provided. * * the returned value will be at least one, even in cases where the size of the qr code does not fit its contents. * this is done so that the inevitable clipping is handled more gracefully since this way at least something is * displayed instead of just a blank space filled by the background color. * * @param {frame} frame - the {@link frame} from which the module size is to be derived * @return {number} the pixel size for each module in the qr code which will be no less than one. * @protected */ }, { key: 'getmodulesize', value: function getmodulesize(frame) { var pixels = math.floor(this.qrious.size / frame.width); return math.max(1, pixels); } /** * calculates the offset/padding (in pixel units) to be inserted before the qr code based on the frame * provided. * * the returned value will be zero if there is no available offset or if the size of the qr code does not fit its * contents. it will never be a negative value. this is done so that the inevitable clipping appears more naturally * and it is not clipped from all directions. * * @param {frame} frame - the {@link frame} from which the offset is to be derived * @return {number} the pixel offset for the qr code which will be no less than zero. * @protected */ }, { key: 'getoffset', value: function getoffset(frame) { var modulesize = this.getmodulesize(frame); var offset = math.floor((this.qrious.size - modulesize * frame.width) / 2); return math.max(0, offset); } /** * renders a qr code on the underlying element based on the frame provided. * * @param {frame} frame - the {@link frame} to be rendered * @public */ }, { key: 'render', value: function render(frame) { this.resize(); this.reset(); this.draw(frame); } /** * resets the underlying element, effectively clearing any previously rendered qr code. * * implementations of {@link renderer} must override this method with their own specific logic. * * @protected */ }, { key: 'reset', value: function reset() { utilities.throwunimplemented('renderer', 'reset'); } /** * ensures that the size of the underlying element matches that defined on the associated {@link qrious} instance. * * implementations of {@link renderer} must override this method with their own specific logic. * * @protected */ }, { key: 'resize', value: function resize() { utilities.throwunimplemented('renderer', 'resize'); } }]); return renderer; }(); /** * an implementation of {@link renderer} for working with canvas elements. * * @public * @extends renderer */ var canvasrenderer = function (_renderer) { inherits(canvasrenderer, _renderer); function canvasrenderer() { classcallcheck(this, canvasrenderer); return possibleconstructorreturn(this, object.getprototypeof(canvasrenderer).apply(this, arguments)); } createclass(canvasrenderer, [{ key: 'draw', /** * @override */ value: function draw(frame) { var qrious = this.qrious; var modulesize = this.getmodulesize(frame); var offset = this.getoffset(frame); var context = qrious.canvas.getcontext('2d'); context.fillstyle = qrious.foreground; for (var i = 0; i < frame.width; i++) { for (var j = 0; j < frame.width; j++) { if (frame.buffer[j * frame.width + i]) { context.fillrect(modulesize * i + offset, modulesize * j + offset, modulesize, modulesize); } } } } /** * @override */ }, { key: 'reset', value: function reset() { var qrious = this.qrious; var context = qrious.canvas.getcontext('2d'); context.linewidth = 1; context.clearrect(0, 0, qrious.size, qrious.size); context.fillstyle = qrious.background; context.fillrect(0, 0, qrious.size, qrious.size); } /** * @override */ }, { key: 'resize', value: function resize() { var qrious = this.qrious; var canvas = qrious.canvas; canvas.width = qrious.size; canvas.height = qrious.size; } }]); return canvasrenderer; }(renderer); /* eslint no-multi-spaces: 0 */ /** * contains alignment pattern information. * * @public */ var alignment = function () { function alignment() { classcallcheck(this, alignment); } createclass(alignment, null, [{ key: "block", /** * returns the alignment pattern block. * * @return {number[]} the alignment pattern block. * @public * @static */ get: function get() { return [0, 11, 15, 19, 23, 27, 31, 16, 18, 20, 22, 24, 26, 28, 20, 22, 24, 24, 26, 28, 28, 22, 24, 24, 26, 26, 28, 28, 24, 24, 26, 26, 26, 28, 28, 24, 26, 26, 26, 28, 28]; } }]); return alignment; }(); var errorcorrection = function () { function errorcorrection() { classcallcheck(this, errorcorrection); } createclass(errorcorrection, null, [{ key: "blocks", get: function get() { return [1, 0, 19, 7, 1, 0, 16, 10, 1, 0, 13, 13, 1, 0, 9, 17, 1, 0, 34, 10, 1, 0, 28, 16, 1, 0, 22, 22, 1, 0, 16, 28, 1, 0, 55, 15, 1, 0, 44, 26, 2, 0, 17, 18, 2, 0, 13, 22, 1, 0, 80, 20, 2, 0, 32, 18, 2, 0, 24, 26, 4, 0, 9, 16, 1, 0, 108, 26, 2, 0, 43, 24, 2, 2, 15, 18, 2, 2, 11, 22, 2, 0, 68, 18, 4, 0, 27, 16, 4, 0, 19, 24, 4, 0, 15, 28, 2, 0, 78, 20, 4, 0, 31, 18, 2, 4, 14, 18, 4, 1, 13, 26, 2, 0, 97, 24, 2, 2, 38, 22, 4, 2, 18, 22, 4, 2, 14, 26, 2, 0, 116, 30, 3, 2, 36, 22, 4, 4, 16, 20, 4, 4, 12, 24, 2, 2, 68, 18, 4, 1, 43, 26, 6, 2, 19, 24, 6, 2, 15, 28, 4, 0, 81, 20, 1, 4, 50, 30, 4, 4, 22, 28, 3, 8, 12, 24, 2, 2, 92, 24, 6, 2, 36, 22, 4, 6, 20, 26, 7, 4, 14, 28, 4, 0, 107, 26, 8, 1, 37, 22, 8, 4, 20, 24, 12, 4, 11, 22, 3, 1, 115, 30, 4, 5, 40, 24, 11, 5, 16, 20, 11, 5, 12, 24, 5, 1, 87, 22, 5, 5, 41, 24, 5, 7, 24, 30, 11, 7, 12, 24, 5, 1, 98, 24, 7, 3, 45, 28, 15, 2, 19, 24, 3, 13, 15, 30, 1, 5, 107, 28, 10, 1, 46, 28, 1, 15, 22, 28, 2, 17, 14, 28, 5, 1, 120, 30, 9, 4, 43, 26, 17, 1, 22, 28, 2, 19, 14, 28, 3, 4, 113, 28, 3, 11, 44, 26, 17, 4, 21, 26, 9, 16, 13, 26, 3, 5, 107, 28, 3, 13, 41, 26, 15, 5, 24, 30, 15, 10, 15, 28, 4, 4, 116, 28, 17, 0, 42, 26, 17, 6, 22, 28, 19, 6, 16, 30, 2, 7, 111, 28, 17, 0, 46, 28, 7, 16, 24, 30, 34, 0, 13, 24, 4, 5, 121, 30, 4, 14, 47, 28, 11, 14, 24, 30, 16, 14, 15, 30, 6, 4, 117, 30, 6, 14, 45, 28, 11, 16, 24, 30, 30, 2, 16, 30, 8, 4, 106, 26, 8, 13, 47, 28, 7, 22, 24, 30, 22, 13, 15, 30, 10, 2, 114, 28, 19, 4, 46, 28, 28, 6, 22, 28, 33, 4, 16, 30, 8, 4, 122, 30, 22, 3, 45, 28, 8, 26, 23, 30, 12, 28, 15, 30, 3, 10, 117, 30, 3, 23, 45, 28, 4, 31, 24, 30, 11, 31, 15, 30, 7, 7, 116, 30, 21, 7, 45, 28, 1, 37, 23, 30, 19, 26, 15, 30, 5, 10, 115, 30, 19, 10, 47, 28, 15, 25, 24, 30, 23, 25, 15, 30, 13, 3, 115, 30, 2, 29, 46, 28, 42, 1, 24, 30, 23, 28, 15, 30, 17, 0, 115, 30, 10, 23, 46, 28, 10, 35, 24, 30, 19, 35, 15, 30, 17, 1, 115, 30, 14, 21, 46, 28, 29, 19, 24, 30, 11, 46, 15, 30, 13, 6, 115, 30, 14, 23, 46, 28, 44, 7, 24, 30, 59, 1, 16, 30, 12, 7, 121, 30, 12, 26, 47, 28, 39, 14, 24, 30, 22, 41, 15, 30, 6, 14, 121, 30, 6, 34, 47, 28, 46, 10, 24, 30, 2, 64, 15, 30, 17, 4, 122, 30, 29, 14, 46, 28, 49, 10, 24, 30, 24, 46, 15, 30, 4, 18, 122, 30, 13, 32, 46, 28, 48, 14, 24, 30, 42, 32, 15, 30, 20, 4, 117, 30, 40, 7, 47, 28, 43, 22, 24, 30, 10, 67, 15, 30, 19, 6, 118, 30, 18, 31, 47, 28, 34, 34, 24, 30, 20, 61, 15, 30]; } /** * returns the final format bits with mask (level << 3 | mask). * * @return {number[]} the final format bits. * @public * @static */ }, { key: "final_format", get: function get() { return [ // l 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976, // m 0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0, // q 0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed, // h 0x1689, 0x13be, 0x1ce7, 0x19d0, 0x0762, 0x0255, 0x0d0c, 0x083b]; } /** * returns a map of human-readable ecc levels. * * @return {object} a ecc level mapping. * @public * @static */ }, { key: "levels", get: function get() { return { l: 1, m: 2, q: 3, h: 4 }; } }]); return errorcorrection; }(); var galois = function () { function galois() { classcallcheck(this, galois); } createclass(galois, null, [{ key: "exponent", /** * returns the galois field exponent table. * * @return {number[]} the galois field exponent table. * @public * @static */ get: function get() { return [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1d, 0x3a, 0x74, 0xe8, 0xcd, 0x87, 0x13, 0x26, 0x4c, 0x98, 0x2d, 0x5a, 0xb4, 0x75, 0xea, 0xc9, 0x8f, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x9d, 0x27, 0x4e, 0x9c, 0x25, 0x4a, 0x94, 0x35, 0x6a, 0xd4, 0xb5, 0x77, 0xee, 0xc1, 0x9f, 0x23, 0x46, 0x8c, 0x05, 0x0a, 0x14, 0x28, 0x50, 0xa0, 0x5d, 0xba, 0x69, 0xd2, 0xb9, 0x6f, 0xde, 0xa1, 0x5f, 0xbe, 0x61, 0xc2, 0x99, 0x2f, 0x5e, 0xbc, 0x65, 0xca, 0x89, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0xfd, 0xe7, 0xd3, 0xbb, 0x6b, 0xd6, 0xb1, 0x7f, 0xfe, 0xe1, 0xdf, 0xa3, 0x5b, 0xb6, 0x71, 0xe2, 0xd9, 0xaf, 0x43, 0x86, 0x11, 0x22, 0x44, 0x88, 0x0d, 0x1a, 0x34, 0x68, 0xd0, 0xbd, 0x67, 0xce, 0x81, 0x1f, 0x3e, 0x7c, 0xf8, 0xed, 0xc7, 0x93, 0x3b, 0x76, 0xec, 0xc5, 0x97, 0x33, 0x66, 0xcc, 0x85, 0x17, 0x2e, 0x5c, 0xb8, 0x6d, 0xda, 0xa9, 0x4f, 0x9e, 0x21, 0x42, 0x84, 0x15, 0x2a, 0x54, 0xa8, 0x4d, 0x9a, 0x29, 0x52, 0xa4, 0x55, 0xaa, 0x49, 0x92, 0x39, 0x72, 0xe4, 0xd5, 0xb7, 0x73, 0xe6, 0xd1, 0xbf, 0x63, 0xc6, 0x91, 0x3f, 0x7e, 0xfc, 0xe5, 0xd7, 0xb3, 0x7b, 0xf6, 0xf1, 0xff, 0xe3, 0xdb, 0xab, 0x4b, 0x96, 0x31, 0x62, 0xc4, 0x95, 0x37, 0x6e, 0xdc, 0xa5, 0x57, 0xae, 0x41, 0x82, 0x19, 0x32, 0x64, 0xc8, 0x8d, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xdd, 0xa7, 0x53, 0xa6, 0x51, 0xa2, 0x59, 0xb2, 0x79, 0xf2, 0xf9, 0xef, 0xc3, 0x9b, 0x2b, 0x56, 0xac, 0x45, 0x8a, 0x09, 0x12, 0x24, 0x48, 0x90, 0x3d, 0x7a, 0xf4, 0xf5, 0xf7, 0xf3, 0xfb, 0xeb, 0xcb, 0x8b, 0x0b, 0x16, 0x2c, 0x58, 0xb0, 0x7d, 0xfa, 0xe9, 0xcf, 0x83, 0x1b, 0x36, 0x6c, 0xd8, 0xad, 0x47, 0x8e, 0x00]; } /** * returns the galois field log table. * * @return {number[]} the galois field log table. * @public * @static */ }, { key: "log", get: function get() { return [0xff, 0x00, 0x01, 0x19, 0x02, 0x32, 0x1a, 0xc6, 0x03, 0xdf, 0x33, 0xee, 0x1b, 0x68, 0xc7, 0x4b, 0x04, 0x64, 0xe0, 0x0e, 0x34, 0x8d, 0xef, 0x81, 0x1c, 0xc1, 0x69, 0xf8, 0xc8, 0x08, 0x4c, 0x71, 0x05, 0x8a, 0x65, 0x2f, 0xe1, 0x24, 0x0f, 0x21, 0x35, 0x93, 0x8e, 0xda, 0xf0, 0x12, 0x82, 0x45, 0x1d, 0xb5, 0xc2, 0x7d, 0x6a, 0x27, 0xf9, 0xb9, 0xc9, 0x9a, 0x09, 0x78, 0x4d, 0xe4, 0x72, 0xa6, 0x06, 0xbf, 0x8b, 0x62, 0x66, 0xdd, 0x30, 0xfd, 0xe2, 0x98, 0x25, 0xb3, 0x10, 0x91, 0x22, 0x88, 0x36, 0xd0, 0x94, 0xce, 0x8f, 0x96, 0xdb, 0xbd, 0xf1, 0xd2, 0x13, 0x5c, 0x83, 0x38, 0x46, 0x40, 0x1e, 0x42, 0xb6, 0xa3, 0xc3, 0x48, 0x7e, 0x6e, 0x6b, 0x3a, 0x28, 0x54, 0xfa, 0x85, 0xba, 0x3d, 0xca, 0x5e, 0x9b, 0x9f, 0x0a, 0x15, 0x79, 0x2b, 0x4e, 0xd4, 0xe5, 0xac, 0x73, 0xf3, 0xa7, 0x57, 0x07, 0x70, 0xc0, 0xf7, 0x8c, 0x80, 0x63, 0x0d, 0x67, 0x4a, 0xde, 0xed, 0x31, 0xc5, 0xfe, 0x18, 0xe3, 0xa5, 0x99, 0x77, 0x26, 0xb8, 0xb4, 0x7c, 0x11, 0x44, 0x92, 0xd9, 0x23, 0x20, 0x89, 0x2e, 0x37, 0x3f, 0xd1, 0x5b, 0x95, 0xbc, 0xcf, 0xcd, 0x90, 0x87, 0x97, 0xb2, 0xdc, 0xfc, 0xbe, 0x61, 0xf2, 0x56, 0xd3, 0xab, 0x14, 0x2a, 0x5d, 0x9e, 0x84, 0x3c, 0x39, 0x53, 0x47, 0x6d, 0x41, 0xa2, 0x1f, 0x2d, 0x43, 0xd8, 0xb7, 0x7b, 0xa4, 0x76, 0xc4, 0x17, 0x49, 0xec, 0x7f, 0x0c, 0x6f, 0xf6, 0x6c, 0xa1, 0x3b, 0x52, 0x29, 0x9d, 0x55, 0xaa, 0xfb, 0x60, 0x86, 0xb1, 0xbb, 0xcc, 0x3e, 0x5a, 0xcb, 0x59, 0x5f, 0xb0, 0x9c, 0xa9, 0xa0, 0x51, 0x0b, 0xf5, 0x16, 0xeb, 0x7a, 0x75, 0x2c, 0xd7, 0x4f, 0xae, 0xd5, 0xe9, 0xe6, 0xe7, 0xad, 0xe8, 0x74, 0xd6, 0xf4, 0xea, 0xa8, 0x50, 0x58, 0xaf]; } }]); return galois; }(); var version = function () { function version() { classcallcheck(this, version); } createclass(version, null, [{ key: "block", get: function get() { return [0xc94, 0x5bc, 0xa99, 0x4d3, 0xbf6, 0x762, 0x847, 0x60d, 0x928, 0xb78, 0x45d, 0xa17, 0x532, 0x9a6, 0x683, 0x8c9, 0x7ec, 0xec4, 0x1e1, 0xfab, 0x08e, 0xc1a, 0x33f, 0xd75, 0x250, 0x9d5, 0x6f0, 0x8ba, 0x79f, 0xb0b, 0x42e, 0xa64, 0x541, 0xc69]; } }]); return version; }(); /** * generates information for a qr code frame based on a specific value to be encoded. * * @public */ var frame = function () { createclass(frame, null, [{ key: '_createarray', value: function _createarray(length) { var array = []; for (var i = 0; i < length; i++) { array[i] = 0; } return array; } }, { key: '_getmaskbit', value: function _getmaskbit(x, y) { var bit = void 0; if (x > y) { bit = x; x = y; y = bit; } bit = y; bit += y * y; bit >>= 1; bit += x; return bit; } }, { key: '_modn', value: function _modn(x) { while (x >= 255) { x -= 255; x = (x >> 8) + (x & 255); } return x; } // *badness* coefficients. }, { key: 'n1', get: function get() { return 3; } }, { key: 'n2', get: function get() { return 3; } }, { key: 'n3', get: function get() { return 40; } }, { key: 'n4', get: function get() { return 10; } /** * creates an instance of {@link frame} based on the options provided. * * @param {frame~options} options - the options to be used * @public */ }]); function frame(options) { classcallcheck(this, frame); this._badness = []; this._level = errorcorrection.levels[options.level]; this._polynomial = []; this._value = options.value; this._valuelength = this._value.length; this._version = 0; this._stringbuffer = this._value.slice(0); var datablock = void 0; var eccblock = void 0; var neccblock1 = void 0; var neccblock2 = void 0; while (this._version < 40) { this._version++; var index = (this._level - 1) * 4 + (this._version - 1) * 16; neccblock1 = errorcorrection.blocks[index++]; neccblock2 = errorcorrection.blocks[index++]; datablock = errorcorrection.blocks[index++]; eccblock = errorcorrection.blocks[index]; index = datablock * (neccblock1 + neccblock2) + neccblock2 - 3 + (this._version <= 9); if (this._valuelength <= index) { break; } } this._datablock = datablock; this._eccblock = eccblock; this._neccblock1 = neccblock1; this._neccblock2 = neccblock2; // fixme: ensure that it fits instead of being truncated. this.width = 17 + 4 * this._version; this.buffer = frame._createarray(this.width * this.width); this._ecc = frame._createarray(this._datablock + (this._datablock + this._eccblock) * (this._neccblock1 + this._neccblock2) + this._neccblock2); this._mask = frame._createarray((this.width * (this.width + 1) + 1) / 2); this._insertfinders(); this._insertalignments(); // insert single foreground cell. this.buffer[8 + this.width * (this.width - 8)] = 1; this._inserttiminggap(); this._reversemask(); this._inserttimingrowandcolumn(); this._insertversion(); this._syncmask(); this._convertbitstream(this._stringbuffer.length); this._calculatepolynomial(); this._appendecctodata(); this._interleaveblocks(); this._pack(); this._finish(); } createclass(frame, [{ key: '_addalignment', value: function _addalignment(x, y) { this.buffer[x + this.width * y] = 1; for (var i = -2; i < 2; i++) { this.buffer[x + i + this.width * (y - 2)] = 1; this.buffer[x - 2 + this.width * (y + i + 1)] = 1; this.buffer[x + 2 + this.width * (y + i)] = 1; this.buffer[x + i + 1 + this.width * (y + 2)] = 1; } for (var _i = 0; _i < 2; _i++) { this._setmask(x - 1, y + _i); this._setmask(x + 1, y - _i); this._setmask(x - _i, y - 1); this._setmask(x + _i, y + 1); } } }, { key: '_appenddata', value: function _appenddata(data, datalength, ecc, ecclength) { for (var i = 0; i < ecclength; i++) { this._stringbuffer[ecc + i] = 0; } for (var _i2 = 0; _i2 < datalength; _i2++) { var bit = galois.log[this._stringbuffer[data + _i2] ^ this._stringbuffer[ecc]]; if (bit !== 255) { for (var j = 1; j < ecclength; j++) { this._stringbuffer[ecc + j - 1] = this._stringbuffer[ecc + j] ^ galois.exponent[frame._modn(bit + this._polynomial[ecclength - j])]; } } else { for (var _j = ecc; _j < ecc + ecclength; _j++) { this._stringbuffer[_j] = this._stringbuffer[_j + 1]; } } this._stringbuffer[ecc + ecclength - 1] = bit === 255 ? 0 : galois.exponent[frame._modn(bit + this._polynomial[0])]; } } }, { key: '_appendecctodata', value: function _appendecctodata() { var data = 0; var ecc = this._calculatemaxlength(); for (var i = 0; i < this._neccblock1; i++) { this._appenddata(data, this._datablock, ecc, this._eccblock); data += this._datablock; ecc += this._eccblock; } for (var _i3 = 0; _i3 < this._neccblock2; _i3++) { this._appenddata(data, this._datablock + 1, ecc, this._eccblock); data += this._datablock + 1; ecc += this._eccblock; } } }, { key: '_applymask', value: function _applymask(mask) { var width = this.width; switch (mask) { case 0: for (var y = 0; y < width; y++) { for (var x = 0; x < width; x++) { if (!(x + y & 1) && !this._ismasked(x, y)) { this.buffer[x + y * width] ^= 1; } } } break; case 1: for (var _y = 0; _y < width; _y++) { for (var _x = 0; _x < width; _x++) { if (!(_y & 1) && !this._ismasked(_x, _y)) { this.buffer[_x + _y * width] ^= 1; } } } break; case 2: for (var _y2 = 0; _y2 < width; _y2++) { for (var r3x = 0, _x2 = 0; _x2 < width; _x2++, r3x++) { if (r3x === 3) { r3x = 0; } if (!r3x && !this._ismasked(_x2, _y2)) { this.buffer[_x2 + _y2 * width] ^= 1; } } } break; case 3: for (var r3y = 0, _y3 = 0; _y3 < width; _y3++, r3y++) { if (r3y === 3) { r3y = 0; } for (var _r3x = r3y, _x3 = 0; _x3 < width; _x3++, _r3x++) { if (_r3x === 3) { _r3x = 0; } if (!_r3x && !this._ismasked(_x3, _y3)) { this.buffer[_x3 + _y3 * width] ^= 1; } } } break; case 4: for (var _y4 = 0; _y4 < width; _y4++) { for (var _r3x2 = 0, _r3y = _y4 >> 1 & 1, _x4 = 0; _x4 < width; _x4++, _r3x2++) { if (_r3x2 === 3) { _r3x2 = 0; _r3y = !_r3y; } if (!_r3y && !this._ismasked(_x4, _y4)) { this.buffer[_x4 + _y4 * width] ^= 1; } } } break; case 5: for (var _r3y2 = 0, _y5 = 0; _y5 < width; _y5++, _r3y2++) { if (_r3y2 === 3) { _r3y2 = 0; } for (var _r3x3 = 0, _x5 = 0; _x5 < width; _x5++, _r3x3++) { if (_r3x3 === 3) { _r3x3 = 0; } if (!((_x5 & _y5 & 1) + !(!_r3x3 | !_r3y2)) && !this._ismasked(_x5, _y5)) { this.buffer[_x5 + _y5 * width] ^= 1; } } } break; case 6: for (var _r3y3 = 0, _y6 = 0; _y6 < width; _y6++, _r3y3++) { if (_r3y3 === 3) { _r3y3 = 0; } for (var _r3x4 = 0, _x6 = 0; _x6 < width; _x6++, _r3x4++) { if (_r3x4 === 3) { _r3x4 = 0; } if (!(_x6 & _y6 & 1 + (_r3x4 && _r3x4 === _r3y3) & 1) && !this._ismasked(_x6, _y6)) { this.buffer[_x6 + _y6 * width] ^= 1; } } } break; case 7: for (var _r3y4 = 0, _y7 = 0; _y7 < width; _y7++, _r3y4++) { if (_r3y4 === 3) { _r3y4 = 0; } for (var _r3x5 = 0, _x7 = 0; _x7 < width; _x7++, _r3x5++) { if (_r3x5 === 3) { _r3x5 = 0; } if (!((_r3x5 && _r3x5 === _r3y4) + (_x7 + _y7 & 1) & 1) && !this._ismasked(_x7, _y7)) { this.buffer[_x7 + _y7 * width] ^= 1; } } } break; } } }, { key: '_calculatemaxlength', value: function _calculatemaxlength() { return this._datablock * (this._neccblock1 + this._neccblock2) + this._neccblock2; } }, { key: '_calculatepolynomial', value: function _calculatepolynomial() { this._polynomial[0] = 1; for (var i = 0; i < this._eccblock; i++) { this._polynomial[i + 1] = 1; for (var j = i; j > 0; j--) { this._polynomial[j] = this._polynomial[j] ? this._polynomial[j - 1] ^ galois.exponent[frame._modn(galois.log[this._polynomial[j]] + i)] : this._polynomial[j - 1]; } this._polynomial[0] = galois.exponent[frame._modn(galois.log[this._polynomial[0]] + i)]; } // use logs for generator polynomial to save calculation step. for (var _i4 = 0; _i4 <= this._eccblock; _i4++) { this._polynomial[_i4] = galois.log[this._polynomial[_i4]]; } } }, { key: '_checkbadness', value: function _checkbadness() { var bad = 0; var width = this.width; // blocks of same colour. for (var y = 0; y < width - 1; y++) { for (var x = 0; x < width - 1; x++) { // all foreground colour. if (this.buffer[x + width * y] && this.buffer[x + 1 + width * y] && this.buffer[x + width * (y + 1)] && this.buffer[x + 1 + width * (y + 1)] || // all background colour. !(this.buffer[x + width * y] || this.buffer[x + 1 + width * y] || this.buffer[x + width * (y + 1)] || this.buffer[x + 1 + width * (y + 1)])) { bad += frame.n2; } } } var bw = 0; // x runs. for (var _y8 = 0; _y8 < width; _y8++) { var h = 0; this._badness[0] = 0; for (var b = 0, _x8 = 0; _x8 < width; _x8++) { var b1 = this.buffer[_x8 + width * _y8]; if (b === b1) { this._badness[h]++; } else { this._badness[++h] = 1; } b = b1; bw += b ? 1 : -1; } bad += this._getbadness(h); } if (bw < 0) { bw = -bw; } var count = 0; var big = bw; big += big << 2; big <<= 1; while (big > width * width) { big -= width * width; count++; } bad += count * frame.n4; // y runs. for (var _x9 = 0; _x9 < width; _x9++) { var _h = 0; this._badness[0] = 0; for (var _b = 0, _y9 = 0; _y9 < width; _y9++) { var _b2 = this.buffer[_x9 + width * _y9]; if (_b === _b2) { this._badness[_h]++; } else { this._badness[++_h] = 1; } _b = _b2; } bad += this._getbadness(_h); } return bad; } }, { key: '_convertbitstream', value: function _convertbitstream(length) { // convert string to bit stream. 8-bit data to qr-coded 8-bit data (numeric, alphanum, or kanji // not supported). for (var i = 0; i < length; i++) { this._ecc[i] = this._stringbuffer.charcodeat(i); } this._stringbuffer = this._ecc.slice(0); var maxlength = this._calculatemaxlength(); if (length >= maxlength - 2) { length = maxlength - 2; if (this._version > 9) { length--; } } // shift and re-pack to insert length prefix. var index = length; if (this._version > 9) { this._stringbuffer[index + 2] = 0; this._stringbuffer[index + 3] = 0; while (index--) { var bit = this._stringbuffer[index]; this._stringbuffer[index + 3] |= 255 & bit << 4; this._stringbuffer[index + 2] = bit >> 4; } this._stringbuffer[2] |= 255 & length << 4; this._stringbuffer[1] = length >> 4; this._stringbuffer[0] = 0x40 | length >> 12; } else { this._stringbuffer[index + 1] = 0; this._stringbuffer[index + 2] = 0; while (index--) { var _bit = this._stringbuffer[index]; this._stringbuffer[index + 2] |= 255 & _bit << 4; this._stringbuffer[index + 1] = _bit >> 4; } this._stringbuffer[1] |= 255 & length << 4; this._stringbuffer[0] = 0x40 | length >> 4; } // fill to end with pad pattern. index = length + 3 - (this._version < 10); while (index < maxlength) { this._stringbuffer[index++] = 0xec; this._stringbuffer[index++] = 0x11; } } }, { key: '_getbadness', value: function _getbadness(length) { var badruns = 0; for (var i = 0; i <= length; i++) { if (this._badness[i] >= 5) { badruns += frame.n1 + this._badness[i] - 5; } } // fbfffbf as in finder. for (var _i5 = 3; _i5 < length - 1; _i5 += 2) { if (this._badness[_i5 - 2] === this._badness[_i5 + 2] && this._badness[_i5 + 2] === this._badness[_i5 - 1] && this._badness[_i5 - 1] === this._badness[_i5 + 1] && this._badness[_i5 - 1] * 3 === this._badness[_i5] && ( // background around the foreground pattern? not part of the specs. this._badness[_i5 - 3] === 0 || _i5 + 3 > length || this._badness[_i5 - 3] * 3 >= this._badness[_i5] * 4 || this._badness[_i5 + 3] * 3 >= this._badness[_i5] * 4)) { badruns += frame.n3; } } return badruns; } }, { key: '_finish', value: function _finish() { // save pre-mask copy of frame. this._stringbuffer = this.buffer.slice(0); var bit = 0; var i = void 0; var mask = 30000; /* * using for instead of while since in original arduino code if an early mask was "good enough" it wouldn't try for * a better one since they get more complex and take longer. */ for (i = 0; i < 8; i++) { // returns foreground-background imbalance. this._applymask(i); var currentmask = this._checkbadness(); // is current mask better than previous best? if (currentmask < mask) { mask = currentmask; bit = i; } // don't increment "i" to a void redoing mask. if (bit === 7) { break; } // reset for next pass. this.buffer = this._stringbuffer.slice(0); } // redo best mask as none were "good enough" (i.e. last wasn't bit). if (bit !== i) { this._applymask(bit); } // add in final mask/ecc level bytes. mask = errorcorrection.final_format[bit + (this._level - 1 << 3)]; // low byte. for (i = 0; i < 8; i++, mask >>= 1) { if (mask & 1) { this.buffer[this.width - 1 - i + this.width * 8] = 1; if (i < 6) { this.buffer[8 + this.width * i] = 1; } else { this.buffer[8 + this.width * (i + 1)] = 1; } } } // high byte. for (i = 0; i < 7; i++, mask >>= 1) { if (mask & 1) { this.buffer[8 + this.width * (this.width - 7 + i)] = 1; if (i) { this.buffer[6 - i + this.width * 8] = 1; } else { this.buffer[7 + this.width * 8] = 1; } } } } }, { key: '_interleaveblocks', value: function _interleaveblocks() { var maxlength = this._calculatemaxlength(); var i = void 0; var k = 0; for (i = 0; i < this._datablock; i++) { for (var j = 0; j < this._neccblock1; j++) { this._ecc[k++] = this._stringbuffer[i + j * this._datablock]; } for (var _j2 = 0; _j2 < this._neccblock2; _j2++) { this._ecc[k++] = this._stringbuffer[this._neccblock1 * this._datablock + i + _j2 * (this._datablock + 1)]; } } for (var _j3 = 0; _j3 < this._neccblock2; _j3++) { this._ecc[k++] = this._stringbuffer[this._neccblock1 * this._datablock + i + _j3 * (this._datablock + 1)]; } for (i = 0; i < this._eccblock; i++) { for (var _j4 = 0; _j4 < this._neccblock1 + this._neccblock2; _j4++) { this._ecc[k++] = this._stringbuffer[maxlength + i + _j4 * this._eccblock]; } } this._stringbuffer = this._ecc; } }, { key: '_insertalignments', value: function _insertalignments() { var width = this.width; if (this._version > 1) { var i = alignment.block[this._version]; var y = width - 7; for (;;) { var x = width - 7; while (x > i - 3) { this._addalignment(x, y); if (x < i) { break; } x -= i; } if (y <= i + 9) { break; } y -= i; this._addalignment(6, y); this._addalignment(y, 6); } } } }, { key: '_insertfinders', value: function _insertfinders() { var width = this.width; for (var i = 0; i < 3; i++) { var j = 0; var y = 0; if (i === 1) { j = width - 7; } if (i === 2) { y = width - 7; } this.buffer[y + 3 + width * (j + 3)] = 1; for (var x = 0; x < 6; x++) { this.buffer[y + x + width * j] = 1; this.buffer[y + width * (j + x + 1)] = 1; this.buffer[y + 6 + width * (j + x)] = 1; this.buffer[y + x + 1 + width * (j + 6)] = 1; } for (var _x10 = 1; _x10 < 5; _x10++) { this._setmask(y + _x10, j + 1); this._setmask(y + 1, j + _x10 + 1); this._setmask(y + 5, j + _x10); this._setmask(y + _x10 + 1, j + 5); } for (var _x11 = 2; _x11 < 4; _x11++) { this.buffer[y + _x11 + width * (j + 2)] = 1; this.buffer[y + 2 + width * (j + _x11 + 1)] = 1; this.buffer[y + 4 + width * (j + _x11)] = 1; this.buffer[y + _x11 + 1 + width * (j + 4)] = 1; } } } }, { key: '_inserttiminggap', value: function _inserttiminggap() { var width = this.width; for (var y = 0; y < 7; y++) { this._setmask(7, y); this._setmask(width - 8, y); this._setmask(7, y + width - 7); } for (var x = 0; x < 8; x++) { this._setmask(x, 7); this._setmask(x + width - 8, 7); this._setmask(x, width - 8); } } }, { key: '_inserttimingrowandcolumn', value: function _inserttimingrowandcolumn() { var width = this.width; for (var x = 0; x < width - 14; x++) { if (x & 1) { this._setmask(8 + x, 6); this._setmask(6, 8 + x); } else { this.buffer[8 + x + width * 6] = 1; this.buffer[6 + width * (8 + x)] = 1; } } } }, { key: '_insertversion', value: function _insertversion() { var width = this.width; if (this._version > 6) { var i = version.block[this._version - 7]; var j = 17; for (var x = 0; x < 6; x++) { for (var y = 0; y < 3; y++, j--) { if (1 & (j > 11 ? this._version >> j - 12 : i >> j)) { this.buffer[5 - x + width * (2 - y + width - 11)] = 1; this.buffer[2 - y + width - 11 + width * (5 - x)] = 1; } else { this._setmask(5 - x, 2 - y + width - 11); this._setmask(2 - y + width - 11, 5 - x); } } } } } }, { key: '_ismasked', value: function _ismasked(x, y) { var bit = frame._getmaskbit(x, y); return this._mask[bit] === 1; } }, { key: '_pack', value: function _pack() { var x = this.width - 1; var y = this.width - 1; var k = 1; var v = 1; // interleaved data and ecc codes. var length = (this._datablock + this._eccblock) * (this._neccblock1 + this._neccblock2) + this._neccblock2; for (var i = 0; i < length; i++) { var bit = this._stringbuffer[i]; for (var j = 0; j < 8; j++, bit <<= 1) { if (0x80 & bit) { this.buffer[x + this.width * y] = 1; } // find next fill position. do { if (v) { x--; } else { x++; if (k) { if (y !== 0) { y--; } else { x -= 2; k = !k; if (x === 6) { x--; y = 9; } } } else if (y !== this.width - 1) { y++; } else { x -= 2; k = !k; if (x === 6) { x--; y -= 8; } } } v = !v; } while (this._ismasked(x, y)); } } } }, { key: '_reversemask', value: function _reversemask() { var width = this.width; for (var x = 0; x < 9; x++) { this._setmask(x, 8); } for (var _x12 = 0; _x12 < 8; _x12++) { this._setmask(_x12 + width - 8, 8); this._setmask(8, _x12); } for (var y = 0; y < 7; y++) { this._setmask(8, y + width - 7); } } }, { key: '_setmask', value: function _setmask(x, y) { var bit = frame._getmaskbit(x, y); this._mask[bit] = 1; } }, { key: '_syncmask', value: function _syncmask() { var width = this.width; for (var y = 0; y < width; y++) { for (var x = 0; x <= y; x++) { if (this.buffer[x + width * y]) { this._setmask(x, y); } } } } }]); return frame; }(); /** * an implementation of {@link renderer} for working with img elements. * * this depends on {@link canvasrenderer} being executed first as this implementation simply applies the data url from * the rendered canvas element as the src for the img element being rendered. * * @public * @extends renderer */ var imagerenderer = function (_renderer) { inherits(imagerenderer, _renderer); function imagerenderer() { classcallcheck(this, imagerenderer); return possibleconstructorreturn(this, object.getprototypeof(imagerenderer).apply(this, arguments)); } createclass(imagerenderer, [{ key: 'draw', /** * @override */ value: function draw() { var qrious = this.qrious; qrious.image.src = qrious.todataurl(); } /** * @override */ }, { key: 'reset', value: function reset() { var qrious = this.qrious; qrious.image.src = ''; } /** * @override */ }, { key: 'resize', value: function resize() { var qrious = this.qrious; var image = qrious.image; image.width = qrious.size; image.height = qrious.size; } }]); return imagerenderer; }(renderer); /** * a basic manager for {@link service} implementations that are mapped to simple names. * * @public */ var servicemanager = function () { /** * creates a new instance of {@link servicemanager}. * * @public */ function servicemanager() { classcallcheck(this, servicemanager); this._services = {}; } createclass(servicemanager, [{ key: "getservice", value: function getservice(name) { var service = this._services[name]; if (!service) { throw new error("service is not being managed with name: " + name); } return service; } /** * sets the {@link service} implementation to be managed for the specified name to the * service provided. * * @param {string} name - the name of the {@link service} to be managed with name * @param {service} service - the {@link service} implementation to be managed * @throws {error} if a {@link service} is already being managed with the same name. * @public */ }, { key: "setservice", value: function setservice(name, service) { if (this._services[name]) { throw new error("service is already managed with name: " + name); } if (service) { this._services[name] = service; } } }]); return servicemanager; }(); /** * enables configuration of a qr code generator which uses html5 canvas for rendering. * * @public */ var qrious = function () { createclass(qrious, null, [{ key: 'use', /** * configures the service provided to be used by all {@link qrious} instances. * * @param {service} service - the {@link service} to be configured * @throws {error} if a {@link service} has already been configured with the same name. * @public * @static */ value: function use(service) { qrious._servicemanager.setservice(service.getname(), service); } }, { key: '_parseoptions', value: function _parseoptions(options) { options = object.assign({}, qrious.defaults, options); options.level = utilities.touppercase(options.level); options.size = math.abs(options.size); return options; } /** * creates a new instance of {@link qrious} based on the options provided. * * @param {qrious~options} [options] - the options to be used * @public */ }, { key: 'defaults', /** * returns the default options for {@link qrious}. * * @return {qrious~options} the default options. * @public * @static */ get: function get() { return { background: 'white', foreground: 'black', level: 'l', mime: 'image/png', size: 100, value: '' }; } }, { key: 'version', get: function get() { return 'x.x.x'; } }]); function qrious(options) { classcallcheck(this, qrious); options = qrious._parseoptions(options); utilities.privatize(this, options); var element = this._element; var elementservice = qrious._servicemanager.getservice('element'); /** * the canvas being used to render the qr code for this {@link qrious}. * * @public * @type {*} */ this.canvas = element && elementservice.iscanvas(element) ? element : elementservice.createcanvas(); this.canvas.qrious = this; /** * the img to contain the rendered qr code for this {@link qrious}. * * @public * @type {*} */ this.image = element && elementservice.isimage(element) ? element : elementservice.createimage(); this.image.qrious = this; this._renderers = [new canvasrenderer(this), new imagerenderer(this)]; this.update(); } /** * returns the image data uri for the generated qr code using the mime provided. * * @param {string} [mime] - the mime type for the image * @return {string} the image data uri for the qr code. * @public */ createclass(qrious, [{ key: 'todataurl', value: function todataurl(mime) { return this.canvas.todataurl(mime || this.mime); } /** * updates this {@link qrious} by generating a new {@link frame} and re-rendering the qr code. * * @protected */ }, { key: 'update', value: function update() { var frame = new frame({ level: this.level, value: this.value }); this._renderers.foreach(function (renderer) { return renderer.render(frame); }); } /** * returns the background color for the qr code. * * @return {string} the background color. * @public */ }, { key: 'background', get: function get() { return this._background; } /** * sets the background color for the qr code to background. * * @param {string} [background="white"] - the background color to be set * @public */ , set: function set(background) { var changed = utilities.setter(this, '_background', background, qrious.defaults.background); if (changed) { this.update(); } } /** * returns the foreground color for the qr code. * * @return {string} the foreground color. * @public */ }, { key: 'foreground', get: function get() { return this._foreground; } /** * sets the foreground color for the qr code to foreground. * * @param {string} [foreground="black"] - the foreground color to be set * @public */ , set: function set(foreground) { var changed = utilities.setter(this, '_foreground', foreground, qrious.defaults.foreground); if (changed) { this.update(); } } /** * returns the error correction level for the qr code. * * @return {string} the ecc level. * @public */ }, { key: 'level', get: function get() { return this._level; } /** * sets the error correction level for the qr code to level. * * level will be transformed to upper case to aid mapping to known ecc level blocks. * * @param {string} [level="l"] - the ecc level to be set * @public */ , set: function set(level) { var changed = utilities.setter(this, '_level', level, qrious.defaults.level, utilities.touppercase); if (changed) { this.update(); } } /** * returns the mime type for the image rendered for the qr code. * * @return {string} the image mime type. * @public */ }, { key: 'mime', get: function get() { return this._mime; } /** * sets the mime type for the image rendered for the qr code to mime. * * @param {string} [mime="image/png"] - the image mime type to be set * @public */ , set: function set(mime) { var changed = utilities.setter(this, '_mime', mime, qrious.defaults.mime); if (changed) { this.update(); } } /** * returns the size of the qr code. * * @return {number} the size in pixels. * @public */ }, { key: 'size', get: function get() { return this._size; } /** * sets the size of the qr code to size. * * size will be transformed to ensure that it is always an absolute positive numbers (e.g. * -100 would become 100). * * @param {number} [size=100] - the size in pixels to be set * @public */ , set: function set(size) { var changed = utilities.setter(this, '_size', size, qrious.defaults.size, math.abs); if (changed) { this.update(); } } /** * returns the value of the qr code. * * @return {string} the value. * @public */ }, { key: 'value', get: function get() { return this._value; } /** * sets the value of the qr code to value. * * @param {string} [value=""] - the value to be set * @public */ , set: function set(value) { var changed = utilities.setter(this, '_value', value, qrious.defaults.value); if (changed) { this.update(); } } }]); return qrious; }(); qrious._servicemanager = new servicemanager(); qrious.use(new browserelementservice()); return qrious; })); //# sourcemappingurl=qrious.js.map