jsQR.js 115 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752
  1. (function webpackUniversalModuleDefinition(root, factory) {
  2. if(typeof exports === 'object' && typeof module === 'object')
  3. module.exports = factory();
  4. else if(typeof define === 'function' && define.amd)
  5. define([], factory);
  6. else if(typeof exports === 'object')
  7. exports["jsQR"] = factory();
  8. else
  9. root["jsQR"] = factory();
  10. })(this, function() {
  11. return /******/ (function(modules) { // webpackBootstrap
  12. if ( !Array.prototype.forEach ) {
  13. Array.prototype.forEach = function forEach( callback, thisArg ) {
  14. var T, k;
  15. if ( this == null ) {
  16. throw new TypeError( "this is null or not defined" );
  17. }
  18. var O = Object(this);
  19. var len = O.length >>> 0;
  20. if ( typeof callback !== "function" ) {
  21. throw new TypeError( callback + " is not a function" );
  22. }
  23. if ( arguments.length > 1 ) {
  24. T = thisArg;
  25. }
  26. k = 0;
  27. while( k < len ) {
  28. var kValue;
  29. if ( k in O ) {
  30. kValue = O[ k ];
  31. callback.call( T, kValue, k, O );
  32. }
  33. k++;
  34. }
  35. };
  36. }
  37. /******/ // The module cache
  38. /******/ var installedModules = {};
  39. /******/ // The require function
  40. /******/ function __webpack_require__(moduleId) {
  41. /******/ // Check if module is in cache
  42. /******/ if(installedModules[moduleId])
  43. /******/ return installedModules[moduleId].exports;
  44. /******/ // Create a new module (and put it into the cache)
  45. /******/ var module = installedModules[moduleId] = {
  46. /******/ exports: {},
  47. /******/ id: moduleId,
  48. /******/ loaded: false
  49. /******/ };
  50. /******/ // Execute the module function
  51. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  52. /******/ // Flag the module as loaded
  53. /******/ module.loaded = true;
  54. /******/ // Return the exports of the module
  55. /******/ return module.exports;
  56. /******/ }
  57. /******/ // expose the modules object (__webpack_modules__)
  58. /******/ __webpack_require__.m = modules;
  59. /******/ // expose the module cache
  60. /******/ __webpack_require__.c = installedModules;
  61. /******/ // __webpack_public_path__
  62. /******/ __webpack_require__.p = "";
  63. /******/ // Load entry module and return exports
  64. /******/ return __webpack_require__(0);
  65. /******/ })
  66. /************************************************************************/
  67. /******/ ([
  68. /* 0 */
  69. /***/ function(module, exports, __webpack_require__) {
  70. "use strict";
  71. /// <reference path="./common/types.d.ts" />
  72. var binarizer_1 = __webpack_require__(1);
  73. var locator_1 = __webpack_require__(3);
  74. var extractor_1 = __webpack_require__(4);
  75. var decoder_1 = __webpack_require__(9);
  76. var bitmatrix_1 = __webpack_require__(2);
  77. var binarizeImage = binarizer_1.binarize;
  78. exports.binarizeImage = binarizeImage;
  79. var locateQRInBinaryImage = locator_1.locate;
  80. exports.locateQRInBinaryImage = locateQRInBinaryImage;
  81. var extractQRFromBinaryImage = extractor_1.extract;
  82. exports.extractQRFromBinaryImage = extractQRFromBinaryImage;
  83. function decodeQR(matrix) {
  84. return byteArrayToString(decoder_1.decode(matrix));
  85. }
  86. exports.decodeQR = decodeQR;
  87. // return bytes.reduce((p, b) => p + String.fromCharCode(b), "");
  88. function byteArrayToString(bytes) {
  89. var str = "";
  90. if (bytes != null && bytes != undefined) {
  91. for (var i = 0; i < bytes.length; i++) {
  92. str += String.fromCharCode(bytes[i]);
  93. }
  94. }
  95. return str;
  96. }
  97. function createBitMatrix(data, width) {
  98. return new bitmatrix_1.BitMatrix(data, width);
  99. }
  100. exports.createBitMatrix = createBitMatrix;
  101. function decodeQRFromImage(data, width, height) {
  102. return byteArrayToString(decodeQRFromImageAsByteArray(data, width, height));
  103. }
  104. exports.decodeQRFromImage = decodeQRFromImage;
  105. function decodeQRFromImageAsByteArray(data, width, height) {
  106. var binarizedImage = binarizeImage(data, width, height);
  107. var location = locator_1.locate(binarizedImage);
  108. if (!location) {
  109. return null;
  110. }
  111. var rawQR = extractor_1.extract(binarizedImage, location);
  112. if (!rawQR) {
  113. return null;
  114. }
  115. return decoder_1.decode(rawQR);
  116. }
  117. exports.decodeQRFromImageAsByteArray = decodeQRFromImageAsByteArray;
  118. /***/ },
  119. /* 1 */
  120. /***/ function(module, exports, __webpack_require__) {
  121. "use strict";
  122. var bitmatrix_1 = __webpack_require__(2);
  123. // Magic Constants
  124. var BLOCK_SIZE_POWER = 3;
  125. var BLOCK_SIZE = 1 << BLOCK_SIZE_POWER;
  126. var BLOCK_SIZE_MASK = BLOCK_SIZE - 1;
  127. var MIN_DYNAMIC_RANGE = 24;
  128. function calculateBlackPoints(luminances, subWidth, subHeight, width, height) {
  129. var blackPoints = new Array(subHeight);
  130. for (var i = 0; i < subHeight; i++) {
  131. blackPoints[i] = new Array(subWidth);
  132. }
  133. for (var y = 0; y < subHeight; y++) {
  134. var yoffset = y << BLOCK_SIZE_POWER;
  135. var maxYOffset = height - BLOCK_SIZE;
  136. if (yoffset > maxYOffset) {
  137. yoffset = maxYOffset;
  138. }
  139. for (var x = 0; x < subWidth; x++) {
  140. var xoffset = x << BLOCK_SIZE_POWER;
  141. var maxXOffset = width - BLOCK_SIZE;
  142. if (xoffset > maxXOffset) {
  143. xoffset = maxXOffset;
  144. }
  145. var sum = 0;
  146. var min = 0xFF;
  147. var max = 0;
  148. for (var yy = 0, offset = yoffset * width + xoffset; yy < BLOCK_SIZE; yy++, offset += width) {
  149. for (var xx = 0; xx < BLOCK_SIZE; xx++) {
  150. var pixel = luminances[offset + xx] & 0xFF;
  151. // still looking for good contrast
  152. sum += pixel;
  153. if (pixel < min) {
  154. min = pixel;
  155. }
  156. if (pixel > max) {
  157. max = pixel;
  158. }
  159. }
  160. // short-circuit min/max tests once dynamic range is met
  161. if (max - min > MIN_DYNAMIC_RANGE) {
  162. // finish the rest of the rows quickly
  163. for (yy++, offset += width; yy < BLOCK_SIZE; yy++, offset += width) {
  164. for (var xx = 0; xx < BLOCK_SIZE; xx++) {
  165. sum += luminances[offset + xx] & 0xFF;
  166. }
  167. }
  168. }
  169. }
  170. // The default estimate is the average of the values in the block.
  171. var average = sum >> (BLOCK_SIZE_POWER * 2);
  172. if (max - min <= MIN_DYNAMIC_RANGE) {
  173. // If variation within the block is low, assume this is a block with only light or only
  174. // dark pixels. In that case we do not want to use the average, as it would divide this
  175. // low contrast area into black and white pixels, essentially creating data out of noise.
  176. //
  177. // The default assumption is that the block is light/background. Since no estimate for
  178. // the level of dark pixels exists locally, use half the min for the block.
  179. average = min >> 1;
  180. if (y > 0 && x > 0) {
  181. // Correct the "white background" assumption for blocks that have neighbors by comparing
  182. // the pixels in this block to the previously calculated black points. This is based on
  183. // the fact that dark barcode symbology is always surrounded by some amount of light
  184. // background for which reasonable black point estimates were made. The bp estimated at
  185. // the boundaries is used for the interior.
  186. // The (min < bp) is arbitrary but works better than other heuristics that were tried.
  187. var averageNeighborBlackPoint = (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) >> 2;
  188. if (min < averageNeighborBlackPoint) {
  189. average = averageNeighborBlackPoint;
  190. }
  191. }
  192. }
  193. blackPoints[y][x] = average;
  194. }
  195. }
  196. return blackPoints;
  197. }
  198. function calculateThresholdForBlock(luminances, subWidth, subHeight, width, height, blackPoints) {
  199. function cap(value, min, max) {
  200. return value < min ? min : value > max ? max : value;
  201. }
  202. // var outArray = new Array(width * height);
  203. var outMatrix = bitmatrix_1.BitMatrix.createEmpty(width, height);
  204. function thresholdBlock(luminances, xoffset, yoffset, threshold, stride) {
  205. var offset = (yoffset * stride) + xoffset;
  206. for (var y = 0; y < BLOCK_SIZE; y++, offset += stride) {
  207. for (var x = 0; x < BLOCK_SIZE; x++) {
  208. var pixel = luminances[offset + x] & 0xff;
  209. // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0.
  210. outMatrix.set(xoffset + x, yoffset + y, pixel <= threshold);
  211. }
  212. }
  213. }
  214. for (var y = 0; y < subHeight; y++) {
  215. var yoffset = y << BLOCK_SIZE_POWER;
  216. var maxYOffset = height - BLOCK_SIZE;
  217. if (yoffset > maxYOffset) {
  218. yoffset = maxYOffset;
  219. }
  220. for (var x = 0; x < subWidth; x++) {
  221. var xoffset = x << BLOCK_SIZE_POWER;
  222. var maxXOffset = width - BLOCK_SIZE;
  223. if (xoffset > maxXOffset) {
  224. xoffset = maxXOffset;
  225. }
  226. var left = cap(x, 2, subWidth - 3);
  227. var top = cap(y, 2, subHeight - 3);
  228. var sum = 0;
  229. for (var z = -2; z <= 2; z++) {
  230. var blackRow = blackPoints[top + z];
  231. sum += blackRow[left - 2];
  232. sum += blackRow[left - 1];
  233. sum += blackRow[left];
  234. sum += blackRow[left + 1];
  235. sum += blackRow[left + 2];
  236. }
  237. var average = sum / 25;
  238. thresholdBlock(luminances, xoffset, yoffset, average, width);
  239. }
  240. }
  241. return outMatrix;
  242. }
  243. function binarize(data, width, height) {
  244. if (data.length !== width * height * 4) {
  245. throw new Error("Binarizer data.length != width * height * 4");
  246. }
  247. var gsArray = new Array(width * height);
  248. for (var x = 0; x < width; x++) {
  249. for (var y = 0; y < height; y++) {
  250. var startIndex = (y * width + x) * 4;
  251. var r = data[startIndex];
  252. var g = data[startIndex + 1];
  253. var b = data[startIndex + 2];
  254. // Magic lumosity constants
  255. var lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
  256. gsArray[y * width + x] = lum;
  257. }
  258. }
  259. var subWidth = width >> BLOCK_SIZE_POWER;
  260. if ((width & BLOCK_SIZE_MASK) != 0) {
  261. subWidth++;
  262. }
  263. var subHeight = height >> BLOCK_SIZE_POWER;
  264. if ((height & BLOCK_SIZE_MASK) != 0) {
  265. subHeight++;
  266. }
  267. var blackPoints = calculateBlackPoints(gsArray, subWidth, subHeight, width, height);
  268. return calculateThresholdForBlock(gsArray, subWidth, subHeight, width, height, blackPoints);
  269. }
  270. exports.binarize = binarize;
  271. /***/ },
  272. /* 2 */
  273. /***/ function(module, exports) {
  274. "use strict";
  275. var BitMatrix = (function () {
  276. function BitMatrix(data, width) {
  277. this.width = width;
  278. this.height = data.length / width;
  279. this.data = data;
  280. }
  281. BitMatrix.createEmpty = function (width, height) {
  282. var data = new Array(width * height);
  283. for (var i = 0; i < data.length; i++) {
  284. data[i] = false;
  285. }
  286. return new BitMatrix(data, width);
  287. };
  288. BitMatrix.prototype.get = function (x, y) {
  289. return this.data[y * this.width + x];
  290. };
  291. BitMatrix.prototype.set = function (x, y, v) {
  292. this.data[y * this.width + x] = v;
  293. };
  294. BitMatrix.prototype.copyBit = function (x, y, versionBits) {
  295. return this.get(x, y) ? (versionBits << 1) | 0x1 : versionBits << 1;
  296. };
  297. BitMatrix.prototype.setRegion = function (left, top, width, height) {
  298. var right = left + width;
  299. var bottom = top + height;
  300. for (var y = top; y < bottom; y++) {
  301. for (var x = left; x < right; x++) {
  302. this.set(x, y, true);
  303. }
  304. }
  305. };
  306. BitMatrix.prototype.mirror = function () {
  307. for (var x = 0; x < this.width; x++) {
  308. for (var y = x + 1; y < this.height; y++) {
  309. if (this.get(x, y) != this.get(y, x)) {
  310. this.set(x, y, !this.get(x, y));
  311. this.set(y, x, !this.get(y, x));
  312. }
  313. }
  314. }
  315. };
  316. return BitMatrix;
  317. }());
  318. exports.BitMatrix = BitMatrix;
  319. /***/ },
  320. /* 3 */
  321. /***/ function(module, exports) {
  322. "use strict";
  323. var CENTER_QUORUM = 2;
  324. var MIN_SKIP = 3;
  325. var MAX_MODULES = 57;
  326. var INTEGER_MATH_SHIFT = 8;
  327. var FinderPattern = (function () {
  328. function FinderPattern(x, y, estimatedModuleSize, count) {
  329. this.x = x;
  330. this.y = y;
  331. this.estimatedModuleSize = estimatedModuleSize;
  332. if (count == null) {
  333. this.count = 1;
  334. }
  335. else {
  336. this.count = count;
  337. }
  338. }
  339. FinderPattern.prototype.aboutEquals = function (moduleSize, i, j) {
  340. if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) {
  341. var moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize);
  342. return moduleSizeDiff <= 1.0 || moduleSizeDiff <= this.estimatedModuleSize;
  343. }
  344. return false;
  345. };
  346. FinderPattern.prototype.combineEstimate = function (i, j, newModuleSize) {
  347. var combinedCount = this.count + 1;
  348. var combinedX = (this.count * this.x + j) / combinedCount;
  349. var combinedY = (this.count * this.y + i) / combinedCount;
  350. var combinedModuleSize = (this.count * this.estimatedModuleSize + newModuleSize) / combinedCount;
  351. return new FinderPattern(combinedX, combinedY, combinedModuleSize, combinedCount);
  352. };
  353. return FinderPattern;
  354. }());
  355. function foundPatternCross(stateCount) {
  356. var totalModuleSize = 0;
  357. for (var i = 0; i < 5; i++) {
  358. var count = stateCount[i];
  359. if (count === 0)
  360. return false;
  361. totalModuleSize += count;
  362. }
  363. if (totalModuleSize < 7)
  364. return false;
  365. var moduleSize = (totalModuleSize << INTEGER_MATH_SHIFT) / 7;
  366. var maxVariance = moduleSize / 2;
  367. // Allow less than 50% variance from 1-1-3-1-1 proportions
  368. return Math.abs(moduleSize - (stateCount[0] << INTEGER_MATH_SHIFT)) < maxVariance &&
  369. Math.abs(moduleSize - (stateCount[1] << INTEGER_MATH_SHIFT)) < maxVariance &&
  370. Math.abs(3 * moduleSize - (stateCount[2] << INTEGER_MATH_SHIFT)) < 3 * maxVariance &&
  371. Math.abs(moduleSize - (stateCount[3] << INTEGER_MATH_SHIFT)) < maxVariance &&
  372. Math.abs(moduleSize - (stateCount[4] << INTEGER_MATH_SHIFT)) < maxVariance;
  373. }
  374. function centerFromEnd(stateCount, end) {
  375. var result = (end - stateCount[4] - stateCount[3]) - stateCount[2] / 2;
  376. // Fix this.
  377. if (result !== result) {
  378. return null;
  379. }
  380. return result;
  381. }
  382. function distance(pattern1, pattern2) {
  383. var a = pattern1.x - pattern2.x;
  384. var b = pattern1.y - pattern2.y;
  385. return Math.sqrt(a * a + b * b);
  386. }
  387. function crossProductZ(pointA, pointB, pointC) {
  388. var bX = pointB.x;
  389. var bY = pointB.y;
  390. return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX));
  391. }
  392. function ReorderFinderPattern(patterns) {
  393. // Find distances between pattern centers
  394. var zeroOneDistance = distance(patterns[0], patterns[1]);
  395. var oneTwoDistance = distance(patterns[1], patterns[2]);
  396. var zeroTwoDistance = distance(patterns[0], patterns[2]);
  397. var pointA, pointB, pointC;
  398. // Assume one closest to other two is B; A and C will just be guesses at first
  399. if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) {
  400. pointB = patterns[0];
  401. pointA = patterns[1];
  402. pointC = patterns[2];
  403. }
  404. else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) {
  405. pointB = patterns[1];
  406. pointA = patterns[0];
  407. pointC = patterns[2];
  408. }
  409. else {
  410. pointB = patterns[2];
  411. pointA = patterns[0];
  412. pointC = patterns[1];
  413. }
  414. // Use cross product to figure out whether A and C are correct or flipped.
  415. // This asks whether BC x BA has a positive z component, which is the arrangement
  416. // we want for A, B, C. If it's negative, then we've got it flipped around and
  417. // should swap A and C.
  418. if (crossProductZ(pointA, pointB, pointC) < 0) {
  419. var temp = pointA;
  420. pointA = pointC;
  421. pointC = temp;
  422. }
  423. return {
  424. bottomLeft: { x: pointA.x, y: pointA.y },
  425. topLeft: { x: pointB.x, y: pointB.y },
  426. topRight: { x: pointC.x, y: pointC.y }
  427. };
  428. }
  429. function locate(matrix) {
  430. // Global state :(
  431. var possibleCenters = [];
  432. var hasSkipped = false;
  433. function get(x, y) {
  434. x = Math.floor(x);
  435. y = Math.floor(y);
  436. return matrix.get(x, y);
  437. }
  438. // Methods
  439. function crossCheckDiagonal(startI, centerJ, maxCount, originalStateCountTotal) {
  440. var maxI = matrix.height;
  441. var maxJ = matrix.width;
  442. var stateCount = [0, 0, 0, 0, 0];
  443. // Start counting up, left from center finding black center mass
  444. var i = 0;
  445. while (startI - i >= 0 && get(centerJ - i, startI - i)) {
  446. stateCount[2]++;
  447. i++;
  448. }
  449. if ((startI - i < 0) || (centerJ - i < 0)) {
  450. return false;
  451. }
  452. // Continue up, left finding white space
  453. while ((startI - i >= 0) && (centerJ - i >= 0) && !get(centerJ - i, startI - i) && stateCount[1] <= maxCount) {
  454. stateCount[1]++;
  455. i++;
  456. }
  457. // If already too many modules in this state or ran off the edge:
  458. if ((startI - i < 0) || (centerJ - i < 0) || stateCount[1] > maxCount) {
  459. return false;
  460. }
  461. // Continue up, left finding black border
  462. while ((startI - i >= 0) && (centerJ - i >= 0) && get(centerJ - i, startI - i) && stateCount[0] <= maxCount) {
  463. stateCount[0]++;
  464. i++;
  465. }
  466. if (stateCount[0] > maxCount) {
  467. return false;
  468. }
  469. // Now also count down, right from center
  470. i = 1;
  471. while ((startI + i < maxI) && (centerJ + i < maxJ) && get(centerJ + i, startI + i)) {
  472. stateCount[2]++;
  473. i++;
  474. }
  475. // Ran off the edge?
  476. if ((startI + i >= maxI) || (centerJ + i >= maxJ)) {
  477. return false;
  478. }
  479. while ((startI + i < maxI) && (centerJ + i < maxJ) && !get(centerJ + i, startI + i) && stateCount[3] < maxCount) {
  480. stateCount[3]++;
  481. i++;
  482. }
  483. if ((startI + i >= maxI) || (centerJ + i >= maxJ) || stateCount[3] >= maxCount) {
  484. return false;
  485. }
  486. while ((startI + i < maxI) && (centerJ + i < maxJ) && get(centerJ + i, startI + i) && stateCount[4] < maxCount) {
  487. stateCount[4]++;
  488. i++;
  489. }
  490. if (stateCount[4] >= maxCount) {
  491. return false;
  492. }
  493. // If we found a finder-pattern-like section, but its size is more than 100% different than
  494. // the original, assume it's a false positive
  495. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  496. return Math.abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal &&
  497. foundPatternCross(stateCount);
  498. }
  499. function crossCheckVertical(startI, centerJ, maxCount, originalStateCountTotal) {
  500. var maxI = matrix.height;
  501. var stateCount = [0, 0, 0, 0, 0];
  502. // Start counting up from center
  503. var i = startI;
  504. while (i >= 0 && get(centerJ, i)) {
  505. stateCount[2]++;
  506. i--;
  507. }
  508. if (i < 0) {
  509. return null;
  510. }
  511. while (i >= 0 && !get(centerJ, i) && stateCount[1] <= maxCount) {
  512. stateCount[1]++;
  513. i--;
  514. }
  515. // If already too many modules in this state or ran off the edge:
  516. if (i < 0 || stateCount[1] > maxCount) {
  517. return null;
  518. }
  519. while (i >= 0 && get(centerJ, i) && stateCount[0] <= maxCount) {
  520. stateCount[0]++;
  521. i--;
  522. }
  523. if (stateCount[0] > maxCount) {
  524. return null;
  525. }
  526. // Now also count down from center
  527. i = startI + 1;
  528. while (i < maxI && get(centerJ, i)) {
  529. stateCount[2]++;
  530. i++;
  531. }
  532. if (i == maxI) {
  533. return null;
  534. }
  535. while (i < maxI && !get(centerJ, i) && stateCount[3] < maxCount) {
  536. stateCount[3]++;
  537. i++;
  538. }
  539. if (i == maxI || stateCount[3] >= maxCount) {
  540. return null;
  541. }
  542. while (i < maxI && get(centerJ, i) && stateCount[4] < maxCount) {
  543. stateCount[4]++;
  544. i++;
  545. }
  546. if (stateCount[4] >= maxCount) {
  547. return null;
  548. }
  549. // If we found a finder-pattern-like section, but its size is more than 40% different than
  550. // the original, assume it's a false positive
  551. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  552. if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
  553. return null;
  554. }
  555. return foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : null;
  556. }
  557. function haveMultiplyConfirmedCenters() {
  558. var confirmedCount = 0;
  559. var totalModuleSize = 0;
  560. var max = possibleCenters.length;
  561. possibleCenters.forEach(function (pattern) {
  562. if (pattern.count >= CENTER_QUORUM) {
  563. confirmedCount++;
  564. totalModuleSize += pattern.estimatedModuleSize;
  565. }
  566. });
  567. if (confirmedCount < 3) {
  568. return false;
  569. }
  570. // OK, we have at least 3 confirmed centers, but, it's possible that one is a "false positive"
  571. // and that we need to keep looking. We detect this by asking if the estimated module sizes
  572. // vary too much. We arbitrarily say that when the total deviation from average exceeds
  573. // 5% of the total module size estimates, it's too much.
  574. var average = totalModuleSize / max;
  575. var totalDeviation = 0;
  576. for (var i = 0; i < max; i++) {
  577. var pattern = possibleCenters[i];
  578. totalDeviation += Math.abs(pattern.estimatedModuleSize - average);
  579. }
  580. return totalDeviation <= 0.05 * totalModuleSize;
  581. }
  582. function crossCheckHorizontal(startJ, centerI, maxCount, originalStateCountTotal) {
  583. var maxJ = matrix.width;
  584. var stateCount = [0, 0, 0, 0, 0];
  585. var j = startJ;
  586. while (j >= 0 && get(j, centerI)) {
  587. stateCount[2]++;
  588. j--;
  589. }
  590. if (j < 0) {
  591. return null;
  592. }
  593. while (j >= 0 && !get(j, centerI) && stateCount[1] <= maxCount) {
  594. stateCount[1]++;
  595. j--;
  596. }
  597. if (j < 0 || stateCount[1] > maxCount) {
  598. return null;
  599. }
  600. while (j >= 0 && get(j, centerI) && stateCount[0] <= maxCount) {
  601. stateCount[0]++;
  602. j--;
  603. }
  604. if (stateCount[0] > maxCount) {
  605. return null;
  606. }
  607. j = startJ + 1;
  608. while (j < maxJ && get(j, centerI)) {
  609. stateCount[2]++;
  610. j++;
  611. }
  612. if (j == maxJ) {
  613. return null;
  614. }
  615. while (j < maxJ && !get(j, centerI) && stateCount[3] < maxCount) {
  616. stateCount[3]++;
  617. j++;
  618. }
  619. if (j == maxJ || stateCount[3] >= maxCount) {
  620. return null;
  621. }
  622. while (j < maxJ && get(j, centerI) && stateCount[4] < maxCount) {
  623. stateCount[4]++;
  624. j++;
  625. }
  626. if (stateCount[4] >= maxCount) {
  627. return null;
  628. }
  629. // If we found a finder-pattern-like section, but its size is significantly different than
  630. // the original, assume it's a false positive
  631. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  632. if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) {
  633. return null;
  634. }
  635. return foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : null;
  636. }
  637. function handlePossibleCenter(stateCount, i, j, pureBarcode) {
  638. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4];
  639. var centerJ = centerFromEnd(stateCount, j);
  640. if (centerJ == null)
  641. return false;
  642. var centerI = crossCheckVertical(i, Math.floor(centerJ), stateCount[2], stateCountTotal);
  643. if (centerI != null) {
  644. // Re-cross check
  645. centerJ = crossCheckHorizontal(Math.floor(centerJ), Math.floor(centerI), stateCount[2], stateCountTotal);
  646. if (centerJ != null && (!pureBarcode || crossCheckDiagonal(Math.floor(centerI), Math.floor(centerJ), stateCount[2], stateCountTotal))) {
  647. var estimatedModuleSize = stateCountTotal / 7;
  648. var found = false;
  649. for (var index = 0; index < possibleCenters.length; index++) {
  650. var center = possibleCenters[index];
  651. // Look for about the same center and module size:
  652. if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) {
  653. possibleCenters.splice(index, 1, center.combineEstimate(centerI, centerJ, estimatedModuleSize));
  654. found = true;
  655. break;
  656. }
  657. }
  658. if (!found) {
  659. // var point = new FinderPattern(centerJ.Value, centerI.Value, estimatedModuleSize);
  660. var point = new FinderPattern(centerJ, centerI, estimatedModuleSize);
  661. possibleCenters.push(point);
  662. }
  663. return true;
  664. }
  665. }
  666. return false;
  667. }
  668. function findRowSkip() {
  669. var max = possibleCenters.length;
  670. if (max <= 1) {
  671. return 0;
  672. }
  673. var firstConfirmedCenter = null;
  674. possibleCenters.forEach(function (center) {
  675. if (center.count >= CENTER_QUORUM) {
  676. if (firstConfirmedCenter == null) {
  677. firstConfirmedCenter = center;
  678. }
  679. else {
  680. // We have two confirmed centers
  681. // How far down can we skip before resuming looking for the next
  682. // pattern? In the worst case, only the difference between the
  683. // difference in the x / y coordinates of the two centers.
  684. // This is the case where you find top left last.
  685. hasSkipped = true;
  686. //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'"
  687. return Math.floor(Math.abs(firstConfirmedCenter.x - center.x) - Math.abs(firstConfirmedCenter.y - center.y)) / 2;
  688. }
  689. }
  690. });
  691. return 0;
  692. }
  693. function selectBestPatterns() {
  694. var startSize = possibleCenters.length;
  695. if (startSize < 3) {
  696. // Couldn't find enough finder patterns
  697. return null;
  698. }
  699. // Filter outlier possibilities whose module size is too different
  700. if (startSize > 3) {
  701. // But we can only afford to do so if we have at least 4 possibilities to choose from
  702. var totalModuleSize = 0;
  703. var square = 0;
  704. possibleCenters.forEach(function (center) {
  705. var size = center.estimatedModuleSize;
  706. totalModuleSize += size;
  707. square += size * size;
  708. });
  709. var average = totalModuleSize / startSize;
  710. var stdDev = Math.sqrt(square / startSize - average * average);
  711. //possibleCenters.Sort(new FurthestFromAverageComparator(average));
  712. possibleCenters.sort(function (x, y) {
  713. var dA = Math.abs(y.estimatedModuleSize - average);
  714. var dB = Math.abs(x.estimatedModuleSize - average);
  715. return dA < dB ? -1 : dA == dB ? 0 : 1;
  716. });
  717. var limit = Math.max(0.2 * average, stdDev);
  718. for (var i = 0; i < possibleCenters.length && possibleCenters.length > 3; i++) {
  719. var pattern = possibleCenters[i];
  720. if (Math.abs(pattern.estimatedModuleSize - average) > limit) {
  721. possibleCenters.splice(i, 1);
  722. ///possibleCenters.RemoveAt(i);
  723. i--;
  724. }
  725. }
  726. }
  727. if (possibleCenters.length > 3) {
  728. // Throw away all but those first size candidate points we found.
  729. var totalModuleSize = 0;
  730. possibleCenters.forEach(function (possibleCenter) {
  731. totalModuleSize += possibleCenter.estimatedModuleSize;
  732. });
  733. var average = totalModuleSize / possibleCenters.length;
  734. // possibleCenters.Sort(new CenterComparator(average));
  735. possibleCenters.sort(function (x, y) {
  736. if (y.count === x.count) {
  737. var dA = Math.abs(y.estimatedModuleSize - average);
  738. var dB = Math.abs(x.estimatedModuleSize - average);
  739. return dA < dB ? 1 : dA == dB ? 0 : -1;
  740. }
  741. return y.count - x.count;
  742. });
  743. //possibleCenters.subList(3, possibleCenters.Count).clear();
  744. ///possibleCenters = possibleCenters.GetRange(0, 3);
  745. possibleCenters = possibleCenters.slice(0, 3);
  746. }
  747. return [possibleCenters[0], possibleCenters[1], possibleCenters[2]];
  748. }
  749. var pureBarcode = false;
  750. var maxI = matrix.height;
  751. var maxJ = matrix.width;
  752. var iSkip = Math.floor((3 * maxI) / (4 * MAX_MODULES));
  753. if (iSkip < MIN_SKIP || false) {
  754. iSkip = MIN_SKIP;
  755. }
  756. var done = false;
  757. var stateCount = [0, 0, 0, 0, 0];
  758. for (var i = iSkip - 1; i < maxI && !done; i += iSkip) {
  759. stateCount = [0, 0, 0, 0, 0];
  760. var currentState = 0;
  761. for (var j = 0; j < maxJ; j++) {
  762. if (get(j, i)) {
  763. // Black pixel
  764. if ((currentState & 1) === 1) {
  765. currentState++;
  766. }
  767. stateCount[currentState]++;
  768. }
  769. else {
  770. // White pixel
  771. if ((currentState & 1) === 0) {
  772. // Counting black pixels
  773. if (currentState === 4) {
  774. // A winner?
  775. if (foundPatternCross(stateCount)) {
  776. // Yes
  777. var confirmed = handlePossibleCenter(stateCount, i, j, pureBarcode);
  778. if (confirmed) {
  779. // Start examining every other line. Checking each line turned out to be too
  780. // expensive and didn't improve performance.
  781. iSkip = 2;
  782. if (hasSkipped) {
  783. done = haveMultiplyConfirmedCenters();
  784. }
  785. else {
  786. var rowSkip = findRowSkip();
  787. if (rowSkip > stateCount[2]) {
  788. // Skip rows between row of lower confirmed center
  789. // and top of presumed third confirmed center
  790. // but back up a bit to get a full chance of detecting
  791. // it, entire width of center of finder pattern
  792. // Skip by rowSkip, but back off by stateCount[2] (size of last center
  793. // of pattern we saw) to be conservative, and also back off by iSkip which
  794. // is about to be re-added
  795. i += rowSkip - stateCount[2] - iSkip;
  796. j = maxJ - 1;
  797. }
  798. }
  799. }
  800. else {
  801. stateCount = [stateCount[2], stateCount[3], stateCount[4], 1, 0];
  802. currentState = 3;
  803. continue;
  804. }
  805. // Clear state to start looking again
  806. stateCount = [0, 0, 0, 0, 0];
  807. currentState = 0;
  808. }
  809. else {
  810. stateCount = [stateCount[2], stateCount[3], stateCount[4], 1, 0];
  811. currentState = 3;
  812. }
  813. }
  814. else {
  815. // Should I really have copy/pasted this fuckery?
  816. stateCount[++currentState]++;
  817. }
  818. }
  819. else {
  820. // Counting the white pixels
  821. stateCount[currentState]++;
  822. }
  823. }
  824. }
  825. if (foundPatternCross(stateCount)) {
  826. var confirmed = handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
  827. if (confirmed) {
  828. iSkip = stateCount[0];
  829. if (hasSkipped) {
  830. // Found a third one
  831. done = haveMultiplyConfirmedCenters();
  832. }
  833. }
  834. }
  835. }
  836. var patternInfo = selectBestPatterns();
  837. if (!patternInfo)
  838. return null;
  839. return ReorderFinderPattern(patternInfo);
  840. }
  841. exports.locate = locate;
  842. /***/ },
  843. /* 4 */
  844. /***/ function(module, exports, __webpack_require__) {
  845. "use strict";
  846. /// <reference path="../common/types.d.ts" />
  847. var alignment_finder_1 = __webpack_require__(5);
  848. var perspective_transform_1 = __webpack_require__(7);
  849. var version_1 = __webpack_require__(8);
  850. var bitmatrix_1 = __webpack_require__(2);
  851. var helpers_1 = __webpack_require__(6);
  852. function checkAndNudgePoints(width, height, points) {
  853. // Check and nudge points from start until we see some that are OK:
  854. var nudged = true;
  855. for (var offset = 0; offset < points.length && nudged; offset += 2) {
  856. var x = Math.floor(points[offset]);
  857. var y = Math.floor(points[offset + 1]);
  858. if (x < -1 || x > width || y < -1 || y > height) {
  859. throw new Error();
  860. }
  861. nudged = false;
  862. if (x == -1) {
  863. points[offset] = 0;
  864. nudged = true;
  865. }
  866. else if (x == width) {
  867. points[offset] = width - 1;
  868. nudged = true;
  869. }
  870. if (y == -1) {
  871. points[offset + 1] = 0;
  872. nudged = true;
  873. }
  874. else if (y == height) {
  875. points[offset + 1] = height - 1;
  876. nudged = true;
  877. }
  878. }
  879. // Check and nudge points from end:
  880. nudged = true;
  881. for (var offset = points.length - 2; offset >= 0 && nudged; offset -= 2) {
  882. var x = Math.floor(points[offset]);
  883. var y = Math.floor(points[offset + 1]);
  884. if (x < -1 || x > width || y < -1 || y > height) {
  885. throw new Error();
  886. }
  887. nudged = false;
  888. if (x == -1) {
  889. points[offset] = 0;
  890. nudged = true;
  891. }
  892. else if (x == width) {
  893. points[offset] = width - 1;
  894. nudged = true;
  895. }
  896. if (y == -1) {
  897. points[offset + 1] = 0;
  898. nudged = true;
  899. }
  900. else if (y == height) {
  901. points[offset + 1] = height - 1;
  902. nudged = true;
  903. }
  904. }
  905. return points;
  906. }
  907. function bitArrayFromImage(image, dimension, transform) {
  908. if (dimension <= 0) {
  909. return null;
  910. }
  911. var bits = bitmatrix_1.BitMatrix.createEmpty(dimension, dimension);
  912. var points = new Array(dimension << 1);
  913. for (var y = 0; y < dimension; y++) {
  914. var max = points.length;
  915. var iValue = y + 0.5;
  916. for (var x = 0; x < max; x += 2) {
  917. points[x] = (x >> 1) + 0.5;
  918. points[x + 1] = iValue;
  919. }
  920. points = perspective_transform_1.transformPoints(transform, points);
  921. // Quick check to see if points transformed to something inside the image;
  922. // sufficient to check the endpoints
  923. try {
  924. var nudgedPoints = checkAndNudgePoints(image.width, image.height, points);
  925. }
  926. catch (e) {
  927. return null;
  928. }
  929. // try {
  930. for (var x = 0; x < max; x += 2) {
  931. bits.set(x >> 1, y, image.get(Math.floor(nudgedPoints[x]), Math.floor(nudgedPoints[x + 1])));
  932. }
  933. }
  934. return bits;
  935. }
  936. function createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension) {
  937. var dimMinusThree = dimension - 3.5;
  938. var bottomRightX;
  939. var bottomRightY;
  940. var sourceBottomRightX;
  941. var sourceBottomRightY;
  942. if (alignmentPattern != null) {
  943. bottomRightX = alignmentPattern.x;
  944. bottomRightY = alignmentPattern.y;
  945. sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3;
  946. }
  947. else {
  948. // Don't have an alignment pattern, just make up the bottom-right point
  949. bottomRightX = (topRight.x - topLeft.x) + bottomLeft.x;
  950. bottomRightY = (topRight.y - topLeft.y) + bottomLeft.y;
  951. sourceBottomRightX = sourceBottomRightY = dimMinusThree;
  952. }
  953. return perspective_transform_1.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.x, topLeft.y, topRight.x, topRight.y, bottomRightX, bottomRightY, bottomLeft.x, bottomLeft.y);
  954. }
  955. // Taken from 6th grade algebra
  956. function distance(x1, y1, x2, y2) {
  957. return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  958. }
  959. // Attempts to locate an alignment pattern in a limited region of the image, which is guessed to contain it.
  960. // overallEstModuleSize - estimated module size so far
  961. // estAlignmentX - coordinate of center of area probably containing alignment pattern
  962. // estAlignmentY - y coordinate of above</param>
  963. // allowanceFactor - number of pixels in all directions to search from the center</param>
  964. function findAlignmentInRegion(overallEstModuleSize, estAlignmentX, estAlignmentY, allowanceFactor, image) {
  965. estAlignmentX = Math.floor(estAlignmentX);
  966. estAlignmentY = Math.floor(estAlignmentY);
  967. // Look for an alignment pattern (3 modules in size) around where it should be
  968. var allowance = Math.floor(allowanceFactor * overallEstModuleSize);
  969. var alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
  970. var alignmentAreaRightX = Math.min(image.width, estAlignmentX + allowance);
  971. if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) {
  972. return null;
  973. }
  974. var alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
  975. var alignmentAreaBottomY = Math.min(image.height - 1, estAlignmentY + allowance);
  976. return alignment_finder_1.findAlignment(alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, image);
  977. }
  978. // Computes the dimension (number of modules on a size) of the QR Code based on the position of the finder
  979. // patterns and estimated module size.
  980. function computeDimension(topLeft, topRight, bottomLeft, moduleSize) {
  981. var tltrCentersDimension = Math.round(distance(topLeft.x, topLeft.y, topRight.x, topRight.y) / moduleSize);
  982. var tlblCentersDimension = Math.round(distance(topLeft.x, topLeft.y, bottomLeft.x, bottomLeft.y) / moduleSize);
  983. var dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7;
  984. switch (dimension & 0x03) {
  985. // mod 4
  986. case 0:
  987. dimension++;
  988. break;
  989. // 1? do nothing
  990. case 2:
  991. dimension--;
  992. break;
  993. }
  994. return dimension;
  995. }
  996. // Deduces version information purely from QR Code dimensions.
  997. // http://chan.catiewayne.com/z/src/131044167276.jpg
  998. function getProvisionalVersionForDimension(dimension) {
  999. if (dimension % 4 != 1) {
  1000. return null;
  1001. }
  1002. var versionNumber = (dimension - 17) >> 2;
  1003. if (versionNumber < 1 || versionNumber > 40) {
  1004. return null;
  1005. }
  1006. return version_1.getVersionForNumber(versionNumber);
  1007. }
  1008. // This method traces a line from a point in the image, in the direction towards another point.
  1009. // It begins in a black region, and keeps going until it finds white, then black, then white again.
  1010. // It reports the distance from the start to this point.</p>
  1011. //
  1012. // This is used when figuring out how wide a finder pattern is, when the finder pattern
  1013. // may be skewed or rotated.
  1014. function sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY, image) {
  1015. fromX = Math.floor(fromX);
  1016. fromY = Math.floor(fromY);
  1017. toX = Math.floor(toX);
  1018. toY = Math.floor(toY);
  1019. // Mild variant of Bresenham's algorithm;
  1020. // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
  1021. var steep = Math.abs(toY - fromY) > Math.abs(toX - fromX);
  1022. if (steep) {
  1023. var temp = fromX;
  1024. fromX = fromY;
  1025. fromY = temp;
  1026. temp = toX;
  1027. toX = toY;
  1028. toY = temp;
  1029. }
  1030. var dx = Math.abs(toX - fromX);
  1031. var dy = Math.abs(toY - fromY);
  1032. var error = -dx >> 1;
  1033. var xstep = fromX < toX ? 1 : -1;
  1034. var ystep = fromY < toY ? 1 : -1;
  1035. // In black pixels, looking for white, first or second time.
  1036. var state = 0;
  1037. // Loop up until x == toX, but not beyond
  1038. var xLimit = toX + xstep;
  1039. for (var x = fromX, y = fromY; x != xLimit; x += xstep) {
  1040. var realX = steep ? y : x;
  1041. var realY = steep ? x : y;
  1042. // Does current pixel mean we have moved white to black or vice versa?
  1043. // Scanning black in state 0,2 and white in state 1, so if we find the wrong
  1044. // color, advance to next state or end if we are in state 2 already
  1045. if ((state == 1) === image.get(realX, realY)) {
  1046. if (state == 2) {
  1047. return distance(x, y, fromX, fromY);
  1048. }
  1049. state++;
  1050. }
  1051. error += dy;
  1052. if (error > 0) {
  1053. if (y == toY) {
  1054. break;
  1055. }
  1056. y += ystep;
  1057. error -= dx;
  1058. }
  1059. }
  1060. // Found black-white-black; give the benefit of the doubt that the next pixel outside the image
  1061. // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a
  1062. // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this.
  1063. if (state == 2) {
  1064. return distance(toX + xstep, toY, fromX, fromY);
  1065. }
  1066. // else we didn't find even black-white-black; no estimate is really possible
  1067. return NaN;
  1068. }
  1069. // Computes the total width of a finder pattern by looking for a black-white-black run from the center
  1070. // in the direction of another point (another finder pattern center), and in the opposite direction too.
  1071. function sizeOfBlackWhiteBlackRunBothWays(fromX, fromY, toX, toY, image) {
  1072. var result = sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY, image);
  1073. // Now count other way -- don't run off image though of course
  1074. var scale = 1;
  1075. var otherToX = fromX - (toX - fromX);
  1076. if (otherToX < 0) {
  1077. scale = fromX / (fromX - otherToX);
  1078. otherToX = 0;
  1079. }
  1080. else if (otherToX >= image.width) {
  1081. scale = (image.width - 1 - fromX) / (otherToX - fromX);
  1082. otherToX = image.width - 1;
  1083. }
  1084. var otherToY = (fromY - (toY - fromY) * scale);
  1085. scale = 1;
  1086. if (otherToY < 0) {
  1087. scale = fromY / (fromY - otherToY);
  1088. otherToY = 0;
  1089. }
  1090. else if (otherToY >= image.height) {
  1091. scale = (image.height - 1 - fromY) / (otherToY - fromY);
  1092. otherToY = image.height - 1;
  1093. }
  1094. otherToX = (fromX + (otherToX - fromX) * scale);
  1095. result += sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY, image);
  1096. return result - 1; // -1 because we counted the middle pixel twice
  1097. }
  1098. function calculateModuleSizeOneWay(pattern, otherPattern, image) {
  1099. var moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays(pattern.x, pattern.y, otherPattern.x, otherPattern.y, image);
  1100. var moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays(otherPattern.x, otherPattern.y, pattern.x, pattern.y, image);
  1101. if (helpers_1.isNaN(moduleSizeEst1)) {
  1102. return moduleSizeEst2 / 7;
  1103. }
  1104. if (helpers_1.isNaN(moduleSizeEst2)) {
  1105. return moduleSizeEst1 / 7;
  1106. }
  1107. // Average them, and divide by 7 since we've counted the width of 3 black modules,
  1108. // and 1 white and 1 black module on either side. Ergo, divide sum by 14.
  1109. return (moduleSizeEst1 + moduleSizeEst2) / 14;
  1110. }
  1111. // Computes an average estimated module size based on estimated derived from the positions of the three finder patterns.
  1112. function calculateModuleSize(topLeft, topRight, bottomLeft, image) {
  1113. return (calculateModuleSizeOneWay(topLeft, topRight, image) + calculateModuleSizeOneWay(topLeft, bottomLeft, image)) / 2;
  1114. }
  1115. function extract(image, location) {
  1116. var moduleSize = calculateModuleSize(location.topLeft, location.topRight, location.bottomLeft, image);
  1117. if (moduleSize < 1) {
  1118. return null;
  1119. }
  1120. var dimension = computeDimension(location.topLeft, location.topRight, location.bottomLeft, moduleSize);
  1121. if (!dimension) {
  1122. return null;
  1123. }
  1124. var provisionalVersion = getProvisionalVersionForDimension(dimension);
  1125. if (provisionalVersion == null) {
  1126. return null;
  1127. }
  1128. var modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7;
  1129. var alignmentPattern = null;
  1130. // Anything above version 1 has an alignment pattern
  1131. if (provisionalVersion.alignmentPatternCenters.length > 0) {
  1132. // Guess where a "bottom right" finder pattern would have been
  1133. var bottomRightX = location.topRight.x - location.topLeft.x + location.bottomLeft.x;
  1134. var bottomRightY = location.topRight.y - location.topLeft.y + location.bottomLeft.y;
  1135. // Estimate that alignment pattern is closer by 3 modules
  1136. // from "bottom right" to known top left location
  1137. var correctionToTopLeft = 1 - 3 / modulesBetweenFPCenters;
  1138. var estAlignmentX = location.topLeft.x + correctionToTopLeft * (bottomRightX - location.topLeft.x);
  1139. var estAlignmentY = location.topLeft.y + correctionToTopLeft * (bottomRightY - location.topLeft.y);
  1140. // Kind of arbitrary -- expand search radius before giving up
  1141. for (var i = 4; i <= 16; i <<= 1) {
  1142. alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i, image);
  1143. if (!alignmentPattern) {
  1144. continue;
  1145. }
  1146. break;
  1147. }
  1148. }
  1149. var transform = createTransform(location.topLeft, location.topRight, location.bottomLeft, alignmentPattern, dimension);
  1150. return bitArrayFromImage(image, dimension, transform);
  1151. }
  1152. exports.extract = extract;
  1153. /***/ },
  1154. /* 5 */
  1155. /***/ function(module, exports, __webpack_require__) {
  1156. "use strict";
  1157. var helpers_1 = __webpack_require__(6);
  1158. function aboutEquals(center, moduleSize, i, j) {
  1159. if (Math.abs(i - center.y) <= moduleSize && Math.abs(j - center.x) <= moduleSize) {
  1160. var moduleSizeDiff = Math.abs(moduleSize - center.estimatedModuleSize);
  1161. return moduleSizeDiff <= 1 || moduleSizeDiff <= center.estimatedModuleSize;
  1162. }
  1163. return false;
  1164. }
  1165. function combineEstimate(center, i, j, newModuleSize) {
  1166. var combinedX = (center.x + j) / 2;
  1167. var combinedY = (center.y + i) / 2;
  1168. var combinedModuleSize = (center.estimatedModuleSize + newModuleSize) / 2;
  1169. return { x: combinedX, y: combinedY, estimatedModuleSize: combinedModuleSize };
  1170. }
  1171. // returns true if the proportions of the counts is close enough to the 1/1/1 ratios used by alignment
  1172. // patterns to be considered a match
  1173. function foundPatternCross(stateCount, moduleSize) {
  1174. var maxVariance = moduleSize / 2;
  1175. for (var i = 0; i < 3; i++) {
  1176. if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) {
  1177. return false;
  1178. }
  1179. }
  1180. return true;
  1181. }
  1182. // Given a count of black/white/black pixels just seen and an end position,
  1183. // figures the location of the center of this black/white/black run.
  1184. function centerFromEnd(stateCount, end) {
  1185. var result = (end - stateCount[2]) - stateCount[1] / 2;
  1186. if (helpers_1.isNaN(result)) {
  1187. return null;
  1188. }
  1189. return result;
  1190. }
  1191. // After a horizontal scan finds a potential alignment pattern, this method
  1192. // "cross-checks" by scanning down vertically through the center of the possible
  1193. // alignment pattern to see if the same proportion is detected.</p>
  1194. //
  1195. // startI - row where an alignment pattern was detected</param>
  1196. // centerJ - center of the section that appears to cross an alignment pattern</param>
  1197. // maxCount - maximum reasonable number of modules that should be observed in any reading state, based
  1198. // on the results of the horizontal scan</param>
  1199. // originalStateCountTotal - The original state count total
  1200. function crossCheckVertical(startI, centerJ, maxCount, originalStateCountTotal, moduleSize, image) {
  1201. var maxI = image.height;
  1202. var stateCount = [0, 0, 0];
  1203. // Start counting up from center
  1204. var i = startI;
  1205. while (i >= 0 && image.get(centerJ, i) && stateCount[1] <= maxCount) {
  1206. stateCount[1]++;
  1207. i--;
  1208. }
  1209. // If already too many modules in this state or ran off the edge:
  1210. if (i < 0 || stateCount[1] > maxCount) {
  1211. return null;
  1212. }
  1213. while (i >= 0 && !image.get(centerJ, i) && stateCount[0] <= maxCount) {
  1214. stateCount[0]++;
  1215. i--;
  1216. }
  1217. if (stateCount[0] > maxCount) {
  1218. return null;
  1219. }
  1220. // Now also count down from center
  1221. i = startI + 1;
  1222. while (i < maxI && image.get(centerJ, i) && stateCount[1] <= maxCount) {
  1223. stateCount[1]++;
  1224. i++;
  1225. }
  1226. if (i == maxI || stateCount[1] > maxCount) {
  1227. return null;
  1228. }
  1229. while (i < maxI && !image.get(centerJ, i) && stateCount[2] <= maxCount) {
  1230. stateCount[2]++;
  1231. i++;
  1232. }
  1233. if (stateCount[2] > maxCount) {
  1234. return null;
  1235. }
  1236. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  1237. if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) {
  1238. return null;
  1239. }
  1240. return foundPatternCross(stateCount, moduleSize) ? centerFromEnd(stateCount, i) : null;
  1241. }
  1242. function findAlignment(startX, startY, width, height, moduleSize, image) {
  1243. // Global State :(
  1244. var possibleCenters = [];
  1245. // This is called when a horizontal scan finds a possible alignment pattern. It will
  1246. // cross check with a vertical scan, and if successful, will see if this pattern had been
  1247. // found on a previous horizontal scan. If so, we consider it confirmed and conclude we have
  1248. // found the alignment pattern.</p>
  1249. //
  1250. // stateCount - reading state module counts from horizontal scan
  1251. // i - where alignment pattern may be found
  1252. // j - end of possible alignment pattern in row
  1253. function handlePossibleCenter(stateCount, i, j, moduleSize) {
  1254. var stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2];
  1255. var centerJ = centerFromEnd(stateCount, j);
  1256. if (centerJ == null) {
  1257. return null;
  1258. }
  1259. var centerI = crossCheckVertical(i, Math.floor(centerJ), 2 * stateCount[1], stateCountTotal, moduleSize, image);
  1260. if (centerI != null) {
  1261. var estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3;
  1262. for (var i2 in possibleCenters) {
  1263. var center = possibleCenters[i2];
  1264. // Look for about the same center and module size:
  1265. if (aboutEquals(center, estimatedModuleSize, centerI, centerJ)) {
  1266. return combineEstimate(center, centerI, centerJ, estimatedModuleSize);
  1267. }
  1268. }
  1269. // Hadn't found this before; save it
  1270. var point = { x: centerJ, y: centerI, estimatedModuleSize: estimatedModuleSize };
  1271. possibleCenters.push(point);
  1272. }
  1273. return null;
  1274. }
  1275. var maxJ = startX + width;
  1276. var middleI = startY + (height >> 1);
  1277. // We are looking for black/white/black modules in 1:1:1 ratio;
  1278. // this tracks the number of black/white/black modules seen so far
  1279. var stateCount = [0, 0, 0]; // WTF
  1280. for (var iGen = 0; iGen < height; iGen++) {
  1281. // Search from middle outwards
  1282. var i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1));
  1283. stateCount[0] = 0;
  1284. stateCount[1] = 0;
  1285. stateCount[2] = 0;
  1286. var j = startX;
  1287. // Burn off leading white pixels before anything else; if we start in the middle of
  1288. // a white run, it doesn't make sense to count its length, since we don't know if the
  1289. // white run continued to the left of the start point
  1290. while (j < maxJ && !image.get(j, i)) {
  1291. j++;
  1292. }
  1293. var currentState = 0;
  1294. while (j < maxJ) {
  1295. if (image.get(j, i)) {
  1296. // Black pixel
  1297. if (currentState == 1) {
  1298. // Counting black pixels
  1299. stateCount[currentState]++;
  1300. }
  1301. else {
  1302. // Counting white pixels
  1303. if (currentState == 2) {
  1304. // A winner?
  1305. if (foundPatternCross(stateCount, moduleSize)) {
  1306. // Yes
  1307. confirmed = handlePossibleCenter(stateCount, i, j, moduleSize);
  1308. if (confirmed != null) {
  1309. return confirmed;
  1310. }
  1311. }
  1312. stateCount[0] = stateCount[2];
  1313. stateCount[1] = 1;
  1314. stateCount[2] = 0;
  1315. currentState = 1;
  1316. }
  1317. else {
  1318. stateCount[++currentState]++;
  1319. }
  1320. }
  1321. }
  1322. else {
  1323. // White pixel
  1324. if (currentState == 1) {
  1325. // Counting black pixels
  1326. currentState++;
  1327. }
  1328. stateCount[currentState]++;
  1329. }
  1330. j++;
  1331. }
  1332. if (foundPatternCross(stateCount, moduleSize)) {
  1333. var confirmed = handlePossibleCenter(stateCount, i, moduleSize, maxJ);
  1334. if (confirmed != null) {
  1335. return confirmed;
  1336. }
  1337. }
  1338. }
  1339. // Hmm, nothing we saw was observed and confirmed twice. If we had
  1340. // any guess at all, return it.
  1341. if (possibleCenters.length != 0) {
  1342. return possibleCenters[0];
  1343. }
  1344. return null;
  1345. }
  1346. exports.findAlignment = findAlignment;
  1347. /***/ },
  1348. /* 6 */
  1349. /***/ function(module, exports) {
  1350. "use strict";
  1351. var BITS_SET_IN_HALF_BYTE = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4];
  1352. function numBitsDiffering(a, b) {
  1353. a ^= b; // a now has a 1 bit exactly where its bit differs with b's
  1354. // Count bits set quickly with a series of lookups:
  1355. return BITS_SET_IN_HALF_BYTE[a & 0x0F] +
  1356. BITS_SET_IN_HALF_BYTE[((a >> 4) & 0x0F)] +
  1357. BITS_SET_IN_HALF_BYTE[((a >> 8) & 0x0F)] +
  1358. BITS_SET_IN_HALF_BYTE[((a >> 12) & 0x0F)] +
  1359. BITS_SET_IN_HALF_BYTE[((a >> 16) & 0x0F)] +
  1360. BITS_SET_IN_HALF_BYTE[((a >> 20) & 0x0F)] +
  1361. BITS_SET_IN_HALF_BYTE[((a >> 24) & 0x0F)] +
  1362. BITS_SET_IN_HALF_BYTE[((a >> 28) & 0x0F)];
  1363. }
  1364. exports.numBitsDiffering = numBitsDiffering;
  1365. // Taken from underscore JS
  1366. function isNaN(obj) {
  1367. return Object.prototype.toString.call(obj) === '[object Number]' && obj !== +obj;
  1368. }
  1369. exports.isNaN = isNaN;
  1370. /***/ },
  1371. /* 7 */
  1372. /***/ function(module, exports) {
  1373. /// <reference path="../common/types.d.ts" />
  1374. "use strict";
  1375. function squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3) {
  1376. var dx3 = x0 - x1 + x2 - x3;
  1377. var dy3 = y0 - y1 + y2 - y3;
  1378. if (dx3 == 0 && dy3 == 0) {
  1379. // Affine
  1380. return {
  1381. a11: x1 - x0,
  1382. a21: x2 - x1,
  1383. a31: x0,
  1384. a12: y1 - y0,
  1385. a22: y2 - y1,
  1386. a32: y0,
  1387. a13: 0,
  1388. a23: 0,
  1389. a33: 1
  1390. };
  1391. }
  1392. else {
  1393. var dx1 = x1 - x2;
  1394. var dx2 = x3 - x2;
  1395. var dy1 = y1 - y2;
  1396. var dy2 = y3 - y2;
  1397. var denominator = dx1 * dy2 - dx2 * dy1;
  1398. var a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
  1399. var a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
  1400. return {
  1401. a11: x1 - x0 + a13 * x1,
  1402. a21: x3 - x0 + a23 * x3,
  1403. a31: x0,
  1404. a12: y1 - y0 + a13 * y1,
  1405. a22: y3 - y0 + a23 * y3,
  1406. a32: y0,
  1407. a13: a13,
  1408. a23: a23,
  1409. a33: 1
  1410. };
  1411. }
  1412. }
  1413. function buildAdjoint(i) {
  1414. return {
  1415. a11: i.a22 * i.a33 - i.a23 * i.a32,
  1416. a21: i.a23 * i.a31 - i.a21 * i.a33,
  1417. a31: i.a21 * i.a32 - i.a22 * i.a31,
  1418. a12: i.a13 * i.a32 - i.a12 * i.a33,
  1419. a22: i.a11 * i.a33 - i.a13 * i.a31,
  1420. a32: i.a12 * i.a31 - i.a11 * i.a32,
  1421. a13: i.a12 * i.a23 - i.a13 * i.a22,
  1422. a23: i.a13 * i.a21 - i.a11 * i.a23,
  1423. a33: i.a11 * i.a22 - i.a12 * i.a21
  1424. };
  1425. }
  1426. function times(a, b) {
  1427. return {
  1428. a11: a.a11 * b.a11 + a.a21 * b.a12 + a.a31 * b.a13,
  1429. a21: a.a11 * b.a21 + a.a21 * b.a22 + a.a31 * b.a23,
  1430. a31: a.a11 * b.a31 + a.a21 * b.a32 + a.a31 * b.a33,
  1431. a12: a.a12 * b.a11 + a.a22 * b.a12 + a.a32 * b.a13,
  1432. a22: a.a12 * b.a21 + a.a22 * b.a22 + a.a32 * b.a23,
  1433. a32: a.a12 * b.a31 + a.a22 * b.a32 + a.a32 * b.a33,
  1434. a13: a.a13 * b.a11 + a.a23 * b.a12 + a.a33 * b.a13,
  1435. a23: a.a13 * b.a21 + a.a23 * b.a22 + a.a33 * b.a23,
  1436. a33: a.a13 * b.a31 + a.a23 * b.a32 + a.a33 * b.a33
  1437. };
  1438. }
  1439. function quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3) {
  1440. // Here, the adjoint serves as the inverse:
  1441. return buildAdjoint(squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3));
  1442. }
  1443. function transformPoints(transform, points) {
  1444. var max = points.length;
  1445. var a11 = transform.a11;
  1446. var a12 = transform.a12;
  1447. var a13 = transform.a13;
  1448. var a21 = transform.a21;
  1449. var a22 = transform.a22;
  1450. var a23 = transform.a23;
  1451. var a31 = transform.a31;
  1452. var a32 = transform.a32;
  1453. var a33 = transform.a33;
  1454. for (var i = 0; i < max; i += 2) {
  1455. var x = points[i];
  1456. var y = points[i + 1];
  1457. var denominator = a13 * x + a23 * y + a33;
  1458. points[i] = (a11 * x + a21 * y + a31) / denominator;
  1459. points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
  1460. }
  1461. return points;
  1462. }
  1463. exports.transformPoints = transformPoints;
  1464. function quadrilateralToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p) {
  1465. var qToS = quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  1466. var sToQ = squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  1467. return times(sToQ, qToS);
  1468. }
  1469. exports.quadrilateralToQuadrilateral = quadrilateralToQuadrilateral;
  1470. /***/ },
  1471. /* 8 */
  1472. /***/ function(module, exports, __webpack_require__) {
  1473. "use strict";
  1474. var helpers_1 = __webpack_require__(6);
  1475. var VERSION_DECODE_INFO = [
  1476. 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
  1477. 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
  1478. 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
  1479. 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
  1480. 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
  1481. 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
  1482. 0x2542E, 0x26A64, 0x27541, 0x28C69,
  1483. ];
  1484. var ECB = (function () {
  1485. function ECB(_count, _dataCodewords) {
  1486. this.count = _count;
  1487. this.dataCodewords = _dataCodewords;
  1488. }
  1489. return ECB;
  1490. }());
  1491. var ECBlocks = (function () {
  1492. function ECBlocks(_ecCodewordsPerBlock) {
  1493. var _ecBlocks = [];
  1494. for (var _i = 1; _i < arguments.length; _i++) {
  1495. _ecBlocks[_i - 1] = arguments[_i];
  1496. }
  1497. this.ecCodewordsPerBlock = _ecCodewordsPerBlock;
  1498. this.ecBlocks = _ecBlocks;
  1499. }
  1500. ECBlocks.prototype.getNumBlocks = function () {
  1501. return this.ecBlocks.reduce(function (a, b) { return (a + b.count); }, 0);
  1502. };
  1503. ECBlocks.prototype.getTotalECCodewords = function () {
  1504. return this.ecCodewordsPerBlock * this.getNumBlocks();
  1505. };
  1506. return ECBlocks;
  1507. }());
  1508. var Version = (function () {
  1509. function Version(_versionNumber, _alignmentPatternCenters) {
  1510. var _ecBlocks = [];
  1511. for (var _i = 2; _i < arguments.length; _i++) {
  1512. _ecBlocks[_i - 2] = arguments[_i];
  1513. }
  1514. this.versionNumber = _versionNumber;
  1515. this.alignmentPatternCenters = _alignmentPatternCenters;
  1516. this.ecBlocks = _ecBlocks;
  1517. var total = 0;
  1518. var ecCodewords = this.ecBlocks[0].ecCodewordsPerBlock;
  1519. var ecbArray = this.ecBlocks[0].ecBlocks;
  1520. ecbArray.forEach(function (ecBlock) {
  1521. total += ecBlock.count * (ecBlock.dataCodewords + ecCodewords);
  1522. });
  1523. this.totalCodewords = total;
  1524. }
  1525. Version.prototype.getDimensionForVersion = function () {
  1526. return 17 + 4 * this.versionNumber;
  1527. };
  1528. Version.prototype.getECBlocksForLevel = function (ecLevel) {
  1529. return this.ecBlocks[ecLevel.ordinal];
  1530. };
  1531. Version.decodeVersionInformation = function (versionBits) {
  1532. var bestDifference = Infinity;
  1533. var bestVersion = 0;
  1534. for (var i = 0; i < VERSION_DECODE_INFO.length; i++) {
  1535. var targetVersion = VERSION_DECODE_INFO[i];
  1536. // Do the version info bits match exactly? done.
  1537. if (targetVersion == versionBits) {
  1538. return getVersionForNumber(i + 7);
  1539. }
  1540. // Otherwise see if this is the closest to a real version info bit string
  1541. // we have seen so far
  1542. var bitsDifference = helpers_1.numBitsDiffering(versionBits, targetVersion);
  1543. if (bitsDifference < bestDifference) {
  1544. bestVersion = i + 7;
  1545. bestDifference = bitsDifference;
  1546. }
  1547. }
  1548. // We can tolerate up to 3 bits of error since no two version info codewords will
  1549. // differ in less than 8 bits.
  1550. if (bestDifference <= 3) {
  1551. return getVersionForNumber(bestVersion);
  1552. }
  1553. // If we didn't find a close enough match, fail
  1554. return null;
  1555. };
  1556. return Version;
  1557. }());
  1558. exports.Version = Version;
  1559. var VERSIONS = [
  1560. new Version(1, [], new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))),
  1561. new Version(2, [6, 18], new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))),
  1562. new Version(3, [6, 22], new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))),
  1563. new Version(4, [6, 26], new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))),
  1564. new Version(5, [6, 30], new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))),
  1565. new Version(6, [6, 34], new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))),
  1566. new Version(7, [6, 22, 38], new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))),
  1567. new Version(8, [6, 24, 42], new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))),
  1568. new Version(9, [6, 26, 46], new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))),
  1569. new Version(10, [6, 28, 50], new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))),
  1570. new Version(11, [6, 30, 54], new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))),
  1571. new Version(12, [6, 32, 58], new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))),
  1572. new Version(13, [6, 34, 62], new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))),
  1573. new Version(14, [6, 26, 46, 66], new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))),
  1574. new Version(15, [6, 26, 48, 70], new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))),
  1575. new Version(16, [6, 26, 50, 74], new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))),
  1576. new Version(17, [6, 30, 54, 78], new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))),
  1577. new Version(18, [6, 30, 56, 82], new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))),
  1578. new Version(19, [6, 30, 58, 86], new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))),
  1579. new Version(20, [6, 34, 62, 90], new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))),
  1580. new Version(21, [6, 28, 50, 72, 94], new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))),
  1581. new Version(22, [6, 26, 50, 74, 98], new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))),
  1582. new Version(23, [6, 30, 54, 74, 102], new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))),
  1583. new Version(24, [6, 28, 54, 80, 106], new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))),
  1584. new Version(25, [6, 32, 58, 84, 110], new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))),
  1585. new Version(26, [6, 30, 58, 86, 114], new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))),
  1586. new Version(27, [6, 34, 62, 90, 118], new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))),
  1587. new Version(28, [6, 26, 50, 74, 98, 122], new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))),
  1588. new Version(29, [6, 30, 54, 78, 102, 126], new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))),
  1589. new Version(30, [6, 26, 52, 78, 104, 130], new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))),
  1590. new Version(31, [6, 30, 56, 82, 108, 134], new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))),
  1591. new Version(32, [6, 34, 60, 86, 112, 138], new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))),
  1592. new Version(33, [6, 30, 58, 86, 114, 142], new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))),
  1593. new Version(34, [6, 34, 62, 90, 118, 146], new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))),
  1594. new Version(35, [6, 30, 54, 78, 102, 126, 150], new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))),
  1595. new Version(36, [6, 24, 50, 76, 102, 128, 154], new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))),
  1596. new Version(37, [6, 28, 54, 80, 106, 132, 158], new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))),
  1597. new Version(38, [6, 32, 58, 84, 110, 136, 162], new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))),
  1598. new Version(39, [6, 26, 54, 82, 110, 138, 166], new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))),
  1599. new Version(40, [6, 30, 58, 86, 114, 142, 170], new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16))),
  1600. ];
  1601. function getVersionForNumber(versionNumber) {
  1602. if (versionNumber < 1 || versionNumber > 40) {
  1603. throw new Error("Invalid version number " + versionNumber);
  1604. }
  1605. return VERSIONS[versionNumber - 1];
  1606. }
  1607. exports.getVersionForNumber = getVersionForNumber;
  1608. /***/ },
  1609. /* 9 */
  1610. /***/ function(module, exports, __webpack_require__) {
  1611. "use strict";
  1612. var bitmatrix_1 = __webpack_require__(2);
  1613. var decodeqrdata_1 = __webpack_require__(10);
  1614. var helpers_1 = __webpack_require__(6);
  1615. var reedsolomon_1 = __webpack_require__(12);
  1616. var version_1 = __webpack_require__(8);
  1617. var FORMAT_INFO_MASK_QR = 0x5412;
  1618. var FORMAT_INFO_DECODE_LOOKUP = [
  1619. [0x5412, 0x00],
  1620. [0x5125, 0x01],
  1621. [0x5E7C, 0x02],
  1622. [0x5B4B, 0x03],
  1623. [0x45F9, 0x04],
  1624. [0x40CE, 0x05],
  1625. [0x4F97, 0x06],
  1626. [0x4AA0, 0x07],
  1627. [0x77C4, 0x08],
  1628. [0x72F3, 0x09],
  1629. [0x7DAA, 0x0A],
  1630. [0x789D, 0x0B],
  1631. [0x662F, 0x0C],
  1632. [0x6318, 0x0D],
  1633. [0x6C41, 0x0E],
  1634. [0x6976, 0x0F],
  1635. [0x1689, 0x10],
  1636. [0x13BE, 0x11],
  1637. [0x1CE7, 0x12],
  1638. [0x19D0, 0x13],
  1639. [0x0762, 0x14],
  1640. [0x0255, 0x15],
  1641. [0x0D0C, 0x16],
  1642. [0x083B, 0x17],
  1643. [0x355F, 0x18],
  1644. [0x3068, 0x19],
  1645. [0x3F31, 0x1A],
  1646. [0x3A06, 0x1B],
  1647. [0x24B4, 0x1C],
  1648. [0x2183, 0x1D],
  1649. [0x2EDA, 0x1E],
  1650. [0x2BED, 0x1F],
  1651. ];
  1652. var DATA_MASKS = [
  1653. function (i, j) { return ((i + j) & 0x01) === 0; },
  1654. function (i, j) { return (i & 0x01) === 0; },
  1655. function (i, j) { return j % 3 == 0; },
  1656. function (i, j) { return (i + j) % 3 === 0; },
  1657. function (i, j) { return (((i >> 1) + (j / 3)) & 0x01) === 0; },
  1658. function (i, j) { return ((i * j) & 0x01) + ((i * j) % 3) === 0; },
  1659. function (i, j) { return ((((i * j) & 0x01) + ((i * j) % 3)) & 0x01) === 0; },
  1660. function (i, j) { return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) === 0; },
  1661. ];
  1662. var ERROR_CORRECTION_LEVELS = [
  1663. { ordinal: 1, bits: 0x00, name: "M" },
  1664. { ordinal: 0, bits: 0x01, name: "L" },
  1665. { ordinal: 3, bits: 0x02, name: "H" },
  1666. { ordinal: 2, bits: 0x03, name: "Q" },
  1667. ];
  1668. function buildFunctionPattern(version) {
  1669. var dimension = version.getDimensionForVersion();
  1670. var emptyArray = new Array(dimension * dimension);
  1671. for (var i = 0; i < emptyArray.length; i++) {
  1672. emptyArray[i] = false;
  1673. }
  1674. var bitMatrix = new bitmatrix_1.BitMatrix(emptyArray, dimension);
  1675. ///BitMatrix bitMatrix = new BitMatrix(dimension);
  1676. // Top left finder pattern + separator + format
  1677. bitMatrix.setRegion(0, 0, 9, 9);
  1678. // Top right finder pattern + separator + format
  1679. bitMatrix.setRegion(dimension - 8, 0, 8, 9);
  1680. // Bottom left finder pattern + separator + format
  1681. bitMatrix.setRegion(0, dimension - 8, 9, 8);
  1682. // Alignment patterns
  1683. var max = version.alignmentPatternCenters.length;
  1684. for (var x = 0; x < max; x++) {
  1685. var i = version.alignmentPatternCenters[x] - 2;
  1686. for (var y = 0; y < max; y++) {
  1687. if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
  1688. // No alignment patterns near the three finder paterns
  1689. continue;
  1690. }
  1691. bitMatrix.setRegion(version.alignmentPatternCenters[y] - 2, i, 5, 5);
  1692. }
  1693. }
  1694. // Vertical timing pattern
  1695. bitMatrix.setRegion(6, 9, 1, dimension - 17);
  1696. // Horizontal timing pattern
  1697. bitMatrix.setRegion(9, 6, dimension - 17, 1);
  1698. if (version.versionNumber > 6) {
  1699. // Version info, top right
  1700. bitMatrix.setRegion(dimension - 11, 0, 3, 6);
  1701. // Version info, bottom left
  1702. bitMatrix.setRegion(0, dimension - 11, 6, 3);
  1703. }
  1704. return bitMatrix;
  1705. }
  1706. function readCodewords(matrix, version, formatInfo) {
  1707. // Get the data mask for the format used in this QR Code. This will exclude
  1708. // some bits from reading as we wind through the bit matrix.
  1709. var dataMask = DATA_MASKS[formatInfo.dataMask];
  1710. var dimension = matrix.height;
  1711. var funcPattern = buildFunctionPattern(version);
  1712. var readingUp = true;
  1713. var result = [];
  1714. var resultOffset = 0;
  1715. var currentByte = 0;
  1716. var bitsRead = 0;
  1717. // Read columns in pairs, from right to left
  1718. for (var j = dimension - 1; j > 0; j -= 2) {
  1719. if (j == 6) {
  1720. // Skip whole column with vertical alignment pattern;
  1721. // saves time and makes the other code proceed more cleanly
  1722. j--;
  1723. }
  1724. // Read alternatingly from bottom to top then top to bottom
  1725. for (var count = 0; count < dimension; count++) {
  1726. var i = readingUp ? dimension - 1 - count : count;
  1727. for (var col = 0; col < 2; col++) {
  1728. // Ignore bits covered by the function pattern
  1729. if (!funcPattern.get(j - col, i)) {
  1730. // Read a bit
  1731. bitsRead++;
  1732. currentByte <<= 1;
  1733. if (matrix.get(j - col, i) !== dataMask(i, j - col)) {
  1734. currentByte |= 1;
  1735. }
  1736. // If we've made a whole byte, save it off
  1737. if (bitsRead == 8) {
  1738. result[resultOffset++] = currentByte & 0xFF;
  1739. bitsRead = 0;
  1740. currentByte = 0;
  1741. }
  1742. }
  1743. }
  1744. }
  1745. readingUp = !readingUp; // switch directions
  1746. }
  1747. if (resultOffset != version.totalCodewords) {
  1748. return null;
  1749. }
  1750. return result;
  1751. }
  1752. function readVersion(matrix) {
  1753. var dimension = matrix.height;
  1754. var provisionalVersion = (dimension - 17) >> 2;
  1755. if (provisionalVersion <= 6) {
  1756. return version_1.getVersionForNumber(provisionalVersion);
  1757. }
  1758. // Read top-right version info: 3 wide by 6 tall
  1759. var versionBits = 0;
  1760. var ijMin = dimension - 11;
  1761. for (var j = 5; j >= 0; j--) {
  1762. for (var i = dimension - 9; i >= ijMin; i--) {
  1763. versionBits = matrix.copyBit(i, j, versionBits);
  1764. }
  1765. }
  1766. var parsedVersion = version_1.Version.decodeVersionInformation(versionBits);
  1767. if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) {
  1768. return parsedVersion;
  1769. }
  1770. // Hmm, failed. Try bottom left: 6 wide by 3 tall
  1771. versionBits = 0;
  1772. for (var i = 5; i >= 0; i--) {
  1773. for (var j = dimension - 9; j >= ijMin; j--) {
  1774. versionBits = matrix.copyBit(i, j, versionBits);
  1775. }
  1776. }
  1777. parsedVersion = version_1.Version.decodeVersionInformation(versionBits);
  1778. if (parsedVersion != null && parsedVersion.getDimensionForVersion() == dimension) {
  1779. return parsedVersion;
  1780. }
  1781. return null;
  1782. }
  1783. function newFormatInformation(formatInfo) {
  1784. return {
  1785. errorCorrectionLevel: ERROR_CORRECTION_LEVELS[(formatInfo >> 3) & 0x03],
  1786. dataMask: formatInfo & 0x07
  1787. };
  1788. }
  1789. function doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2) {
  1790. // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
  1791. var bestDifference = Infinity;
  1792. var bestFormatInfo = 0;
  1793. for (var i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
  1794. var decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
  1795. var targetInfo = decodeInfo[0];
  1796. if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) {
  1797. // Found an exact match
  1798. return newFormatInformation(decodeInfo[1]);
  1799. }
  1800. var bitsDifference = helpers_1.numBitsDiffering(maskedFormatInfo1, targetInfo);
  1801. if (bitsDifference < bestDifference) {
  1802. bestFormatInfo = decodeInfo[1];
  1803. bestDifference = bitsDifference;
  1804. }
  1805. if (maskedFormatInfo1 != maskedFormatInfo2) {
  1806. // also try the other option
  1807. bitsDifference = helpers_1.numBitsDiffering(maskedFormatInfo2, targetInfo);
  1808. if (bitsDifference < bestDifference) {
  1809. bestFormatInfo = decodeInfo[1];
  1810. bestDifference = bitsDifference;
  1811. }
  1812. }
  1813. }
  1814. // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
  1815. // differing means we found a match
  1816. if (bestDifference <= 3)
  1817. return newFormatInformation(bestFormatInfo);
  1818. return null;
  1819. }
  1820. function decodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2) {
  1821. var formatInfo = doDecodeFormatInformation(maskedFormatInfo1, maskedFormatInfo2);
  1822. if (formatInfo) {
  1823. return formatInfo;
  1824. }
  1825. // Should return null, but, some QR codes apparently
  1826. // do not mask this info. Try again by actually masking the pattern
  1827. // first
  1828. return doDecodeFormatInformation(maskedFormatInfo1 ^ FORMAT_INFO_MASK_QR, maskedFormatInfo2 ^ FORMAT_INFO_MASK_QR);
  1829. }
  1830. function readFormatInformation(matrix) {
  1831. // Read top-left format info bits
  1832. var formatInfoBits1 = 0;
  1833. for (var i = 0; i < 6; i++) {
  1834. formatInfoBits1 = matrix.copyBit(i, 8, formatInfoBits1);
  1835. }
  1836. // .. and skip a bit in the timing pattern ...
  1837. formatInfoBits1 = matrix.copyBit(7, 8, formatInfoBits1);
  1838. formatInfoBits1 = matrix.copyBit(8, 8, formatInfoBits1);
  1839. formatInfoBits1 = matrix.copyBit(8, 7, formatInfoBits1);
  1840. // .. and skip a bit in the timing pattern ...
  1841. for (var j = 5; j >= 0; j--) {
  1842. formatInfoBits1 = matrix.copyBit(8, j, formatInfoBits1);
  1843. }
  1844. // Read the top-right/bottom-left pattern too
  1845. var dimension = matrix.height;
  1846. var formatInfoBits2 = 0;
  1847. var jMin = dimension - 7;
  1848. for (var j = dimension - 1; j >= jMin; j--) {
  1849. formatInfoBits2 = matrix.copyBit(8, j, formatInfoBits2);
  1850. }
  1851. for (var i = dimension - 8; i < dimension; i++) {
  1852. formatInfoBits2 = matrix.copyBit(i, 8, formatInfoBits2);
  1853. }
  1854. // parsedFormatInfo = FormatInformation.decodeFormatInformation(formatInfoBits1, formatInfoBits2);
  1855. var parsedFormatInfo = decodeFormatInformation(formatInfoBits1, formatInfoBits2);
  1856. if (parsedFormatInfo != null) {
  1857. return parsedFormatInfo;
  1858. }
  1859. return null;
  1860. }
  1861. function getDataBlocks(rawCodewords, version, ecLevel) {
  1862. if (rawCodewords.length != version.totalCodewords) {
  1863. throw new Error("Invalid number of codewords for version; got " + rawCodewords.length + " expected " + version.totalCodewords);
  1864. }
  1865. // Figure out the number and size of data blocks used by this version and
  1866. // error correction level
  1867. var ecBlocks = version.getECBlocksForLevel(ecLevel);
  1868. // First count the total number of data blocks
  1869. var totalBlocks = 0;
  1870. var ecBlockArray = ecBlocks.ecBlocks;
  1871. ecBlockArray.forEach(function (ecBlock) {
  1872. totalBlocks += ecBlock.count;
  1873. });
  1874. // Now establish DataBlocks of the appropriate size and number of data codewords
  1875. var result = new Array(totalBlocks);
  1876. var numResultBlocks = 0;
  1877. ecBlockArray.forEach(function (ecBlock) {
  1878. for (var i = 0; i < ecBlock.count; i++) {
  1879. var numDataCodewords = ecBlock.dataCodewords;
  1880. var numBlockCodewords = ecBlocks.ecCodewordsPerBlock + numDataCodewords;
  1881. result[numResultBlocks++] = { numDataCodewords: numDataCodewords, codewords: new Array(numBlockCodewords) };
  1882. }
  1883. });
  1884. // All blocks have the same amount of data, except that the last n
  1885. // (where n may be 0) have 1 more byte. Figure out where these start.
  1886. var shorterBlocksTotalCodewords = result[0].codewords.length;
  1887. var longerBlocksStartAt = result.length - 1;
  1888. while (longerBlocksStartAt >= 0) {
  1889. var numCodewords = result[longerBlocksStartAt].codewords.length;
  1890. if (numCodewords == shorterBlocksTotalCodewords) {
  1891. break;
  1892. }
  1893. longerBlocksStartAt--;
  1894. }
  1895. longerBlocksStartAt++;
  1896. var shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ecCodewordsPerBlock;
  1897. // The last elements of result may be 1 element longer;
  1898. // first fill out as many elements as all of them have
  1899. var rawCodewordsOffset = 0;
  1900. for (var i = 0; i < shorterBlocksNumDataCodewords; i++) {
  1901. for (var j = 0; j < numResultBlocks; j++) {
  1902. result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
  1903. }
  1904. }
  1905. // Fill out the last data block in the longer ones
  1906. for (var j = longerBlocksStartAt; j < numResultBlocks; j++) {
  1907. result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
  1908. }
  1909. // Now add in error correction blocks
  1910. var max = result[0].codewords.length;
  1911. for (var i = shorterBlocksNumDataCodewords; i < max; i++) {
  1912. for (var j = 0; j < numResultBlocks; j++) {
  1913. var iOffset = j < longerBlocksStartAt ? i : i + 1;
  1914. result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
  1915. }
  1916. }
  1917. return result;
  1918. }
  1919. function correctErrors(codewordBytes, numDataCodewords) {
  1920. var rsDecoder = new reedsolomon_1.ReedSolomonDecoder();
  1921. var numCodewords = codewordBytes.length;
  1922. // First read into an array of ints
  1923. var codewordsInts = new Array(numCodewords);
  1924. for (var i = 0; i < numCodewords; i++) {
  1925. codewordsInts[i] = codewordBytes[i] & 0xFF;
  1926. }
  1927. var numECCodewords = codewordBytes.length - numDataCodewords;
  1928. if (!rsDecoder.decode(codewordsInts, numECCodewords))
  1929. return false;
  1930. // Copy back into array of bytes -- only need to worry about the bytes that were data
  1931. // We don't care about errors in the error-correction codewords
  1932. for (var i = 0; i < numDataCodewords; i++) {
  1933. codewordBytes[i] = codewordsInts[i];
  1934. }
  1935. return true;
  1936. }
  1937. function decodeMatrix(matrix) {
  1938. var version = readVersion(matrix);
  1939. if (!version) {
  1940. return null;
  1941. }
  1942. var formatInfo = readFormatInformation(matrix);
  1943. if (!formatInfo) {
  1944. return null;
  1945. }
  1946. var ecLevel = formatInfo.errorCorrectionLevel;
  1947. // Read codewords
  1948. var codewords = readCodewords(matrix, version, formatInfo);
  1949. if (!codewords) {
  1950. return null;
  1951. }
  1952. // Separate into data blocks
  1953. var dataBlocks = getDataBlocks(codewords, version, ecLevel);
  1954. // Count total number of data bytes
  1955. var totalBytes = 0;
  1956. dataBlocks.forEach(function (dataBlock) {
  1957. totalBytes += dataBlock.numDataCodewords;
  1958. });
  1959. var resultBytes = new Array(totalBytes);
  1960. var resultOffset = 0;
  1961. // Error-correct and copy data blocks together into a stream of bytes
  1962. for (var _i = 0, dataBlocks_1 = dataBlocks; _i < dataBlocks_1.length; _i++) {
  1963. var dataBlock = dataBlocks_1[_i];
  1964. var codewordBytes = dataBlock.codewords;
  1965. var numDataCodewords = dataBlock.numDataCodewords;
  1966. if (!correctErrors(codewordBytes, numDataCodewords))
  1967. return null;
  1968. for (var i = 0; i < numDataCodewords; i++) {
  1969. resultBytes[resultOffset++] = codewordBytes[i];
  1970. }
  1971. }
  1972. return decodeqrdata_1.decodeQRdata(resultBytes, version.versionNumber, ecLevel.name);
  1973. }
  1974. function decode(matrix) {
  1975. if (matrix == null) {
  1976. return null;
  1977. }
  1978. var result = decodeMatrix(matrix);
  1979. if (result) {
  1980. return result;
  1981. }
  1982. // Decoding didn't work, try mirroring the QR
  1983. matrix.mirror();
  1984. return decodeMatrix(matrix);
  1985. }
  1986. exports.decode = decode;
  1987. /***/ },
  1988. /* 10 */
  1989. /***/ function(module, exports, __webpack_require__) {
  1990. "use strict";
  1991. var bitstream_1 = __webpack_require__(11);
  1992. function toAlphaNumericByte(value) {
  1993. var ALPHANUMERIC_CHARS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
  1994. 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
  1995. 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  1996. ' ', '$', '%', '*', '+', '-', '.', '/', ':'];
  1997. if (value >= ALPHANUMERIC_CHARS.length) {
  1998. throw new Error("Could not decode alphanumeric char");
  1999. }
  2000. return ALPHANUMERIC_CHARS[value].charCodeAt(0);
  2001. }
  2002. var Mode = (function () {
  2003. function Mode(characterCountBitsForVersions, bits) {
  2004. this.characterCountBitsForVersions = characterCountBitsForVersions;
  2005. this.bits = bits;
  2006. }
  2007. Mode.prototype.getCharacterCountBits = function (version) {
  2008. if (this.characterCountBitsForVersions == null) {
  2009. throw new Error("Character count doesn't apply to this mode");
  2010. }
  2011. var offset;
  2012. if (version <= 9) {
  2013. offset = 0;
  2014. }
  2015. else if (version <= 26) {
  2016. offset = 1;
  2017. }
  2018. else {
  2019. offset = 2;
  2020. }
  2021. return this.characterCountBitsForVersions[offset];
  2022. };
  2023. return Mode;
  2024. }());
  2025. var TERMINATOR_MODE = new Mode([0, 0, 0], 0x00); // Not really a mod...
  2026. var NUMERIC_MODE = new Mode([10, 12, 14], 0x01);
  2027. var ALPHANUMERIC_MODE = new Mode([9, 11, 13], 0x02);
  2028. var STRUCTURED_APPEND_MODE = new Mode([0, 0, 0], 0x03); // Not supported
  2029. var BYTE_MODE = new Mode([8, 16, 16], 0x04);
  2030. var ECI_MODE = new Mode(null, 0x07); // character counts don't apply
  2031. var KANJI_MODE = new Mode([8, 10, 12], 0x08);
  2032. var FNC1_FIRST_POSITION_MODE = new Mode(null, 0x05);
  2033. var FNC1_SECOND_POSITION_MODE = new Mode(null, 0x09);
  2034. var HANZI_MODE = new Mode([8, 10, 12], 0x0D);
  2035. function modeForBits(bits) {
  2036. switch (bits) {
  2037. case 0x0:
  2038. return TERMINATOR_MODE;
  2039. case 0x1:
  2040. return NUMERIC_MODE;
  2041. case 0x2:
  2042. return ALPHANUMERIC_MODE;
  2043. case 0x3:
  2044. return STRUCTURED_APPEND_MODE;
  2045. case 0x4:
  2046. return BYTE_MODE;
  2047. case 0x5:
  2048. return FNC1_FIRST_POSITION_MODE;
  2049. case 0x7:
  2050. return ECI_MODE;
  2051. case 0x8:
  2052. return KANJI_MODE;
  2053. case 0x9:
  2054. return FNC1_SECOND_POSITION_MODE;
  2055. case 0xD:
  2056. // 0xD is defined in GBT 18284-2000, may not be supported in foreign country
  2057. return HANZI_MODE;
  2058. default:
  2059. throw new Error("Couldn't decode mode from byte array");
  2060. }
  2061. }
  2062. function parseECIValue(bits) {
  2063. var firstByte = bits.readBits(8);
  2064. if ((firstByte & 0x80) == 0) {
  2065. // just one byte
  2066. return firstByte & 0x7F;
  2067. }
  2068. if ((firstByte & 0xC0) == 0x80) {
  2069. // two bytes
  2070. var secondByte = bits.readBits(8);
  2071. return ((firstByte & 0x3F) << 8) | secondByte;
  2072. }
  2073. if ((firstByte & 0xE0) == 0xC0) {
  2074. // three bytes
  2075. var secondThirdBytes = bits.readBits(16);
  2076. return ((firstByte & 0x1F) << 16) | secondThirdBytes;
  2077. }
  2078. throw new Error("Bad ECI bits starting with byte " + firstByte);
  2079. }
  2080. function decodeHanziSegment(bits, result, count) {
  2081. // Don't crash trying to read more bits than we have available.
  2082. if (count * 13 > bits.available()) {
  2083. return false;
  2084. }
  2085. // Each character will require 2 bytes. Read the characters as 2-byte pairs
  2086. // and decode as GB2312 afterwards
  2087. var buffer = new Array(2 * count);
  2088. var offset = 0;
  2089. while (count > 0) {
  2090. // Each 13 bits encodes a 2-byte character
  2091. var twoBytes = bits.readBits(13);
  2092. var assembledTwoBytes = (Math.floor(twoBytes / 0x060) << 8) | (twoBytes % 0x060);
  2093. if (assembledTwoBytes < 0x003BF) {
  2094. // In the 0xA1A1 to 0xAAFE range
  2095. assembledTwoBytes += 0x0A1A1;
  2096. }
  2097. else {
  2098. // In the 0xB0A1 to 0xFAFE range
  2099. assembledTwoBytes += 0x0A6A1;
  2100. }
  2101. buffer[offset] = ((assembledTwoBytes >> 8) & 0xFF);
  2102. buffer[offset + 1] = (assembledTwoBytes & 0xFF);
  2103. offset += 2;
  2104. count--;
  2105. }
  2106. result.val = buffer;
  2107. return true;
  2108. }
  2109. function decodeNumericSegment(bits, result, count) {
  2110. // Read three digits at a time
  2111. while (count >= 3) {
  2112. // Each 10 bits encodes three digits
  2113. if (bits.available() < 10) {
  2114. return false;
  2115. }
  2116. var threeDigitsBits = bits.readBits(10);
  2117. if (threeDigitsBits >= 1000) {
  2118. return false;
  2119. }
  2120. result.val.push(toAlphaNumericByte(Math.floor(threeDigitsBits / 100)));
  2121. result.val.push(toAlphaNumericByte(Math.floor(threeDigitsBits / 10) % 10));
  2122. result.val.push(toAlphaNumericByte(threeDigitsBits % 10));
  2123. count -= 3;
  2124. }
  2125. if (count == 2) {
  2126. // Two digits left over to read, encoded in 7 bits
  2127. if (bits.available() < 7) {
  2128. return false;
  2129. }
  2130. var twoDigitsBits = bits.readBits(7);
  2131. if (twoDigitsBits >= 100) {
  2132. return false;
  2133. }
  2134. result.val.push(toAlphaNumericByte(Math.floor(twoDigitsBits / 10)));
  2135. result.val.push(toAlphaNumericByte(twoDigitsBits % 10));
  2136. }
  2137. else if (count == 1) {
  2138. // One digit left over to read
  2139. if (bits.available() < 4) {
  2140. return false;
  2141. }
  2142. var digitBits = bits.readBits(4);
  2143. if (digitBits >= 10) {
  2144. return false;
  2145. }
  2146. result.val.push(toAlphaNumericByte(digitBits));
  2147. }
  2148. return true;
  2149. }
  2150. function decodeAlphanumericSegment(bits, result, count, fc1InEffect) {
  2151. // Read two characters at a time
  2152. var start = result.val.length;
  2153. while (count > 1) {
  2154. if (bits.available() < 11) {
  2155. return false;
  2156. }
  2157. var nextTwoCharsBits = bits.readBits(11);
  2158. result.val.push(toAlphaNumericByte(Math.floor(nextTwoCharsBits / 45)));
  2159. result.val.push(toAlphaNumericByte(nextTwoCharsBits % 45));
  2160. count -= 2;
  2161. }
  2162. if (count == 1) {
  2163. // special case: one character left
  2164. if (bits.available() < 6) {
  2165. return false;
  2166. }
  2167. result.val.push(toAlphaNumericByte(bits.readBits(6)));
  2168. }
  2169. // See section 6.4.8.1, 6.4.8.2
  2170. if (fc1InEffect) {
  2171. // We need to massage the result a bit if in an FNC1 mode:
  2172. for (var i = start; i < result.val.length; i++) {
  2173. if (result.val[i] == '%'.charCodeAt(0)) {
  2174. if (i < result.val.length - 1 && result.val[i + 1] == '%'.charCodeAt(0)) {
  2175. // %% is rendered as %
  2176. result.val = result.val.slice(0, i + 1).concat(result.val.slice(i + 2));
  2177. }
  2178. else {
  2179. // In alpha mode, % should be converted to FNC1 separator 0x1D
  2180. // THIS IS ALMOST CERTAINLY INVALID
  2181. result.val[i] = 0x1D;
  2182. }
  2183. }
  2184. }
  2185. }
  2186. return true;
  2187. }
  2188. function decodeByteSegment(bits, result, count) {
  2189. // Don't crash trying to read more bits than we have available.
  2190. if (count << 3 > bits.available()) {
  2191. return false;
  2192. }
  2193. var readBytes = new Array(count);
  2194. for (var i = 0; i < count; i++) {
  2195. readBytes[i] = bits.readBits(8);
  2196. }
  2197. Array.prototype.push.apply(result.val, readBytes);
  2198. return true;
  2199. }
  2200. var GB2312_SUBSET = 1;
  2201. // Takes in a byte array, a qr version number and an error correction level.
  2202. // Returns decoded data.
  2203. function decodeQRdata(data, version, ecl) {
  2204. var symbolSequence = -1;
  2205. var parityData = -1;
  2206. var bits = new bitstream_1.BitStream(data);
  2207. var result = { val: [] }; // Have to pass this around so functions can share a reference to a number[]
  2208. var fc1InEffect = false;
  2209. var mode;
  2210. while (mode != TERMINATOR_MODE) {
  2211. // While still another segment to read...
  2212. if (bits.available() < 4) {
  2213. // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here
  2214. mode = TERMINATOR_MODE;
  2215. }
  2216. else {
  2217. mode = modeForBits(bits.readBits(4)); // mode is encoded by 4 bits
  2218. }
  2219. if (mode != TERMINATOR_MODE) {
  2220. if (mode == FNC1_FIRST_POSITION_MODE || mode == FNC1_SECOND_POSITION_MODE) {
  2221. // We do little with FNC1 except alter the parsed result a bit according to the spec
  2222. fc1InEffect = true;
  2223. }
  2224. else if (mode == STRUCTURED_APPEND_MODE) {
  2225. if (bits.available() < 16) {
  2226. return null;
  2227. }
  2228. // not really supported; but sequence number and parity is added later to the result metadata
  2229. // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue
  2230. symbolSequence = bits.readBits(8);
  2231. parityData = bits.readBits(8);
  2232. }
  2233. else if (mode == ECI_MODE) {
  2234. // Ignore since we don't do character encoding in JS
  2235. var value = parseECIValue(bits);
  2236. if (value < 0 || value > 30) {
  2237. return null;
  2238. }
  2239. }
  2240. else {
  2241. // First handle Hanzi mode which does not start with character count
  2242. if (mode == HANZI_MODE) {
  2243. //chinese mode contains a sub set indicator right after mode indicator
  2244. var subset = bits.readBits(4);
  2245. var countHanzi = bits.readBits(mode.getCharacterCountBits(version));
  2246. if (subset == GB2312_SUBSET) {
  2247. if (!decodeHanziSegment(bits, result, countHanzi)) {
  2248. return null;
  2249. }
  2250. }
  2251. }
  2252. else {
  2253. // "Normal" QR code modes:
  2254. // How many characters will follow, encoded in this mode?
  2255. var count = bits.readBits(mode.getCharacterCountBits(version));
  2256. if (mode == NUMERIC_MODE) {
  2257. if (!decodeNumericSegment(bits, result, count)) {
  2258. return null;
  2259. }
  2260. }
  2261. else if (mode == ALPHANUMERIC_MODE) {
  2262. if (!decodeAlphanumericSegment(bits, result, count, fc1InEffect)) {
  2263. return null;
  2264. }
  2265. }
  2266. else if (mode == BYTE_MODE) {
  2267. if (!decodeByteSegment(bits, result, count)) {
  2268. return null;
  2269. }
  2270. }
  2271. else if (mode == KANJI_MODE) {
  2272. }
  2273. else {
  2274. return null;
  2275. }
  2276. }
  2277. }
  2278. }
  2279. }
  2280. return result.val;
  2281. }
  2282. exports.decodeQRdata = decodeQRdata;
  2283. /***/ },
  2284. /* 11 */
  2285. /***/ function(module, exports) {
  2286. "use strict";
  2287. var BitStream = (function () {
  2288. function BitStream(bytes) {
  2289. this.byteOffset = 0;
  2290. this.bitOffset = 0;
  2291. this.bytes = bytes;
  2292. }
  2293. BitStream.prototype.readBits = function (numBits) {
  2294. if (numBits < 1 || numBits > 32 || numBits > this.available()) {
  2295. throw new Error("Cannot read " + numBits.toString() + " bits");
  2296. }
  2297. var result = 0;
  2298. // First, read remainder from current byte
  2299. if (this.bitOffset > 0) {
  2300. var bitsLeft = 8 - this.bitOffset;
  2301. var toRead = numBits < bitsLeft ? numBits : bitsLeft;
  2302. var bitsToNotRead = bitsLeft - toRead;
  2303. var mask = (0xFF >> (8 - toRead)) << bitsToNotRead;
  2304. result = (this.bytes[this.byteOffset] & mask) >> bitsToNotRead;
  2305. numBits -= toRead;
  2306. this.bitOffset += toRead;
  2307. if (this.bitOffset == 8) {
  2308. this.bitOffset = 0;
  2309. this.byteOffset++;
  2310. }
  2311. }
  2312. // Next read whole bytes
  2313. if (numBits > 0) {
  2314. while (numBits >= 8) {
  2315. result = (result << 8) | (this.bytes[this.byteOffset] & 0xFF);
  2316. this.byteOffset++;
  2317. numBits -= 8;
  2318. }
  2319. // Finally read a partial byte
  2320. if (numBits > 0) {
  2321. var bitsToNotRead = 8 - numBits;
  2322. var mask = (0xFF >> bitsToNotRead) << bitsToNotRead;
  2323. result = (result << numBits) | ((this.bytes[this.byteOffset] & mask) >> bitsToNotRead);
  2324. this.bitOffset += numBits;
  2325. }
  2326. }
  2327. return result;
  2328. };
  2329. BitStream.prototype.available = function () {
  2330. return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset;
  2331. };
  2332. return BitStream;
  2333. }());
  2334. exports.BitStream = BitStream;
  2335. /***/ },
  2336. /* 12 */
  2337. /***/ function(module, exports) {
  2338. "use strict";
  2339. var ReedSolomonDecoder = (function () {
  2340. function ReedSolomonDecoder() {
  2341. this.field = new GenericGF(0x011D, 256, 0); // x^8 + x^4 + x^3 + x^2 + 1
  2342. }
  2343. ReedSolomonDecoder.prototype.decode = function (received, twoS) {
  2344. var poly = new GenericGFPoly(this.field, received);
  2345. var syndromeCoefficients = new Array(twoS);
  2346. var noError = true;
  2347. for (var i = 0; i < twoS; i++) {
  2348. var evaluation = poly.evaluateAt(this.field.exp(i + this.field.generatorBase));
  2349. syndromeCoefficients[syndromeCoefficients.length - 1 - i] = evaluation;
  2350. if (evaluation != 0) {
  2351. noError = false;
  2352. }
  2353. }
  2354. if (noError) {
  2355. return true;
  2356. }
  2357. var syndrome = new GenericGFPoly(this.field, syndromeCoefficients);
  2358. var sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(twoS, 1), syndrome, twoS);
  2359. if (sigmaOmega == null)
  2360. return false;
  2361. var sigma = sigmaOmega[0];
  2362. var errorLocations = this.findErrorLocations(sigma);
  2363. if (errorLocations == null)
  2364. return false;
  2365. var omega = sigmaOmega[1];
  2366. var errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations);
  2367. for (var i = 0; i < errorLocations.length; i++) {
  2368. var position = received.length - 1 - this.field.log(errorLocations[i]);
  2369. if (position < 0) {
  2370. // throw new ReedSolomonException("Bad error location");
  2371. return false;
  2372. }
  2373. received[position] = GenericGF.addOrSubtract(received[position], errorMagnitudes[i]);
  2374. }
  2375. return true;
  2376. };
  2377. ReedSolomonDecoder.prototype.runEuclideanAlgorithm = function (a, b, R) {
  2378. // Assume a's degree is >= b's
  2379. if (a.degree() < b.degree()) {
  2380. var temp = a;
  2381. a = b;
  2382. b = temp;
  2383. }
  2384. var rLast = a;
  2385. var r = b;
  2386. var tLast = this.field.zero;
  2387. var t = this.field.one;
  2388. // Run Euclidean algorithm until r's degree is less than R/2
  2389. while (r.degree() >= R / 2) {
  2390. var rLastLast = rLast;
  2391. var tLastLast = tLast;
  2392. rLast = r;
  2393. tLast = t;
  2394. // Divide rLastLast by rLast, with quotient in q and remainder in r
  2395. if (rLast.isZero()) {
  2396. // Oops, Euclidean algorithm already terminated?
  2397. // throw new ReedSolomonException("r_{i-1} was zero");
  2398. return null;
  2399. }
  2400. r = rLastLast;
  2401. var q = this.field.zero;
  2402. var denominatorLeadingTerm = rLast.getCoefficient(rLast.degree());
  2403. var dltInverse = this.field.inverse(denominatorLeadingTerm);
  2404. while (r.degree() >= rLast.degree() && !r.isZero()) {
  2405. var degreeDiff = r.degree() - rLast.degree();
  2406. var scale = this.field.multiply(r.getCoefficient(r.degree()), dltInverse);
  2407. q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale));
  2408. r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
  2409. }
  2410. t = q.multiplyPoly(tLast).addOrSubtract(tLastLast);
  2411. if (r.degree() >= rLast.degree()) {
  2412. // throw new IllegalStateException("Division algorithm failed to reduce polynomial?");
  2413. return null;
  2414. }
  2415. }
  2416. var sigmaTildeAtZero = t.getCoefficient(0);
  2417. if (sigmaTildeAtZero == 0) {
  2418. // throw new ReedSolomonException("sigmaTilde(0) was zero");
  2419. return null;
  2420. }
  2421. var inverse = this.field.inverse(sigmaTildeAtZero);
  2422. var sigma = t.multiply(inverse);
  2423. var omega = r.multiply(inverse);
  2424. return [sigma, omega];
  2425. };
  2426. ReedSolomonDecoder.prototype.findErrorLocations = function (errorLocator) {
  2427. // This is a direct application of Chien's search
  2428. var numErrors = errorLocator.degree();
  2429. if (numErrors == 1) {
  2430. // shortcut
  2431. return [errorLocator.getCoefficient(1)];
  2432. }
  2433. var result = new Array(numErrors);
  2434. var e = 0;
  2435. for (var i = 1; i < this.field.size && e < numErrors; i++) {
  2436. if (errorLocator.evaluateAt(i) == 0) {
  2437. result[e] = this.field.inverse(i);
  2438. e++;
  2439. }
  2440. }
  2441. if (e != numErrors) {
  2442. // throw new ReedSolomonException("Error locator degree does not match number of roots");
  2443. return null;
  2444. }
  2445. return result;
  2446. };
  2447. ReedSolomonDecoder.prototype.findErrorMagnitudes = function (errorEvaluator, errorLocations) {
  2448. // This is directly applying Forney's Formula
  2449. var s = errorLocations.length;
  2450. var result = new Array(s);
  2451. for (var i = 0; i < s; i++) {
  2452. var xiInverse = this.field.inverse(errorLocations[i]);
  2453. var denominator = 1;
  2454. for (var j = 0; j < s; j++) {
  2455. if (i != j) {
  2456. //denominator = field.multiply(denominator,
  2457. // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse)));
  2458. // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug.
  2459. // Below is a funny-looking workaround from Steven Parkes
  2460. var term = this.field.multiply(errorLocations[j], xiInverse);
  2461. var termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1;
  2462. denominator = this.field.multiply(denominator, termPlus1);
  2463. }
  2464. }
  2465. result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator));
  2466. if (this.field.generatorBase != 0) {
  2467. result[i] = this.field.multiply(result[i], xiInverse);
  2468. }
  2469. }
  2470. return result;
  2471. };
  2472. return ReedSolomonDecoder;
  2473. }());
  2474. exports.ReedSolomonDecoder = ReedSolomonDecoder;
  2475. var GenericGFPoly = (function () {
  2476. function GenericGFPoly(field, coefficients) {
  2477. if (coefficients.length == 0) {
  2478. throw new Error("No coefficients.");
  2479. }
  2480. this.field = field;
  2481. var coefficientsLength = coefficients.length;
  2482. if (coefficientsLength > 1 && coefficients[0] == 0) {
  2483. // Leading term must be non-zero for anything except the constant polynomial "0"
  2484. var firstNonZero = 1;
  2485. while (firstNonZero < coefficientsLength && coefficients[firstNonZero] == 0) {
  2486. firstNonZero++;
  2487. }
  2488. if (firstNonZero == coefficientsLength) {
  2489. this.coefficients = field.zero.coefficients;
  2490. }
  2491. else {
  2492. this.coefficients = new Array(coefficientsLength - firstNonZero);
  2493. /*Array.Copy(coefficients, // Source array
  2494. firstNonZero, // Source index
  2495. this.coefficients, // Destination array
  2496. 0, // Destination index
  2497. this.coefficients.length); // length*/
  2498. for (var i = 0; i < this.coefficients.length; i++) {
  2499. this.coefficients[i] = coefficients[firstNonZero + i];
  2500. }
  2501. }
  2502. }
  2503. else {
  2504. this.coefficients = coefficients;
  2505. }
  2506. }
  2507. GenericGFPoly.prototype.evaluateAt = function (a) {
  2508. var result = 0;
  2509. if (a == 0) {
  2510. // Just return the x^0 coefficient
  2511. return this.getCoefficient(0);
  2512. }
  2513. var size = this.coefficients.length;
  2514. if (a == 1) {
  2515. // Just the sum of the coefficients
  2516. this.coefficients.forEach(function (coefficient) {
  2517. result = GenericGF.addOrSubtract(result, coefficient);
  2518. });
  2519. return result;
  2520. }
  2521. result = this.coefficients[0];
  2522. for (var i = 1; i < size; i++) {
  2523. result = GenericGF.addOrSubtract(this.field.multiply(a, result), this.coefficients[i]);
  2524. }
  2525. return result;
  2526. };
  2527. GenericGFPoly.prototype.getCoefficient = function (degree) {
  2528. return this.coefficients[this.coefficients.length - 1 - degree];
  2529. };
  2530. GenericGFPoly.prototype.degree = function () {
  2531. return this.coefficients.length - 1;
  2532. };
  2533. GenericGFPoly.prototype.isZero = function () {
  2534. return this.coefficients[0] == 0;
  2535. };
  2536. GenericGFPoly.prototype.addOrSubtract = function (other) {
  2537. /* TODO, fix this.
  2538. if (!this.field.Equals(other.field))
  2539. {
  2540. throw new Error("GenericGFPolys do not have same GenericGF field");
  2541. }*/
  2542. if (this.isZero()) {
  2543. return other;
  2544. }
  2545. if (other.isZero()) {
  2546. return this;
  2547. }
  2548. var smallerCoefficients = this.coefficients;
  2549. var largerCoefficients = other.coefficients;
  2550. if (smallerCoefficients.length > largerCoefficients.length) {
  2551. var temp = smallerCoefficients;
  2552. smallerCoefficients = largerCoefficients;
  2553. largerCoefficients = temp;
  2554. }
  2555. var sumDiff = new Array(largerCoefficients.length);
  2556. var lengthDiff = largerCoefficients.length - smallerCoefficients.length;
  2557. // Copy high-order terms only found in higher-degree polynomial's coefficients
  2558. ///Array.Copy(largerCoefficients, 0, sumDiff, 0, lengthDiff);
  2559. for (var i = 0; i < lengthDiff; i++) {
  2560. sumDiff[i] = largerCoefficients[i];
  2561. }
  2562. for (var i = lengthDiff; i < largerCoefficients.length; i++) {
  2563. sumDiff[i] = GenericGF.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
  2564. }
  2565. return new GenericGFPoly(this.field, sumDiff);
  2566. };
  2567. GenericGFPoly.prototype.multiply = function (scalar) {
  2568. if (scalar == 0) {
  2569. return this.field.zero;
  2570. }
  2571. if (scalar == 1) {
  2572. return this;
  2573. }
  2574. var size = this.coefficients.length;
  2575. var product = new Array(size);
  2576. for (var i = 0; i < size; i++) {
  2577. product[i] = this.field.multiply(this.coefficients[i], scalar);
  2578. }
  2579. return new GenericGFPoly(this.field, product);
  2580. };
  2581. GenericGFPoly.prototype.multiplyPoly = function (other) {
  2582. /* TODO Fix this.
  2583. if (!field.Equals(other.field))
  2584. {
  2585. throw new Error("GenericGFPolys do not have same GenericGF field");
  2586. }*/
  2587. if (this.isZero() || other.isZero()) {
  2588. return this.field.zero;
  2589. }
  2590. var aCoefficients = this.coefficients;
  2591. var aLength = aCoefficients.length;
  2592. var bCoefficients = other.coefficients;
  2593. var bLength = bCoefficients.length;
  2594. var product = new Array(aLength + bLength - 1);
  2595. for (var i = 0; i < aLength; i++) {
  2596. var aCoeff = aCoefficients[i];
  2597. for (var j = 0; j < bLength; j++) {
  2598. product[i + j] = GenericGF.addOrSubtract(product[i + j], this.field.multiply(aCoeff, bCoefficients[j]));
  2599. }
  2600. }
  2601. return new GenericGFPoly(this.field, product);
  2602. };
  2603. GenericGFPoly.prototype.multiplyByMonomial = function (degree, coefficient) {
  2604. if (degree < 0) {
  2605. throw new Error("Invalid degree less than 0");
  2606. }
  2607. if (coefficient == 0) {
  2608. return this.field.zero;
  2609. }
  2610. var size = this.coefficients.length;
  2611. var product = new Array(size + degree);
  2612. for (var i = 0; i < size; i++) {
  2613. product[i] = this.field.multiply(this.coefficients[i], coefficient);
  2614. }
  2615. return new GenericGFPoly(this.field, product);
  2616. };
  2617. return GenericGFPoly;
  2618. }());
  2619. var GenericGF = (function () {
  2620. function GenericGF(primitive, size, genBase) {
  2621. // ok.
  2622. this.INITIALIZATION_THRESHOLD = 0;
  2623. this.initialized = false;
  2624. this.primitive = primitive;
  2625. this.size = size;
  2626. this.generatorBase = genBase;
  2627. if (size <= this.INITIALIZATION_THRESHOLD) {
  2628. this.initialize();
  2629. }
  2630. }
  2631. GenericGF.prototype.initialize = function () {
  2632. this.expTable = new Array(this.size);
  2633. this.logTable = new Array(this.size);
  2634. var x = 1;
  2635. for (var i = 0; i < this.size; i++) {
  2636. this.expTable[i] = x;
  2637. x <<= 1; // x = x * 2; we're assuming the generator alpha is 2
  2638. if (x >= this.size) {
  2639. x ^= this.primitive;
  2640. x &= this.size - 1;
  2641. }
  2642. }
  2643. for (var i = 0; i < this.size - 1; i++) {
  2644. this.logTable[this.expTable[i]] = i;
  2645. }
  2646. // logTable[0] == 0 but this should never be used
  2647. this.zero = new GenericGFPoly(this, [0]);
  2648. this.one = new GenericGFPoly(this, [1]);
  2649. this.initialized = true;
  2650. };
  2651. GenericGF.addOrSubtract = function (a, b) {
  2652. return a ^ b;
  2653. };
  2654. GenericGF.prototype.checkInit = function () {
  2655. if (!this.initialized)
  2656. this.initialize();
  2657. };
  2658. GenericGF.prototype.multiply = function (a, b) {
  2659. this.checkInit();
  2660. if (a == 0 || b == 0) {
  2661. return 0;
  2662. }
  2663. return this.expTable[(this.logTable[a] + this.logTable[b]) % (this.size - 1)];
  2664. };
  2665. GenericGF.prototype.exp = function (a) {
  2666. this.checkInit();
  2667. return this.expTable[a];
  2668. };
  2669. GenericGF.prototype.log = function (a) {
  2670. this.checkInit();
  2671. if (a == 0) {
  2672. throw new Error("Can't take log(0)");
  2673. }
  2674. return this.logTable[a];
  2675. };
  2676. GenericGF.prototype.inverse = function (a) {
  2677. this.checkInit();
  2678. if (a == 0) {
  2679. throw new Error("Can't invert 0");
  2680. }
  2681. return this.expTable[this.size - this.logTable[a] - 1];
  2682. };
  2683. GenericGF.prototype.buildMonomial = function (degree, coefficient) {
  2684. this.checkInit();
  2685. if (degree < 0) {
  2686. throw new Error("Invalid monomial degree less than 0");
  2687. }
  2688. if (coefficient == 0) {
  2689. return this.zero;
  2690. }
  2691. var coefficients = new Array(degree + 1);
  2692. coefficients[0] = coefficient;
  2693. return new GenericGFPoly(this, coefficients);
  2694. };
  2695. return GenericGF;
  2696. }());
  2697. /***/ }
  2698. /******/ ])
  2699. });
  2700. ;