@nuintun/qrcode
Version:
A pure JavaScript QRCode encode and decode library.
72 lines (68 loc) • 2.53 kB
JavaScript
/**
* @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 };