UNPKG

@nuintun/qrcode

Version:

A pure JavaScript QRCode encode and decode library.

72 lines (68 loc) 2.53 kB
/** * @module QRCode * @package @nuintun/qrcode * @license MIT * @version 5.0.2 * @author nuintun <nuintun@qq.com> * @description A pure JavaScript QRCode encode and decode library. * @see https://github.com/nuintun/qrcode#readme */ import { accumulate } from '../../common/utils.js'; import { DIFF_PATTERN_RATIO, DIFF_PATTERN_ALLOWANCE } from './constants.js'; import { getCrossScanline, centerFromScanlineEnd, calculateScanlineNoise, sumScanlineNonzero } from './scanline.js'; /** * @module pattern */ function isDiagonalScanlineCheckPassed(slash, backslash, ratios, strict) { return strict ? isMatchPattern(slash, ratios) && isMatchPattern(backslash, ratios) : isMatchPattern(slash, ratios) || isMatchPattern(backslash, ratios); } function alignCrossPattern(matrix, x, y, overscan, ratios, isVertical) { const [scanline, end] = getCrossScanline(matrix, x, y, overscan, isVertical); return [isMatchPattern(scanline, ratios) ? centerFromScanlineEnd(scanline, end) : NaN, scanline]; } function isEqualsSize(size1, size2, ratio) { if (size1 > size2) { [size1, size2] = [size2, size1]; } return size2 - size1 <= size2 * ratio; } function isMatchPattern(scanline, { ratios, modules }) { const { length } = scanline; const scanlineTotal = sumScanlineNonzero(scanline); if (scanlineTotal >= modules) { const moduleSize = scanlineTotal / modules; const threshold = moduleSize * DIFF_PATTERN_RATIO + DIFF_PATTERN_ALLOWANCE; // Allow less than DIFF_PATTERN_RATIO variance from 1-1-3-1-1 or 1-1-1-1-1 proportions. for (let i = 0; i < length; i++) { const ratio = ratios[i]; const count = scanline[i]; const countDiff = Math.abs(count - moduleSize * ratio); if (countDiff > threshold) { return false; } } return true; } return false; } function calculatePatternNoise(ratios, ...scanlines) { let noises = 0; let averageNoises = 0; const { length } = scanlines; const averages = []; // scanline length must be equals ratios length. for (const scanline of scanlines) { const [noise, average] = calculateScanlineNoise(scanline, ratios); noises += noise; averages.push(average); } const total = accumulate(averages); const averagesAvg = total / length; for (const average of averages) { averageNoises += Math.abs(average - averagesAvg); } return noises + averageNoises / total; } export { alignCrossPattern, calculatePatternNoise, isDiagonalScanlineCheckPassed, isEqualsSize, isMatchPattern };