123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- var Utils = require('./utils')
- var ECCode = require('./error-correction-code')
- var ECLevel = require('./error-correction-level')
- var Mode = require('./mode')
- var VersionCheck = require('./version-check')
- var isArray = require('isarray')
- // Generator polynomial used to encode version information
- var G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0)
- var G18_BCH = Utils.getBCHDigit(G18)
- function getBestVersionForDataLength (mode, length, errorCorrectionLevel) {
- for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
- if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, mode)) {
- return currentVersion
- }
- }
- return undefined
- }
- function getReservedBitsCount (mode, version) {
- // Character count indicator + mode indicator bits
- return Mode.getCharCountIndicator(mode, version) + 4
- }
- function getTotalBitsFromDataArray (segments, version) {
- var totalBits = 0
- segments.forEach(function (data) {
- var reservedBits = getReservedBitsCount(data.mode, version)
- totalBits += reservedBits + data.getBitsLength()
- })
- return totalBits
- }
- function getBestVersionForMixedData (segments, errorCorrectionLevel) {
- for (var currentVersion = 1; currentVersion <= 40; currentVersion++) {
- var length = getTotalBitsFromDataArray(segments, currentVersion)
- if (length <= exports.getCapacity(currentVersion, errorCorrectionLevel, Mode.MIXED)) {
- return currentVersion
- }
- }
- return undefined
- }
- /**
- * Returns version number from a value.
- * If value is not a valid version, returns defaultValue
- *
- * @param {Number|String} value QR Code version
- * @param {Number} defaultValue Fallback value
- * @return {Number} QR Code version number
- */
- exports.from = function from (value, defaultValue) {
- if (VersionCheck.isValid(value)) {
- return parseInt(value, 10)
- }
- return defaultValue
- }
- /**
- * Returns how much data can be stored with the specified QR code version
- * and error correction level
- *
- * @param {Number} version QR Code version (1-40)
- * @param {Number} errorCorrectionLevel Error correction level
- * @param {Mode} mode Data mode
- * @return {Number} Quantity of storable data
- */
- exports.getCapacity = function getCapacity (version, errorCorrectionLevel, mode) {
- if (!VersionCheck.isValid(version)) {
- throw new Error('Invalid QR Code version')
- }
- // Use Byte mode as default
- if (typeof mode === 'undefined') mode = Mode.BYTE
- // 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 dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
- if (mode === Mode.MIXED) return dataTotalCodewordsBits
- var usableBits = dataTotalCodewordsBits - getReservedBitsCount(mode, version)
- // Return max number of storable codewords
- switch (mode) {
- case Mode.NUMERIC:
- return Math.floor((usableBits / 10) * 3)
- case Mode.ALPHANUMERIC:
- return Math.floor((usableBits / 11) * 2)
- case Mode.KANJI:
- return Math.floor(usableBits / 13)
- case Mode.BYTE:
- default:
- return Math.floor(usableBits / 8)
- }
- }
- /**
- * Returns the minimum version needed to contain the amount of data
- *
- * @param {Segment} data Segment of data
- * @param {Number} [errorCorrectionLevel=H] Error correction level
- * @param {Mode} mode Data mode
- * @return {Number} QR Code version
- */
- exports.getBestVersionForData = function getBestVersionForData (data, errorCorrectionLevel) {
- var seg
- var ecl = ECLevel.from(errorCorrectionLevel, ECLevel.M)
- if (isArray(data)) {
- if (data.length > 1) {
- return getBestVersionForMixedData(data, ecl)
- }
- if (data.length === 0) {
- return 1
- }
- seg = data[0]
- } else {
- seg = data
- }
- return getBestVersionForDataLength(seg.mode, seg.getLength(), ecl)
- }
- /**
- * Returns version information with relative error correction bits
- *
- * The version information is included in QR Code symbols of version 7 or larger.
- * It consists of an 18-bit sequence containing 6 data bits,
- * with 12 error correction bits calculated using the (18, 6) Golay code.
- *
- * @param {Number} version QR Code version
- * @return {Number} Encoded version info bits
- */
- exports.getEncodedBits = function getEncodedBits (version) {
- if (!VersionCheck.isValid(version) || version < 7) {
- throw new Error('Invalid QR Code version')
- }
- var d = version << 12
- while (Utils.getBCHDigit(d) - G18_BCH >= 0) {
- d ^= (G18 << (Utils.getBCHDigit(d) - G18_BCH))
- }
- return (version << 12) | d
- }
|