UNPKG

qrcode

Version:

QRCode / 2d Barcode api with both server side and client side support using canvas

1,767 lines (1,506 loc) 243 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.QRCode = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ /** * Alignment pattern are fixed reference pattern in defined positions * in a matrix symbology, which enables the decode software to re-synchronise * the coordinate mapping of the image modules in the event of moderate amounts * of distortion of the image. * * Alignment patterns are present only in QR Code symbols of version 2 or larger * and their number depends on the symbol version. */ var getSymbolSize = require('./utils').getSymbolSize /** * Calculate the row/column coordinates of the center module of each alignment pattern * for the specified QR Code version. * * The alignment patterns are positioned symmetrically on either side of the diagonal * running from the top left corner of the symbol to the bottom right corner. * * Since positions are simmetrical only half of the coordinates are returned. * Each item of the array will represent in turn the x and y coordinate. * @see {@link getPositions} * * @param {Number} version QR Code version * @return {Array} Array of coordinate */ exports.getRowColCoords = function getRowColCoords (version) { if (version === 1) return [] var posCount = Math.floor(version / 7) + 2 var size = getSymbolSize(version) var intervals = size === 145 ? 26 : Math.ceil((size - 13) / (2 * posCount - 2)) * 2 var positions = [size - 7] // Last coord is always (size - 7) for (var i = 1; i < posCount - 1; i++) { positions[i] = positions[i - 1] - intervals } positions.push(6) // First coord is always 6 return positions.reverse() } /** * Returns an array containing the positions of each alignment pattern. * Each array's element represent the center point of the pattern as (x, y) coordinates * * Coordinates are calculated expanding the row/column coordinates returned by {@link getRowColCoords} * and filtering out the items that overlaps with finder pattern * * @example * For a Version 7 symbol {@link getRowColCoords} returns values 6, 22 and 38. * The alignment patterns, therefore, are to be centered on (row, column) * positions (6,22), (22,6), (22,22), (22,38), (38,22), (38,38). * Note that the coordinates (6,6), (6,38), (38,6) are occupied by finder patterns * and are not therefore used for alignment patterns. * * var pos = getPositions(7) * // [[6,22], [22,6], [22,22], [22,38], [38,22], [38,38]] * * @param {Number} version QR Code version * @return {Array} Array of coordinates */ exports.getPositions = function getPositions (version) { var coords = [] var pos = exports.getRowColCoords(version) var posLength = pos.length for (var i = 0; i < posLength; i++) { for (var j = 0; j < posLength; j++) { // Skip if position is occupied by finder patterns if ((i === 0 && j === 0) || // top-left (i === 0 && j === posLength - 1) || // bottom-left (i === posLength - 1 && j === 0)) { // top-right continue } coords.push([pos[i], pos[j]]) } } return coords } },{"./utils":20}],2:[function(require,module,exports){ var Mode = require('./mode') /** * Array of characters available in alphanumeric mode * * As per QR Code specification, to each character * is assigned a value from 0 to 44 which in this case coincides * with the array index * * @type {Array} */ var ALPHA_NUM_CHARS = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':' ] function AlphanumericData (data) { this.mode = Mode.ALPHANUMERIC this.data = data } AlphanumericData.getBitsLength = function getBitsLength (length) { return 11 * Math.floor(length / 2) + 6 * (length % 2) } AlphanumericData.prototype.getLength = function getLength () { return this.data.length } AlphanumericData.prototype.getBitsLength = function getBitsLength () { return AlphanumericData.getBitsLength(this.data.length) } AlphanumericData.prototype.write = function write (bitBuffer) { var i // Input data characters are divided into groups of two characters // and encoded as 11-bit binary codes. for (i = 0; i + 2 <= this.data.length; i += 2) { // The character value of the first character is multiplied by 45 var value = ALPHA_NUM_CHARS.indexOf(this.data[i]) * 45 // The character value of the second digit is added to the product value += ALPHA_NUM_CHARS.indexOf(this.data[i + 1]) // The sum is then stored as 11-bit binary number bitBuffer.put(value, 11) } // If the number of input data characters is not a multiple of two, // the character value of the final character is encoded as a 6-bit binary number. if (this.data.length % 2) { bitBuffer.put(ALPHA_NUM_CHARS.indexOf(this.data[i]), 6) } } module.exports = AlphanumericData },{"./mode":13}],3:[function(require,module,exports){ function BitBuffer () { this.buffer = [] this.length = 0 } BitBuffer.prototype = { get: function (index) { var bufIndex = Math.floor(index / 8) return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1) === 1 }, put: function (num, length) { for (var i = 0; i < length; i++) { this.putBit(((num >>> (length - i - 1)) & 1) === 1) } }, getLengthInBits: function () { return this.length }, putBit: function (bit) { var bufIndex = Math.floor(this.length / 8) if (this.buffer.length <= bufIndex) { this.buffer.push(0) } if (bit) { this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)) } this.length++ } } module.exports = BitBuffer },{}],4:[function(require,module,exports){ var Buffer = require('../utils/buffer') /** * Helper class to handle QR Code symbol modules * * @param {Number} size Symbol size */ function BitMatrix (size) { if (!size || size < 1) { throw new Error('BitMatrix size must be defined and greater than 0') } this.size = size this.data = new Buffer(size * size) this.data.fill(0) this.reservedBit = new Buffer(size * size) this.reservedBit.fill(0) } /** * Set bit value at specified location * If reserved flag is set, this bit will be ignored during masking process * * @param {Number} row * @param {Number} col * @param {Boolean} value * @param {Boolean} reserved */ BitMatrix.prototype.set = function (row, col, value, reserved) { var index = row * this.size + col this.data[index] = value if (reserved) this.reservedBit[index] = true } /** * Returns bit value at specified location * * @param {Number} row * @param {Number} col * @return {Boolean} */ BitMatrix.prototype.get = function (row, col) { return this.data[row * this.size + col] } /** * Applies xor operator at specified location * (used during masking process) * * @param {Number} row * @param {Number} col * @param {Boolean} value */ BitMatrix.prototype.xor = function (row, col, value) { this.data[row * this.size + col] ^= value } /** * Check if bit at specified location is reserved * * @param {Number} row * @param {Number} col * @return {Boolean} */ BitMatrix.prototype.isReserved = function (row, col) { return this.reservedBit[row * this.size + col] } module.exports = BitMatrix },{"../utils/buffer":26}],5:[function(require,module,exports){ var Buffer = require('../utils/buffer') var Mode = require('./mode') function ByteData (data) { this.mode = Mode.BYTE this.data = new Buffer(data) } ByteData.getBitsLength = function getBitsLength (length) { return length * 8 } ByteData.prototype.getLength = function getLength () { return this.data.length } ByteData.prototype.getBitsLength = function getBitsLength () { return ByteData.getBitsLength(this.data.length) } ByteData.prototype.write = function (bitBuffer) { for (var i = 0, l = this.data.length; i < l; i++) { bitBuffer.put(this.data[i], 8) } } module.exports = ByteData },{"../utils/buffer":26,"./mode":13}],6:[function(require,module,exports){ var ECLevel = require('./error-correction-level') var EC_BLOCKS_TABLE = [ // L M Q H 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 4, 1, 2, 4, 4, 2, 4, 4, 4, 2, 4, 6, 5, 2, 4, 6, 6, 2, 5, 8, 8, 4, 5, 8, 8, 4, 5, 8, 11, 4, 8, 10, 11, 4, 9, 12, 16, 4, 9, 16, 16, 6, 10, 12, 18, 6, 10, 17, 16, 6, 11, 16, 19, 6, 13, 18, 21, 7, 14, 21, 25, 8, 16, 20, 25, 8, 17, 23, 25, 9, 17, 23, 34, 9, 18, 25, 30, 10, 20, 27, 32, 12, 21, 29, 35, 12, 23, 34, 37, 12, 25, 34, 40, 13, 26, 35, 42, 14, 28, 38, 45, 15, 29, 40, 48, 16, 31, 43, 51, 17, 33, 45, 54, 18, 35, 48, 57, 19, 37, 51, 60, 19, 38, 53, 63, 20, 40, 56, 66, 21, 43, 59, 70, 22, 45, 62, 74, 24, 47, 65, 77, 25, 49, 68, 81 ] var EC_CODEWORDS_TABLE = [ // L M Q H 7, 10, 13, 17, 10, 16, 22, 28, 15, 26, 36, 44, 20, 36, 52, 64, 26, 48, 72, 88, 36, 64, 96, 112, 40, 72, 108, 130, 48, 88, 132, 156, 60, 110, 160, 192, 72, 130, 192, 224, 80, 150, 224, 264, 96, 176, 260, 308, 104, 198, 288, 352, 120, 216, 320, 384, 132, 240, 360, 432, 144, 280, 408, 480, 168, 308, 448, 532, 180, 338, 504, 588, 196, 364, 546, 650, 224, 416, 600, 700, 224, 442, 644, 750, 252, 476, 690, 816, 270, 504, 750, 900, 300, 560, 810, 960, 312, 588, 870, 1050, 336, 644, 952, 1110, 360, 700, 1020, 1200, 390, 728, 1050, 1260, 420, 784, 1140, 1350, 450, 812, 1200, 1440, 480, 868, 1290, 1530, 510, 924, 1350, 1620, 540, 980, 1440, 1710, 570, 1036, 1530, 1800, 570, 1064, 1590, 1890, 600, 1120, 1680, 1980, 630, 1204, 1770, 2100, 660, 1260, 1860, 2220, 720, 1316, 1950, 2310, 750, 1372, 2040, 2430 ] /** * Returns the number of error correction block that the QR Code should contain * for the specified version and error correction level. * * @param {Number} version QR Code version * @param {Number} errorCorrectionLevel Error correction level * @return {Number} Number of error correction blocks */ exports.getBlocksCount = function getBlocksCount (version, errorCorrectionLevel) { switch (errorCorrectionLevel) { case ECLevel.L: return EC_BLOCKS_TABLE[(version - 1) * 4 + 0] case ECLevel.M: return EC_BLOCKS_TABLE[(version - 1) * 4 + 1] case ECLevel.Q: return EC_BLOCKS_TABLE[(version - 1) * 4 + 2] case ECLevel.H: return EC_BLOCKS_TABLE[(version - 1) * 4 + 3] default: return undefined } } /** * Returns the number of error correction codewords to use for the specified * version and error correction level. * * @param {Number} version QR Code version * @param {Number} errorCorrectionLevel Error correction level * @return {Number} Number of error correction codewords */ exports.getTotalCodewordsCount = function getTotalCodewordsCount (version, errorCorrectionLevel) { switch (errorCorrectionLevel) { case ECLevel.L: return EC_CODEWORDS_TABLE[(version - 1) * 4 + 0] case ECLevel.M: return EC_CODEWORDS_TABLE[(version - 1) * 4 + 1] case ECLevel.Q: return EC_CODEWORDS_TABLE[(version - 1) * 4 + 2] case ECLevel.H: return EC_CODEWORDS_TABLE[(version - 1) * 4 + 3] default: return undefined } } },{"./error-correction-level":7}],7:[function(require,module,exports){ exports.L = { bit: 1 } exports.M = { bit: 0 } exports.Q = { bit: 3 } exports.H = { bit: 2 } function fromString (string) { if (typeof string !== 'string') { throw new Error('Param is not a string') } var lcStr = string.toLowerCase() switch (lcStr) { case 'l': case 'low': return exports.L case 'm': case 'medium': return exports.M case 'q': case 'quartile': return exports.Q case 'h': case 'high': return exports.H default: throw new Error('Unknown EC Level: ' + string) } } exports.isValid = function isValid (level) { return level && typeof level.bit !== 'undefined' && level.bit >= 0 && level.bit < 4 } exports.from = function from (value, defaultValue) { if (exports.isValid(value)) { return value } try { return fromString(value) } catch (e) { return defaultValue } } },{}],8:[function(require,module,exports){ var getSymbolSize = require('./utils').getSymbolSize var FINDER_PATTERN_SIZE = 7 /** * Returns an array containing the positions of each finder pattern. * Each array's element represent the top-left point of the pattern as (x, y) coordinates * * @param {Number} version QR Code version * @return {Array} Array of coordinates */ exports.getPositions = function getPositions (version) { var size = getSymbolSize(version) return [ // top-left [0, 0], // top-right [size - FINDER_PATTERN_SIZE, 0], // bottom-left [0, size - FINDER_PATTERN_SIZE] ] } },{"./utils":20}],9:[function(require,module,exports){ var Utils = require('./utils') var G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0) var G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1) var G15_BCH = Utils.getBCHDigit(G15) /** * Returns format information with relative error correction bits * * The format information is a 15-bit sequence containing 5 data bits, * with 10 error correction bits calculated using the (15, 5) BCH code. * * @param {Number} errorCorrectionLevel Error correction level * @param {Number} mask Mask pattern * @return {Number} Encoded format information bits */ exports.getEncodedBits = function getEncodedBits (errorCorrectionLevel, mask) { var data = ((errorCorrectionLevel.bit << 3) | mask) var d = data << 10 while (Utils.getBCHDigit(d) - G15_BCH >= 0) { d ^= (G15 << (Utils.getBCHDigit(d) - G15_BCH)) } // xor final data with mask pattern in order to ensure that // no combination of Error Correction Level and data mask pattern // will result in an all-zero data string return ((data << 10) | d) ^ G15_MASK } },{"./utils":20}],10:[function(require,module,exports){ var Buffer = require('../utils/buffer') var EXP_TABLE = new Buffer(512) var LOG_TABLE = new Buffer(256) /** * Precompute the log and anti-log tables for faster computation later * * For each possible value in the galois field 2^8, we will pre-compute * the logarithm and anti-logarithm (exponential) of this value * * ref {@link https://en.wikiversity.org/wiki/Reed%E2%80%93Solomon_codes_for_coders#Introduction_to_mathematical_fields} */ ;(function initTables () { var x = 1 for (var i = 0; i < 255; i++) { EXP_TABLE[i] = x LOG_TABLE[x] = i x <<= 1 // multiply by 2 // The QR code specification says to use byte-wise modulo 100011101 arithmetic. // This means that when a number is 256 or larger, it should be XORed with 0x11D. if (x & 0x100) { // similar to x >= 256, but a lot faster (because 0x100 == 256) x ^= 0x11D } } // Optimization: double the size of the anti-log table so that we don't need to mod 255 to // stay inside the bounds (because we will mainly use this table for the multiplication of // two GF numbers, no more). // @see {@link mul} for (i = 255; i < 512; i++) { EXP_TABLE[i] = EXP_TABLE[i - 255] } }()) /** * Returns log value of n inside Galois Field * * @param {Number} n * @return {Number} */ exports.log = function log (n) { if (n < 1) throw new Error('log(' + n + ')') return LOG_TABLE[n] } /** * Returns anti-log value of n inside Galois Field * * @param {Number} n * @return {Number} */ exports.exp = function exp (n) { return EXP_TABLE[n] } /** * Multiplies two number inside Galois Field * * @param {Number} x * @param {Number} y * @return {Number} */ exports.mul = function mul (x, y) { if (x === 0 || y === 0) return 0 // should be EXP_TABLE[(LOG_TABLE[x] + LOG_TABLE[y]) % 255] if EXP_TABLE wasn't oversized // @see {@link initTables} return EXP_TABLE[LOG_TABLE[x] + LOG_TABLE[y]] } },{"../utils/buffer":26}],11:[function(require,module,exports){ var Mode = require('./mode') var Utils = require('./utils') function KanjiData (data) { this.mode = Mode.KANJI this.data = data } KanjiData.getBitsLength = function getBitsLength (length) { return length * 13 } KanjiData.prototype.getLength = function getLength () { return this.data.length } KanjiData.prototype.getBitsLength = function getBitsLength () { return KanjiData.getBitsLength(this.data.length) } KanjiData.prototype.write = function (bitBuffer) { var i // In the Shift JIS system, Kanji characters are represented by a two byte combination. // These byte values are shifted from the JIS X 0208 values. // JIS X 0208 gives details of the shift coded representation. for (i = 0; i < this.data.length; i++) { var value = Utils.toSJIS(this.data[i]) // For characters with Shift JIS values from 0x8140 to 0x9FFC: if (value >= 0x8140 && value <= 0x9FFC) { // Subtract 0x8140 from Shift JIS value value -= 0x8140 // For characters with Shift JIS values from 0xE040 to 0xEBBF } else if (value >= 0xE040 && value <= 0xEBBF) { // Subtract 0xC140 from Shift JIS value value -= 0xC140 } else { throw new Error( 'Invalid SJIS character: ' + this.data[i] + '\n' + 'Make sure your charset is UTF-8') } // Multiply most significant byte of result by 0xC0 // and add least significant byte to product value = (((value >>> 8) & 0xff) * 0xC0) + (value & 0xff) // Convert result to a 13-bit binary string bitBuffer.put(value, 13) } } module.exports = KanjiData },{"./mode":13,"./utils":20}],12:[function(require,module,exports){ /** * Data mask pattern reference * @type {Object} */ exports.Patterns = { PATTERN000: 0, PATTERN001: 1, PATTERN010: 2, PATTERN011: 3, PATTERN100: 4, PATTERN101: 5, PATTERN110: 6, PATTERN111: 7 } /** * Weighted penalty scores for the undesirable features * @type {Object} */ var PenaltyScores = { N1: 3, N2: 3, N3: 40, N4: 10 } /** * Check if mask pattern value is valid * * @param {Number} mask Mask pattern * @return {Boolean} true if valid, false otherwise */ exports.isValid = function isValid (mask) { return mask && mask !== '' && !isNaN(mask) && mask >= 0 && mask <= 7 } /** * Returns mask pattern from a value. * If value is not valid, returns undefined * * @param {Number|String} value Mask pattern value * @return {Number} Valid mask pattern or undefined */ exports.from = function from (value) { return exports.isValid(value) ? parseInt(value, 10) : undefined } /** * Find adjacent modules in row/column with the same color * and assign a penalty value. * * Points: N1 + i * i is the amount by which the number of adjacent modules of the same color exceeds 5 */ exports.getPenaltyN1 = function getPenaltyN1 (data) { var size = data.size var points = 0 var sameCountCol = 0 var sameCountRow = 0 var lastCol = null var lastRow = null for (var row = 0; row < size; row++) { sameCountCol = sameCountRow = 0 lastCol = lastRow = null for (var col = 0; col < size; col++) { var module = data.get(row, col) if (module === lastCol) { sameCountCol++ } else { if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5) lastCol = module sameCountCol = 1 } module = data.get(col, row) if (module === lastRow) { sameCountRow++ } else { if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5) lastRow = module sameCountRow = 1 } } if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5) if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5) } return points } /** * Find 2x2 blocks with the same color and assign a penalty value * * Points: N2 * (m - 1) * (n - 1) */ exports.getPenaltyN2 = function getPenaltyN2 (data) { var size = data.size var points = 0 for (var row = 0; row < size - 1; row++) { for (var col = 0; col < size - 1; col++) { var last = data.get(row, col) + data.get(row, col + 1) + data.get(row + 1, col) + data.get(row + 1, col + 1) if (last === 4 || last === 0) points++ } } return points * PenaltyScores.N2 } /** * Find 1:1:3:1:1 ratio (dark:light:dark:light:dark) pattern in row/column, * preceded or followed by light area 4 modules wide * * Points: N3 * number of pattern found */ exports.getPenaltyN3 = function getPenaltyN3 (data) { var size = data.size var points = 0 var bitsCol = 0 var bitsRow = 0 for (var row = 0; row < size; row++) { bitsCol = bitsRow = 0 for (var col = 0; col < size; col++) { bitsCol = ((bitsCol << 1) & 0x7FF) | data.get(row, col) if (col >= 10 && (bitsCol === 0x5D0 || bitsCol === 0x05D)) points++ bitsRow = ((bitsRow << 1) & 0x7FF) | data.get(col, row) if (col >= 10 && (bitsRow === 0x5D0 || bitsRow === 0x05D)) points++ } } return points * PenaltyScores.N3 } /** * Calculate proportion of dark modules in entire symbol * * Points: N4 * k * * k is the rating of the deviation of the proportion of dark modules * in the symbol from 50% in steps of 5% */ exports.getPenaltyN4 = function getPenaltyN4 (data) { var darkCount = 0 var modulesCount = data.data.length for (var i = 0; i < modulesCount; i++) darkCount += data.data[i] var k = Math.abs(Math.ceil((darkCount * 100 / modulesCount) / 5) - 10) return k * PenaltyScores.N4 } /** * Return mask value at given position * * @param {Number} maskPattern Pattern reference value * @param {Number} i Row * @param {Number} j Column * @return {Boolean} Mask value */ function getMaskAt (maskPattern, i, j) { switch (maskPattern) { case exports.Patterns.PATTERN000: return (i + j) % 2 === 0 case exports.Patterns.PATTERN001: return i % 2 === 0 case exports.Patterns.PATTERN010: return j % 3 === 0 case exports.Patterns.PATTERN011: return (i + j) % 3 === 0 case exports.Patterns.PATTERN100: return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0 case exports.Patterns.PATTERN101: return (i * j) % 2 + (i * j) % 3 === 0 case exports.Patterns.PATTERN110: return ((i * j) % 2 + (i * j) % 3) % 2 === 0 case exports.Patterns.PATTERN111: return ((i * j) % 3 + (i + j) % 2) % 2 === 0 default: throw new Error('bad maskPattern:' + maskPattern) } } /** * Apply a mask pattern to a BitMatrix * * @param {Number} pattern Pattern reference number * @param {BitMatrix} data BitMatrix data */ exports.applyMask = function applyMask (pattern, data) { var size = data.size for (var col = 0; col < size; col++) { for (var row = 0; row < size; row++) { if (data.isReserved(row, col)) continue data.xor(row, col, getMaskAt(pattern, row, col)) } } } /** * Returns the best mask pattern for data * * @param {BitMatrix} data * @return {Number} Mask pattern reference number */ exports.getBestMask = function getBestMask (data, setupFormatFunc) { var numPatterns = Object.keys(exports.Patterns).length var bestPattern = 0 var lowerPenalty = Infinity for (var p = 0; p < numPatterns; p++) { setupFormatFunc(p) exports.applyMask(p, data) // Calculate penalty var penalty = exports.getPenaltyN1(data) + exports.getPenaltyN2(data) + exports.getPenaltyN3(data) + exports.getPenaltyN4(data) // Undo previously applied mask exports.applyMask(p, data) if (penalty < lowerPenalty) { lowerPenalty = penalty bestPattern = p } } return bestPattern } },{}],13:[function(require,module,exports){ var Version = require('./version') var Regex = require('./regex') /** * Numeric mode encodes data from the decimal digit set (0 - 9) * (byte values 30HEX to 39HEX). * Normally, 3 data characters are represented by 10 bits. * * @type {Object} */ exports.NUMERIC = { id: 'Numeric', bit: 1 << 0, ccBits: [10, 12, 14] } /** * Alphanumeric mode encodes data from a set of 45 characters, * i.e. 10 numeric digits (0 - 9), * 26 alphabetic characters (A - Z), * and 9 symbols (SP, $, %, *, +, -, ., /, :). * Normally, two input characters are represented by 11 bits. * * @type {Object} */ exports.ALPHANUMERIC = { id: 'Alphanumeric', bit: 1 << 1, ccBits: [9, 11, 13] } /** * In byte mode, data is encoded at 8 bits per character. * * @type {Object} */ exports.BYTE = { id: 'Byte', bit: 1 << 2, ccBits: [8, 16, 16] } /** * The Kanji mode efficiently encodes Kanji characters in accordance with * the Shift JIS system based on JIS X 0208. * The Shift JIS values are shifted from the JIS X 0208 values. * JIS X 0208 gives details of the shift coded representation. * Each two-byte character value is compacted to a 13-bit binary codeword. * * @type {Object} */ exports.KANJI = { id: 'Kanji', bit: 1 << 3, ccBits: [8, 10, 12] } /** * Mixed mode will contain a sequences of data in a combination of any of * the modes described above * * @type {Object} */ exports.MIXED = { bit: -1 } /** * Returns the number of bits needed to store the data length * according to QR Code specifications. * * @param {Mode} mode Data mode * @param {Number} version QR Code version * @return {Number} Number of bits */ exports.getCharCountIndicator = function getCharCountIndicator (mode, version) { if (!mode.ccBits) throw new Error('Invalid mode: ' + mode) if (!Version.isValid(version)) { throw new Error('Invalid version: ' + version) } if (version >= 1 && version < 10) return mode.ccBits[0] else if (version < 27) return mode.ccBits[1] return mode.ccBits[2] } /** * Returns the most efficient mode to store the specified data * * @param {String} dataStr Input data string * @return {Mode} Best mode */ exports.getBestModeForData = function getBestModeForData (dataStr) { if (Regex.testNumeric(dataStr)) return exports.NUMERIC else if (Regex.testAlphanumeric(dataStr)) return exports.ALPHANUMERIC else if (Regex.testKanji(dataStr)) return exports.KANJI else return exports.BYTE } /** * Return mode name as string * * @param {Mode} mode Mode object * @returns {String} Mode name */ exports.toString = function toString (mode) { if (mode && mode.id) return mode.id throw new Error('Invalid mode') } /** * Check if input param is a valid mode object * * @param {Mode} mode Mode object * @returns {Boolean} True if valid mode, false otherwise */ exports.isValid = function isValid (mode) { return mode && mode.bit && mode.ccBits } /** * Get mode object from its name * * @param {String} string Mode name * @returns {Mode} Mode object */ function fromString (string) { if (typeof string !== 'string') { throw new Error('Param is not a string') } var lcStr = string.toLowerCase() switch (lcStr) { case 'numeric': return exports.NUMERIC case 'alphanumeric': return exports.ALPHANUMERIC case 'kanji': return exports.KANJI case 'byte': return exports.BYTE default: throw new Error('Unknown mode: ' + string) } } /** * Returns mode from a value. * If value is not a valid mode, returns defaultValue * * @param {Mode|String} value Encoding mode * @param {Mode} defaultValue Fallback value * @return {Mode} Encoding mode */ exports.from = function from (value, defaultValue) { if (exports.isValid(value)) { return value } try { return fromString(value) } catch (e) { return defaultValue } } },{"./regex":18,"./version":21}],14:[function(require,module,exports){ var Mode = require('./mode') function NumericData (data) { this.mode = Mode.NUMERIC this.data = data.toString() } NumericData.getBitsLength = function getBitsLength (length) { return 10 * Math.floor(length / 3) + ((length % 3) ? ((length % 3) * 3 + 1) : 0) } NumericData.prototype.getLength = function getLength () { return this.data.length } NumericData.prototype.getBitsLength = function getBitsLength () { return NumericData.getBitsLength(this.data.length) } NumericData.prototype.write = function write (bitBuffer) { var i, group, value // The input data string is divided into groups of three digits, // and each group is converted to its 10-bit binary equivalent. for (i = 0; i + 3 <= this.data.length; i += 3) { group = this.data.substr(i, 3) value = parseInt(group, 10) bitBuffer.put(value, 10) } // If the number of input digits is not an exact multiple of three, // the final one or two digits are converted to 4 or 7 bits respectively. var remainingNum = this.data.length - i if (remainingNum > 0) { group = this.data.substr(i) value = parseInt(group, 10) bitBuffer.put(value, remainingNum * 3 + 1) } } module.exports = NumericData },{"./mode":13}],15:[function(require,module,exports){ var Buffer = require('../utils/buffer') var GF = require('./galois-field') /** * Multiplies two polynomials inside Galois Field * * @param {Buffer} p1 Polynomial * @param {Buffer} p2 Polynomial * @return {Buffer} Product of p1 and p2 */ exports.mul = function mul (p1, p2) { var coeff = new Buffer(p1.length + p2.length - 1) coeff.fill(0) for (var i = 0; i < p1.length; i++) { for (var j = 0; j < p2.length; j++) { coeff[i + j] ^= GF.mul(p1[i], p2[j]) } } return coeff } /** * Calculate the remainder of polynomials division * * @param {Buffer} divident Polynomial * @param {Buffer} divisor Polynomial * @return {Buffer} Remainder */ exports.mod = function mod (divident, divisor) { var result = new Buffer(divident) while ((result.length - divisor.length) >= 0) { var coeff = result[0] for (var i = 0; i < divisor.length; i++) { result[i] ^= GF.mul(divisor[i], coeff) } // remove all zeros from buffer head var offset = 0 while (offset < result.length && result[offset] === 0) offset++ result = result.slice(offset) } return result } /** * Generate an irreducible generator polynomial of specified degree * (used by Reed-Solomon encoder) * * @param {Number} degree Degree of the generator polynomial * @return {Buffer} Buffer containing polynomial coefficients */ exports.generateECPolynomial = function generateECPolynomial (degree) { var poly = new Buffer([1]) for (var i = 0; i < degree; i++) { poly = exports.mul(poly, [1, GF.exp(i)]) } return poly } },{"../utils/buffer":26,"./galois-field":10}],16:[function(require,module,exports){ var Buffer = require('../utils/buffer') var Utils = require('./utils') var ECLevel = require('./error-correction-level') var BitBuffer = require('./bit-buffer') var BitMatrix = require('./bit-matrix') var AlignmentPattern = require('./alignment-pattern') var FinderPattern = require('./finder-pattern') var MaskPattern = require('./mask-pattern') var ECCode = require('./error-correction-code') var ReedSolomonEncoder = require('./reed-solomon-encoder') var Version = require('./version') var FormatInfo = require('./format-info') var Mode = require('./mode') var Segments = require('./segments') var isArray = require('isarray') /** * QRCode for JavaScript * * modified by Ryan Day for nodejs support * Copyright (c) 2011 Ryan Day * * Licensed under the MIT license: * http://www.opensource.org/licenses/mit-license.php * //--------------------------------------------------------------------- // QRCode for JavaScript // // Copyright (c) 2009 Kazuhiko Arase // // URL: http://www.d-project.com/ // // Licensed under the MIT license: // http://www.opensource.org/licenses/mit-license.php // // The word "QR Code" is registered trademark of // DENSO WAVE INCORPORATED // http://www.denso-wave.com/qrcode/faqpatent-e.html // //--------------------------------------------------------------------- */ /** * Add finder patterns bits to matrix * * @param {BitMatrix} matrix Modules matrix * @param {Number} version QR Code version */ function setupFinderPattern (matrix, version) { var size = matrix.size var pos = FinderPattern.getPositions(version) for (var i = 0; i < pos.length; i++) { var row = pos[i][0] var col = pos[i][1] for (var r = -1; r <= 7; r++) { if (row + r <= -1 || size <= row + r) continue for (var c = -1; c <= 7; c++) { if (col + c <= -1 || size <= col + c) continue if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) || (c >= 0 && c <= 6 && (r === 0 || r === 6)) || (r >= 2 && r <= 4 && c >= 2 && c <= 4)) { matrix.set(row + r, col + c, true, true) } else { matrix.set(row + r, col + c, false, true) } } } } } /** * Add timing pattern bits to matrix * * Note: this function must be called before {@link setupAlignmentPattern} * * @param {BitMatrix} matrix Modules matrix */ function setupTimingPattern (matrix) { var size = matrix.size for (var r = 8; r < size - 8; r++) { var value = r % 2 === 0 matrix.set(r, 6, value, true) matrix.set(6, r, value, true) } } /** * Add alignment patterns bits to matrix * * Note: this function must be called after {@link setupTimingPattern} * * @param {BitMatrix} matrix Modules matrix * @param {Number} version QR Code version */ function setupAlignmentPattern (matrix, version) { var pos = AlignmentPattern.getPositions(version) for (var i = 0; i < pos.length; i++) { var row = pos[i][0] var col = pos[i][1] for (var r = -2; r <= 2; r++) { for (var c = -2; c <= 2; c++) { if (r === -2 || r === 2 || c === -2 || c === 2 || (r === 0 && c === 0)) { matrix.set(row + r, col + c, true, true) } else { matrix.set(row + r, col + c, false, true) } } } } } /** * Add version info bits to matrix * * @param {BitMatrix} matrix Modules matrix * @param {Number} version QR Code version */ function setupVersionInfo (matrix, version) { var size = matrix.size var bits = Version.getEncodedBits(version) var row, col, mod for (var i = 0; i < 18; i++) { row = Math.floor(i / 3) col = i % 3 + size - 8 - 3 mod = ((bits >> i) & 1) === 1 matrix.set(row, col, mod, true) matrix.set(col, row, mod, true) } } /** * Add format info bits to matrix * * @param {BitMatrix} matrix Modules matrix * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level * @param {Number} maskPattern Mask pattern reference value */ function setupFormatInfo (matrix, errorCorrectionLevel, maskPattern) { var size = matrix.size var bits = FormatInfo.getEncodedBits(errorCorrectionLevel, maskPattern) var i, mod for (i = 0; i < 15; i++) { mod = ((bits >> i) & 1) === 1 // vertical if (i < 6) { matrix.set(i, 8, mod, true) } else if (i < 8) { matrix.set(i + 1, 8, mod, true) } else { matrix.set(size - 15 + i, 8, mod, true) } // horizontal if (i < 8) { matrix.set(8, size - i - 1, mod, true) } else if (i < 9) { matrix.set(8, 15 - i - 1 + 1, mod, true) } else { matrix.set(8, 15 - i - 1, mod, true) } } // fixed module matrix.set(size - 8, 8, 1, true) } /** * Add encoded data bits to matrix * * @param {BitMatrix} matrix Modules matrix * @param {Buffer} data Data codewords */ function setupData (matrix, data) { var size = matrix.size var inc = -1 var row = size - 1 var bitIndex = 7 var byteIndex = 0 for (var col = size - 1; col > 0; col -= 2) { if (col === 6) col-- while (true) { for (var c = 0; c < 2; c++) { if (!matrix.isReserved(row, col - c)) { var dark = false if (byteIndex < data.length) { dark = (((data[byteIndex] >>> bitIndex) & 1) === 1) } matrix.set(row, col - c, dark) bitIndex-- if (bitIndex === -1) { byteIndex++ bitIndex = 7 } } } row += inc if (row < 0 || size <= row) { row -= inc inc = -inc break } } } } /** * Create encoded codewords from data input * * @param {Number} version QR Code version * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level * @param {ByteData} data Data input * @return {Buffer} Buffer containing encoded codewords */ function createData (version, errorCorrectionLevel, segments) { // Prepare data buffer var buffer = new BitBuffer() segments.forEach(function (data) { // prefix data with mode indicator (4 bits) buffer.put(data.mode.bit, 4) // Prefix data with character count indicator. // The character count indicator is a string of bits that represents the // number of characters that are being encoded. // The character count indicator must be placed after the mode indicator // and must be a certain number of bits long, depending on the QR version // and data mode // @see {@link Mode.getCharCountIndicator}. buffer.put(data.getLength(), Mode.getCharCountIndicator(data.mode, version)) // add binary data sequence to buffer data.write(buffer) }) // Calculate required number of bits var totalCodewords = Utils.getSymbolTotalCodewords(version) var ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel) var dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8 // Add a terminator. // If the bit string is shorter than the total number of required bits, // a terminator of up to four 0s must be added to the right side of the string. // If the bit string is more than four bits shorter than the required number of bits, // add four 0s to the end. if (buffer.getLengthInBits() + 4 <= dataTotalCodewordsBits) { buffer.put(0, 4) } // If the bit string is fewer than four bits shorter, add only the number of 0s that // are needed to reach the required number of bits. // After adding the terminator, if the number of bits in the string is not a multiple of 8, // pad the string on the right with 0s to make the string's length a multiple of 8. while (buffer.getLengthInBits() % 8 !== 0) { buffer.putBit(0) } // Add pad bytes if the string is still shorter than the total number of required bits. // Extend the buffer to fill the data capacity of the symbol corresponding to // the Version and Error Correction Level by adding the Pad Codewords 11101100 (0xEC) // and 00010001 (0x11) alternately. var remainingByte = (dataTotalCodewordsBits - buffer.getLengthInBits()) / 8 for (var i = 0; i < remainingByte; i++) { buffer.put(i % 2 ? 0x11 : 0xEC, 8) } return createCodewords(buffer, version, errorCorrectionLevel) } /** * Encode input data with Reed-Solomon and return codewords with * relative error correction bits * * @param {BitBuffer} bitBuffer Data to encode * @param {Number} version QR Code version * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level * @return {Buffer} Buffer containing encoded codewords */ function createCodewords (bitBuffer, version, errorCorrectionLevel) { // Total codewords for this QR code version (Data + Error correction) var totalCodewords = Utils.getSymbolTotalCodewords(version) // Total number of error correction codewords var ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel) // Total number of data codewords var dataTotalCodewords = totalCodewords - ecTotalCodewords // Total number of blocks var ecTotalBlocks = ECCode.getBlocksCount(version, errorCorrectionLevel) // Calculate how many blocks each group should contain var blocksInGroup2 = totalCodewords % ecTotalBlocks var blocksInGroup1 = ecTotalBlocks - blocksInGroup2 var totalCodewordsInGroup1 = Math.floor(totalCodewords / ecTotalBlocks) var dataCodewordsInGroup1 = Math.floor(dataTotalCodewords / ecTotalBlocks) var dataCodewordsInGroup2 = dataCodewordsInGroup1 + 1 // Number of EC codewords is the same for both groups var ecCount = totalCodewordsInGroup1 - dataCodewordsInGroup1 // Initialize a Reed-Solomon encoder with a generator polynomial of degree ecCount var rs = new ReedSolomonEncoder(ecCount) var offset = 0 var dcData = new Array(ecTotalBlocks) var ecData = new Array(ecTotalBlocks) var maxDataSize = 0 var buffer = new Buffer(bitBuffer.buffer) // Divide the buffer into the required number of blocks for (var b = 0; b < ecTotalBlocks; b++) { var dataSize = b < blocksInGroup1 ? dataCodewordsInGroup1 : dataCodewordsInGroup2 // extract a block of data from buffer dcData[b] = buffer.slice(offset, offset + dataSize) // Calculate EC codewords for this data block ecData[b] = rs.encode(dcData[b]) offset += dataSize maxDataSize = Math.max(maxDataSize, dataSize) } // Create final data // Interleave the data and error correction codewords from each block var data = new Buffer(totalCodewords) var index = 0 var i, r // Add data codewords for (i = 0; i < maxDataSize; i++) { for (r = 0; r < ecTotalBlocks; r++) { if (i < dcData[r].length) { data[index++] = dcData[r][i] } } } // Apped EC codewords for (i = 0; i < ecCount; i++) { for (r = 0; r < ecTotalBlocks; r++) { data[index++] = ecData[r][i] } } return data } /** * Build QR Code symbol * * @param {String} data Input string * @param {Number} version QR Code version * @param {ErrorCorretionLevel} errorCorrectionLevel Error level * @param {MaskPattern} maskPattern Mask pattern * @return {Object} Object containing symbol data */ function createSymbol (data, version, errorCorrectionLevel, maskPattern) { var segments if (isArray(data)) { segments = Segments.fromArray(data) } else if (typeof data === 'string') { var estimatedVersion = version if (!estimatedVersion) { var rawSegments = Segments.rawSplit(data) // Estimate best version that can contain raw splitted segments estimatedVersion = Version.getBestVersionForData(rawSegments, errorCorrectionLevel) } // Build optimized segments // If estimated version is undefined, try with the highest version segments = Segments.fromString(data, estimatedVersion || 40) } else { throw new Error('Invalid data') } // Get the min version that can contain data var bestVersion = Version.getBestVersionForData(segments, errorCorrectionLevel) // If no version is found, data cannot be stored if (!bestVersion) { throw new Error('The amount of data is too big to be stored in a QR Code') } // If not specified, use min version as default if (!version) { version = bestVersion // Check if the specified version can contain the data } else if (version < bestVersion) { throw new Error('\n' + 'The chosen QR Code version cannot contain this amount of data.\n' + 'Minimum version required to store current data is: ' + bestVersion + '.\n' ) } var dataBits = createData(version, errorCorrectionLevel, segments) // Allocate matrix buffer var moduleCount = Utils.getSymbolSize(version) var modules = new BitMatrix(moduleCount) // Add function modules setupFinderPattern(modules, version) setupTimingPattern(modules) setupAlignmentPattern(modules, version) // Add temporary dummy bits for format info just to set them as reserved. // This is needed to prevent these bits from being masked by {@link MaskPattern.applyMask} // since the masking operation must be performed only on the encoding region. // These blocks will be replaced with correct values later in code. setupFormatInfo(modules, errorCorrectionLevel, 0) if (version >= 7) { setupVersionInfo(modules, version) } // Add data codewords setupData(modules, dataBits) if (!maskPattern) { // Find best mask pattern maskPattern = MaskPattern.getBestMask(modules, setupFormatInfo.bind(null, modules, errorCorrectionLevel)) } // Apply mask pattern MaskPattern.applyMask(maskPattern, modules) // Replace format info bits with correct values setupFormatInfo(modules, errorCorrectionLevel, maskPattern) return { modules: modules, version: version, errorCorrectionLevel: errorCorrectionLevel, maskPattern: maskPattern, segments: segments } } /** * QR Code * * @param {String | Array} data Input data * @param {Object} options Optional configurations * @param {Number} options.version QR Code version * @param {String} options.errorCorrectionLevel Error correction level * @param {Function} options.toSJISFunc Helper func to convert utf8 to sjis */ exports.create = function create (data, options) { if (typeof data === 'undefined' || data === '') { throw new Error('No input text') } var errorCorrectionLevel = ECLevel.M var version var mask if (typeof options !== 'undefined') { // Use higher error correction level as default errorCorrectionLevel = ECLevel.from(options.errorCorrectionLevel, ECLevel.M) version = Version.from(options.version) mask = MaskPattern.from(options.maskPattern) if (options.toSJISFunc) { Utils.setToSJISFunction(options.toSJISFunc) } } return createSymbol(data, version, errorCorrectionLevel, mask) } },{"../utils/buffer":26,"./alignment-pattern":1,"./bit-buffer":3,"./bit-matrix":4,"./error-correction-code":6,"./error-correction-level":7,"./finder-pattern":8,"./format-info":9,"./mask-pattern":12,"./mode":13,"./reed-solomon-encoder":17,"./segments":19,"./utils":20,"./version":21,"isarray":29}],17:[function(require,module,exports){ var Buffer = require('../utils/buffer') var Polynomial = require('./polynomial') function ReedSolomonEncoder (degree) { this.genPoly = undefined this.degree = degree if (this.degree) this.initialize(this.degree) } /** * Initialize the encoder. * The input param should correspond to the number of error correction codewords. * * @param {Number} degree */ ReedSolomonEncoder.prototype.initialize = function initialize (degree) { // create an irreducible generator polynomial this.degree = degree this.genPoly = Polynomial.generateECPolynomial(this.degree) } /** * Encodes a chunk of data * * @param {Buffer} data Buffer containing input data * @return {Buffer} Buffer containing encoded data */ ReedSolomonEncoder.prototype.encode = function encode (data) { if (!this.genPoly) { throw new Error('Encoder not initialized') } // Calculate EC for this data block // extends data size to data+genPoly size var pad = new Buffer(this.degree) pad.fill(0) var paddedData = Buffer.concat([data, pad], data.length + this.degree) // The error correction codewords are the remainder after dividing the data codewords // by a generator polynomial var remainder = Polynomial.mod(paddedData, this.genPoly) // return EC data blocks (last n byte, where n is the degree of genPoly) // If coefficients number in remainder are less than genPoly degree, // pad with 0s to the left to reach the needed number of coefficients var start = this.degree - remainder.length if (start > 0) { var buff = new Buffer(this.degree) buff.fill(0) remainder.copy(buff, start) return buff } return remainder } module.exports = ReedSolomonEncoder },{"../utils/buffer":26,"./polynomial":15}],18:[function(require,module,exports){ var numeric = '[0-9]+' var alphanumeric = '[A-Z $%*+\\-./:]+' var kanji = '(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|' + '[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|' + '[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|' + '[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+' kanji = kanji.replace(/u/g, '\\u') var byte = '(?:(?![A-Z0-9 $%*+\\-./:]|' + kanji + ').)+' exports.KANJI = new RegExp(kanji, 'g') exports.BYTE_KANJI = new RegExp('[^A-Z0-9 $%*+\\-./:]+', 'g') exports.BYTE = new RegExp(byte, 'g') exports.NUMERIC = new RegExp(numeric, 'g') exports.ALPHANUMERIC = new RegExp(alphanumeric, 'g') var TEST_KANJI = new RegExp('^' + kanji + '$') var TEST_NUMERIC = new RegExp('^' + numeric + '$') var TEST_ALPHANUMERIC = new RegExp('^[A-Z0-9 $%*+\\-./:]+$') exports.testKanji = function testKanji (str) { return TEST_KANJI.test(str) } exports.testNumeric = function testNumeric (str) { return TEST_NUMERIC.test(str) } exports.testAlp