1bd793673eb7af48cb7700da414b63a5de38431d3def90b00ef58b7553e9442e.json raw
1 {"ast":null,"code":"/**\n * Data mask pattern reference\n * @type {Object}\n */\nexports.Patterns = {\n PATTERN000: 0,\n PATTERN001: 1,\n PATTERN010: 2,\n PATTERN011: 3,\n PATTERN100: 4,\n PATTERN101: 5,\n PATTERN110: 6,\n PATTERN111: 7\n};\n\n/**\n * Weighted penalty scores for the undesirable features\n * @type {Object}\n */\nconst PenaltyScores = {\n N1: 3,\n N2: 3,\n N3: 40,\n N4: 10\n};\n\n/**\n * Check if mask pattern value is valid\n *\n * @param {Number} mask Mask pattern\n * @return {Boolean} true if valid, false otherwise\n */\nexports.isValid = function isValid(mask) {\n return mask != null && mask !== '' && !isNaN(mask) && mask >= 0 && mask <= 7;\n};\n\n/**\n * Returns mask pattern from a value.\n * If value is not valid, returns undefined\n *\n * @param {Number|String} value Mask pattern value\n * @return {Number} Valid mask pattern or undefined\n */\nexports.from = function from(value) {\n return exports.isValid(value) ? parseInt(value, 10) : undefined;\n};\n\n/**\n* Find adjacent modules in row/column with the same color\n* and assign a penalty value.\n*\n* Points: N1 + i\n* i is the amount by which the number of adjacent modules of the same color exceeds 5\n*/\nexports.getPenaltyN1 = function getPenaltyN1(data) {\n const size = data.size;\n let points = 0;\n let sameCountCol = 0;\n let sameCountRow = 0;\n let lastCol = null;\n let lastRow = null;\n for (let row = 0; row < size; row++) {\n sameCountCol = sameCountRow = 0;\n lastCol = lastRow = null;\n for (let col = 0; col < size; col++) {\n let module = data.get(row, col);\n if (module === lastCol) {\n sameCountCol++;\n } else {\n if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5);\n lastCol = module;\n sameCountCol = 1;\n }\n module = data.get(col, row);\n if (module === lastRow) {\n sameCountRow++;\n } else {\n if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5);\n lastRow = module;\n sameCountRow = 1;\n }\n }\n if (sameCountCol >= 5) points += PenaltyScores.N1 + (sameCountCol - 5);\n if (sameCountRow >= 5) points += PenaltyScores.N1 + (sameCountRow - 5);\n }\n return points;\n};\n\n/**\n * Find 2x2 blocks with the same color and assign a penalty value\n *\n * Points: N2 * (m - 1) * (n - 1)\n */\nexports.getPenaltyN2 = function getPenaltyN2(data) {\n const size = data.size;\n let points = 0;\n for (let row = 0; row < size - 1; row++) {\n for (let col = 0; col < size - 1; col++) {\n const last = data.get(row, col) + data.get(row, col + 1) + data.get(row + 1, col) + data.get(row + 1, col + 1);\n if (last === 4 || last === 0) points++;\n }\n }\n return points * PenaltyScores.N2;\n};\n\n/**\n * Find 1:1:3:1:1 ratio (dark:light:dark:light:dark) pattern in row/column,\n * preceded or followed by light area 4 modules wide\n *\n * Points: N3 * number of pattern found\n */\nexports.getPenaltyN3 = function getPenaltyN3(data) {\n const size = data.size;\n let points = 0;\n let bitsCol = 0;\n let bitsRow = 0;\n for (let row = 0; row < size; row++) {\n bitsCol = bitsRow = 0;\n for (let col = 0; col < size; col++) {\n bitsCol = bitsCol << 1 & 0x7FF | data.get(row, col);\n if (col >= 10 && (bitsCol === 0x5D0 || bitsCol === 0x05D)) points++;\n bitsRow = bitsRow << 1 & 0x7FF | data.get(col, row);\n if (col >= 10 && (bitsRow === 0x5D0 || bitsRow === 0x05D)) points++;\n }\n }\n return points * PenaltyScores.N3;\n};\n\n/**\n * Calculate proportion of dark modules in entire symbol\n *\n * Points: N4 * k\n *\n * k is the rating of the deviation of the proportion of dark modules\n * in the symbol from 50% in steps of 5%\n */\nexports.getPenaltyN4 = function getPenaltyN4(data) {\n let darkCount = 0;\n const modulesCount = data.data.length;\n for (let i = 0; i < modulesCount; i++) darkCount += data.data[i];\n const k = Math.abs(Math.ceil(darkCount * 100 / modulesCount / 5) - 10);\n return k * PenaltyScores.N4;\n};\n\n/**\n * Return mask value at given position\n *\n * @param {Number} maskPattern Pattern reference value\n * @param {Number} i Row\n * @param {Number} j Column\n * @return {Boolean} Mask value\n */\nfunction getMaskAt(maskPattern, i, j) {\n switch (maskPattern) {\n case exports.Patterns.PATTERN000:\n return (i + j) % 2 === 0;\n case exports.Patterns.PATTERN001:\n return i % 2 === 0;\n case exports.Patterns.PATTERN010:\n return j % 3 === 0;\n case exports.Patterns.PATTERN011:\n return (i + j) % 3 === 0;\n case exports.Patterns.PATTERN100:\n return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 === 0;\n case exports.Patterns.PATTERN101:\n return i * j % 2 + i * j % 3 === 0;\n case exports.Patterns.PATTERN110:\n return (i * j % 2 + i * j % 3) % 2 === 0;\n case exports.Patterns.PATTERN111:\n return (i * j % 3 + (i + j) % 2) % 2 === 0;\n default:\n throw new Error('bad maskPattern:' + maskPattern);\n }\n}\n\n/**\n * Apply a mask pattern to a BitMatrix\n *\n * @param {Number} pattern Pattern reference number\n * @param {BitMatrix} data BitMatrix data\n */\nexports.applyMask = function applyMask(pattern, data) {\n const size = data.size;\n for (let col = 0; col < size; col++) {\n for (let row = 0; row < size; row++) {\n if (data.isReserved(row, col)) continue;\n data.xor(row, col, getMaskAt(pattern, row, col));\n }\n }\n};\n\n/**\n * Returns the best mask pattern for data\n *\n * @param {BitMatrix} data\n * @return {Number} Mask pattern reference number\n */\nexports.getBestMask = function getBestMask(data, setupFormatFunc) {\n const numPatterns = Object.keys(exports.Patterns).length;\n let bestPattern = 0;\n let lowerPenalty = Infinity;\n for (let p = 0; p < numPatterns; p++) {\n setupFormatFunc(p);\n exports.applyMask(p, data);\n\n // Calculate penalty\n const penalty = exports.getPenaltyN1(data) + exports.getPenaltyN2(data) + exports.getPenaltyN3(data) + exports.getPenaltyN4(data);\n\n // Undo previously applied mask\n exports.applyMask(p, data);\n if (penalty < lowerPenalty) {\n lowerPenalty = penalty;\n bestPattern = p;\n }\n }\n return bestPattern;\n};","map":null,"metadata":{},"sourceType":"script","externalDependencies":[]}