qrcode.js 15 KB

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