1 var Utils = require('./utils')
2 var ECCode = require('./error-correction-code')
3 var ECLevel = require('./error-correction-level')
4 var Mode = require('./mode')
5 var VersionCheck = require('./version-check')
6 var isArray = require('isarray')
8 // Generator polynomial used to encode version information
9 var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)
10 var G18_BCH = Utils.getBCHDigit(G18)
12 function getBestVersionForDataLength (mode, length, errorCorrectionLevel) {
13 for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
14 if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, mode)) {
22 function getReservedBitsCount (mode, version) {
23 // Character count indicator + mode indicator bits
24 return Mode.getCharCountIndicator(mode, version) + 4
27 function getTotalBitsFromDataArray (segments, version) {
30 segments.forEach(function (data) {
31 var reservedBits = getReservedBitsCount(data.mode, version)
32 totalBits += reservedBits + data.getBitsLength()
38 function getBestVersionForMixedData (segments, errorCorrectionLevel) {
39 for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
40 var length = getTotalBitsFromDataArray(segments, currentVersion)
41 if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, Mode.MIXED)) {
50 * Returns version number from a value.
51 * If value is not a valid version, returns defaultValue
53 * @param {Number|String} value QR Code version
54 * @param {Number} defaultValue Fallback value
55 * @return {Number} QR Code version number
57 exports.from = function from (value, defaultValue) {
58 if (VersionCheck.isValid(value)) {
59 return parseInt(value, 10)
66 * Returns how much data can be stored with the specified QR code version
67 * and error correction level
69 * @param {Number} version QR Code version (1-40)
70 * @param {Number} errorCorrectionLevel Error correction level
71 * @param {Mode} mode Data mode
72 * @return {Number} Quantity of storable data
74 exports.getCapacity = function getCapacity (version, errorCorrectionLevel, mode) {
75 if (!VersionCheck.isValid(version)) {
76 throw new Error('Invalid QR Code version')
79 // Use Byte mode as default
80 if (typeof mode === 'undefined') mode = Mode.BYTE
82 // Total codewords for this QR code version (Data + Error correction)
83 var totalCodewords = Utils.getSymbolTotalCodewords(version)
85 // Total number of error correction codewords
86 var ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
88 // Total number of data codewords
89 var dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
91 if (mode === Mode.MIXED) return dataTotalCodewordsBits
93 var usableBits = dataTotalCodewordsBits - getReservedBitsCount(mode, version)
95 // Return max number of storable codewords
98 return Math.floor((usableBits / 10) * 3)
100 case Mode.ALPHANUMERIC:
101 return Math.floor((usableBits / 11) * 2)
104 return Math.floor(usableBits / 13)
108 return Math.floor(usableBits / 8)
113 * Returns the minimum version needed to contain the amount of data
115 * @param {Segment} data Segment of data
116 * @param {Number} [errorCorrectionLevel=H] Error correction level
117 * @param {Mode} mode Data mode
118 * @return {Number} QR Code version
120 exports.getBestVersionForData = function getBestVersionForData (data, errorCorrectionLevel) {
123 var ecl = ECLevel.from(errorCorrectionLevel, ECLevel.M)
126 if (data.length > 1) {
127 return getBestVersionForMixedData(data, ecl)
130 if (data.length === 0) {
139 return getBestVersionForDataLength(seg.mode, seg.getLength(), ecl)
143 * Returns version information with relative error correction bits
145 * The version information is included in QR Code symbols of version 7 or larger.
146 * It consists of an 18-bit sequence containing 6 data bits,
147 * with 12 error correction bits calculated using the (18, 6) Golay code.
149 * @param {Number} version QR Code version
150 * @return {Number} Encoded version info bits
152 exports.getEncodedBits = function getEncodedBits (version) {
153 if (!VersionCheck.isValid(version) || version < 7) {
154 throw new Error('Invalid QR Code version')
157 var d = version << 12
159 while (Utils.getBCHDigit(d) - G18_BCH >= 0) {
160 d ^= (G18 << (Utils.getBCHDigit(d) - G18_BCH))
163 return (version << 12) | d