qrcode.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. const Utils = require('./utils')
  2. const ECLevel = require('./error-correction-level')
  3. const BitBuffer = require('./bit-buffer')
  4. const BitMatrix = require('./bit-matrix')
  5. const AlignmentPattern = require('./alignment-pattern')
  6. const FinderPattern = require('./finder-pattern')
  7. const MaskPattern = require('./mask-pattern')
  8. const ECCode = require('./error-correction-code')
  9. const ReedSolomonEncoder = require('./reed-solomon-encoder')
  10. const Version = require('./version')
  11. const FormatInfo = require('./format-info')
  12. const Mode = require('./mode')
  13. const Segments = require('./segments')
  14. /**
  15. * QRCode for JavaScript
  16. *
  17. * modified by Ryan Day for nodejs support
  18. * Copyright (c) 2011 Ryan Day
  19. *
  20. * Licensed under the MIT license:
  21. * http://www.opensource.org/licenses/mit-license.php
  22. *
  23. //---------------------------------------------------------------------
  24. // QRCode for JavaScript
  25. //
  26. // Copyright (c) 2009 Kazuhiko Arase
  27. //
  28. // URL: http://www.d-project.com/
  29. //
  30. // Licensed under the MIT license:
  31. // http://www.opensource.org/licenses/mit-license.php
  32. //
  33. // The word "QR Code" is registered trademark of
  34. // DENSO WAVE INCORPORATED
  35. // http://www.denso-wave.com/qrcode/faqpatent-e.html
  36. //
  37. //---------------------------------------------------------------------
  38. */
  39. /**
  40. * Add finder patterns bits to matrix
  41. *
  42. * @param {BitMatrix} matrix Modules matrix
  43. * @param {Number} version QR Code version
  44. */
  45. function setupFinderPattern (matrix, version) {
  46. const size = matrix.size
  47. const pos = FinderPattern.getPositions(version)
  48. for (let i = 0; i < pos.length; i++) {
  49. const row = pos[i][0]
  50. const col = pos[i][1]
  51. for (let r = -1; r <= 7; r++) {
  52. if (row + r <= -1 || size <= row + r) continue
  53. for (let c = -1; c <= 7; c++) {
  54. if (col + c <= -1 || size <= col + c) continue
  55. if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) ||
  56. (c >= 0 && c <= 6 && (r === 0 || r === 6)) ||
  57. (r >= 2 && r <= 4 && c >= 2 && c <= 4)) {
  58. matrix.set(row + r, col + c, true, true)
  59. } else {
  60. matrix.set(row + r, col + c, false, true)
  61. }
  62. }
  63. }
  64. }
  65. }
  66. /**
  67. * Add timing pattern bits to matrix
  68. *
  69. * Note: this function must be called before {@link setupAlignmentPattern}
  70. *
  71. * @param {BitMatrix} matrix Modules matrix
  72. */
  73. function setupTimingPattern (matrix) {
  74. const size = matrix.size
  75. for (let r = 8; r < size - 8; r++) {
  76. const value = r % 2 === 0
  77. matrix.set(r, 6, value, true)
  78. matrix.set(6, r, value, true)
  79. }
  80. }
  81. /**
  82. * Add alignment patterns bits to matrix
  83. *
  84. * Note: this function must be called after {@link setupTimingPattern}
  85. *
  86. * @param {BitMatrix} matrix Modules matrix
  87. * @param {Number} version QR Code version
  88. */
  89. function setupAlignmentPattern (matrix, version) {
  90. const pos = AlignmentPattern.getPositions(version)
  91. for (let i = 0; i < pos.length; i++) {
  92. const row = pos[i][0]
  93. const col = pos[i][1]
  94. for (let r = -2; r <= 2; r++) {
  95. for (let c = -2; c <= 2; c++) {
  96. if (r === -2 || r === 2 || c === -2 || c === 2 ||
  97. (r === 0 && c === 0)) {
  98. matrix.set(row + r, col + c, true, true)
  99. } else {
  100. matrix.set(row + r, col + c, false, true)
  101. }
  102. }
  103. }
  104. }
  105. }
  106. /**
  107. * Add version info bits to matrix
  108. *
  109. * @param {BitMatrix} matrix Modules matrix
  110. * @param {Number} version QR Code version
  111. */
  112. function setupVersionInfo (matrix, version) {
  113. const size = matrix.size
  114. const bits = Version.getEncodedBits(version)
  115. let row, col, mod
  116. for (let i = 0; i < 18; i++) {
  117. row = Math.floor(i / 3)
  118. col = i % 3 + size - 8 - 3
  119. mod = ((bits >> i) & 1) === 1
  120. matrix.set(row, col, mod, true)
  121. matrix.set(col, row, mod, true)
  122. }
  123. }
  124. /**
  125. * Add format info bits to matrix
  126. *
  127. * @param {BitMatrix} matrix Modules matrix
  128. * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
  129. * @param {Number} maskPattern Mask pattern reference value
  130. */
  131. function setupFormatInfo (matrix, errorCorrectionLevel, maskPattern) {
  132. const size = matrix.size
  133. const bits = FormatInfo.getEncodedBits(errorCorrectionLevel, maskPattern)
  134. let i, mod
  135. for (i = 0; i < 15; i++) {
  136. mod = ((bits >> i) & 1) === 1
  137. // vertical
  138. if (i < 6) {
  139. matrix.set(i, 8, mod, true)
  140. } else if (i < 8) {
  141. matrix.set(i + 1, 8, mod, true)
  142. } else {
  143. matrix.set(size - 15 + i, 8, mod, true)
  144. }
  145. // horizontal
  146. if (i < 8) {
  147. matrix.set(8, size - i - 1, mod, true)
  148. } else if (i < 9) {
  149. matrix.set(8, 15 - i - 1 + 1, mod, true)
  150. } else {
  151. matrix.set(8, 15 - i - 1, mod, true)
  152. }
  153. }
  154. // fixed module
  155. matrix.set(size - 8, 8, 1, true)
  156. }
  157. /**
  158. * Add encoded data bits to matrix
  159. *
  160. * @param {BitMatrix} matrix Modules matrix
  161. * @param {Uint8Array} data Data codewords
  162. */
  163. function setupData (matrix, data) {
  164. const size = matrix.size
  165. let inc = -1
  166. let row = size - 1
  167. let bitIndex = 7
  168. let byteIndex = 0
  169. for (let col = size - 1; col > 0; col -= 2) {
  170. if (col === 6) col--
  171. while (true) {
  172. for (let c = 0; c < 2; c++) {
  173. if (!matrix.isReserved(row, col - c)) {
  174. let dark = false
  175. if (byteIndex < data.length) {
  176. dark = (((data[byteIndex] >>> bitIndex) & 1) === 1)
  177. }
  178. matrix.set(row, col - c, dark)
  179. bitIndex--
  180. if (bitIndex === -1) {
  181. byteIndex++
  182. bitIndex = 7
  183. }
  184. }
  185. }
  186. row += inc
  187. if (row < 0 || size <= row) {
  188. row -= inc
  189. inc = -inc
  190. break
  191. }
  192. }
  193. }
  194. }
  195. /**
  196. * Create encoded codewords from data input
  197. *
  198. * @param {Number} version QR Code version
  199. * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
  200. * @param {ByteData} data Data input
  201. * @return {Uint8Array} Buffer containing encoded codewords
  202. */
  203. function createData (version, errorCorrectionLevel, segments) {
  204. // Prepare data buffer
  205. const buffer = new BitBuffer()
  206. segments.forEach(function (data) {
  207. // prefix data with mode indicator (4 bits)
  208. buffer.put(data.mode.bit, 4)
  209. // Prefix data with character count indicator.
  210. // The character count indicator is a string of bits that represents the
  211. // number of characters that are being encoded.
  212. // The character count indicator must be placed after the mode indicator
  213. // and must be a certain number of bits long, depending on the QR version
  214. // and data mode
  215. // @see {@link Mode.getCharCountIndicator}.
  216. buffer.put(data.getLength(), Mode.getCharCountIndicator(data.mode, version))
  217. // add binary data sequence to buffer
  218. data.write(buffer)
  219. })
  220. // Calculate required number of bits
  221. const totalCodewords = Utils.getSymbolTotalCodewords(version)
  222. const ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
  223. const dataTotalCodewordsBits = (totalCodewords - ecTotalCodewords) * 8
  224. // Add a terminator.
  225. // If the bit string is shorter than the total number of required bits,
  226. // a terminator of up to four 0s must be added to the right side of the string.
  227. // If the bit string is more than four bits shorter than the required number of bits,
  228. // add four 0s to the end.
  229. if (buffer.getLengthInBits() + 4 <= dataTotalCodewordsBits) {
  230. buffer.put(0, 4)
  231. }
  232. // If the bit string is fewer than four bits shorter, add only the number of 0s that
  233. // are needed to reach the required number of bits.
  234. // After adding the terminator, if the number of bits in the string is not a multiple of 8,
  235. // pad the string on the right with 0s to make the string's length a multiple of 8.
  236. while (buffer.getLengthInBits() % 8 !== 0) {
  237. buffer.putBit(0)
  238. }
  239. // Add pad bytes if the string is still shorter than the total number of required bits.
  240. // Extend the buffer to fill the data capacity of the symbol corresponding to
  241. // the Version and Error Correction Level by adding the Pad Codewords 11101100 (0xEC)
  242. // and 00010001 (0x11) alternately.
  243. const remainingByte = (dataTotalCodewordsBits - buffer.getLengthInBits()) / 8
  244. for (let i = 0; i < remainingByte; i++) {
  245. buffer.put(i % 2 ? 0x11 : 0xEC, 8)
  246. }
  247. return createCodewords(buffer, version, errorCorrectionLevel)
  248. }
  249. /**
  250. * Encode input data with Reed-Solomon and return codewords with
  251. * relative error correction bits
  252. *
  253. * @param {BitBuffer} bitBuffer Data to encode
  254. * @param {Number} version QR Code version
  255. * @param {ErrorCorrectionLevel} errorCorrectionLevel Error correction level
  256. * @return {Uint8Array} Buffer containing encoded codewords
  257. */
  258. function createCodewords (bitBuffer, version, errorCorrectionLevel) {
  259. // Total codewords for this QR code version (Data + Error correction)
  260. const totalCodewords = Utils.getSymbolTotalCodewords(version)
  261. // Total number of error correction codewords
  262. const ecTotalCodewords = ECCode.getTotalCodewordsCount(version, errorCorrectionLevel)
  263. // Total number of data codewords
  264. const dataTotalCodewords = totalCodewords - ecTotalCodewords
  265. // Total number of blocks
  266. const ecTotalBlocks = ECCode.getBlocksCount(version, errorCorrectionLevel)
  267. // Calculate how many blocks each group should contain
  268. const blocksInGroup2 = totalCodewords % ecTotalBlocks
  269. const blocksInGroup1 = ecTotalBlocks - blocksInGroup2
  270. const totalCodewordsInGroup1 = Math.floor(totalCodewords / ecTotalBlocks)
  271. const dataCodewordsInGroup1 = Math.floor(dataTotalCodewords / ecTotalBlocks)
  272. const dataCodewordsInGroup2 = dataCodewordsInGroup1 + 1
  273. // Number of EC codewords is the same for both groups
  274. const ecCount = totalCodewordsInGroup1 - dataCodewordsInGroup1
  275. // Initialize a Reed-Solomon encoder with a generator polynomial of degree ecCount
  276. const rs = new ReedSolomonEncoder(ecCount)
  277. let offset = 0
  278. const dcData = new Array(ecTotalBlocks)
  279. const ecData = new Array(ecTotalBlocks)
  280. let maxDataSize = 0
  281. const buffer = new Uint8Array(bitBuffer.buffer)
  282. // Divide the buffer into the required number of blocks
  283. for (let b = 0; b < ecTotalBlocks; b++) {
  284. const dataSize = b < blocksInGroup1 ? dataCodewordsInGroup1 : dataCodewordsInGroup2
  285. // extract a block of data from buffer
  286. dcData[b] = buffer.slice(offset, offset + dataSize)
  287. // Calculate EC codewords for this data block
  288. ecData[b] = rs.encode(dcData[b])
  289. offset += dataSize
  290. maxDataSize = Math.max(maxDataSize, dataSize)
  291. }
  292. // Create final data
  293. // Interleave the data and error correction codewords from each block
  294. const data = new Uint8Array(totalCodewords)
  295. let index = 0
  296. let i, r
  297. // Add data codewords
  298. for (i = 0; i < maxDataSize; i++) {
  299. for (r = 0; r < ecTotalBlocks; r++) {
  300. if (i < dcData[r].length) {
  301. data[index++] = dcData[r][i]
  302. }
  303. }
  304. }
  305. // Apped EC codewords
  306. for (i = 0; i < ecCount; i++) {
  307. for (r = 0; r < ecTotalBlocks; r++) {
  308. data[index++] = ecData[r][i]
  309. }
  310. }
  311. return data
  312. }
  313. /**
  314. * Build QR Code symbol
  315. *
  316. * @param {String} data Input string
  317. * @param {Number} version QR Code version
  318. * @param {ErrorCorretionLevel} errorCorrectionLevel Error level
  319. * @param {MaskPattern} maskPattern Mask pattern
  320. * @return {Object} Object containing symbol data
  321. */
  322. function createSymbol (data, version, errorCorrectionLevel, maskPattern) {
  323. let segments
  324. if (Array.isArray(data)) {
  325. segments = Segments.fromArray(data)
  326. } else if (typeof data === 'string') {
  327. let estimatedVersion = version
  328. if (!estimatedVersion) {
  329. const rawSegments = Segments.rawSplit(data)
  330. // Estimate best version that can contain raw splitted segments
  331. estimatedVersion = Version.getBestVersionForData(rawSegments, errorCorrectionLevel)
  332. }
  333. // Build optimized segments
  334. // If estimated version is undefined, try with the highest version
  335. segments = Segments.fromString(data, estimatedVersion || 40)
  336. } else {
  337. throw new Error('Invalid data')
  338. }
  339. // Get the min version that can contain data
  340. const bestVersion = Version.getBestVersionForData(segments, errorCorrectionLevel)
  341. // If no version is found, data cannot be stored
  342. if (!bestVersion) {
  343. throw new Error('The amount of data is too big to be stored in a QR Code')
  344. }
  345. // If not specified, use min version as default
  346. if (!version) {
  347. version = bestVersion
  348. // Check if the specified version can contain the data
  349. } else if (version < bestVersion) {
  350. throw new Error('\n' +
  351. 'The chosen QR Code version cannot contain this amount of data.\n' +
  352. 'Minimum version required to store current data is: ' + bestVersion + '.\n'
  353. )
  354. }
  355. const dataBits = createData(version, errorCorrectionLevel, segments)
  356. // Allocate matrix buffer
  357. const moduleCount = Utils.getSymbolSize(version)
  358. const modules = new BitMatrix(moduleCount)
  359. // Add function modules
  360. setupFinderPattern(modules, version)
  361. setupTimingPattern(modules)
  362. setupAlignmentPattern(modules, version)
  363. // Add temporary dummy bits for format info just to set them as reserved.
  364. // This is needed to prevent these bits from being masked by {@link MaskPattern.applyMask}
  365. // since the masking operation must be performed only on the encoding region.
  366. // These blocks will be replaced with correct values later in code.
  367. setupFormatInfo(modules, errorCorrectionLevel, 0)
  368. if (version >= 7) {
  369. setupVersionInfo(modules, version)
  370. }
  371. // Add data codewords
  372. setupData(modules, dataBits)
  373. if (isNaN(maskPattern)) {
  374. // Find best mask pattern
  375. maskPattern = MaskPattern.getBestMask(modules,
  376. setupFormatInfo.bind(null, modules, errorCorrectionLevel))
  377. }
  378. // Apply mask pattern
  379. MaskPattern.applyMask(maskPattern, modules)
  380. // Replace format info bits with correct values
  381. setupFormatInfo(modules, errorCorrectionLevel, maskPattern)
  382. return {
  383. modules: modules,
  384. version: version,
  385. errorCorrectionLevel: errorCorrectionLevel,
  386. maskPattern: maskPattern,
  387. segments: segments
  388. }
  389. }
  390. /**
  391. * QR Code
  392. *
  393. * @param {String | Array} data Input data
  394. * @param {Object} options Optional configurations
  395. * @param {Number} options.version QR Code version
  396. * @param {String} options.errorCorrectionLevel Error correction level
  397. * @param {Function} options.toSJISFunc Helper func to convert utf8 to sjis
  398. */
  399. exports.create = function create (data, options) {
  400. if (typeof data === 'undefined' || data === '') {
  401. throw new Error('No input text')
  402. }
  403. let errorCorrectionLevel = ECLevel.M
  404. let version
  405. let mask
  406. if (typeof options !== 'undefined') {
  407. // Use higher error correction level as default
  408. errorCorrectionLevel = ECLevel.from(options.errorCorrectionLevel, ECLevel.M)
  409. version = Version.from(options.version)
  410. mask = MaskPattern.from(options.maskPattern)
  411. if (options.toSJISFunc) {
  412. Utils.setToSJISFunction(options.toSJISFunc)
  413. }
  414. }
  415. return createSymbol(data, version, errorCorrectionLevel, mask)
  416. }