UNPKG

@nuintun/qrcode

Version:

A pure JavaScript QRCode encode and decode library.

93 lines (89 loc) 3.3 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 { Pattern } from './Pattern.js'; import { distance } from '../common/Point.js'; import { scanlineUpdate } from './utils/scanline.js'; import { DIFF_MODULE_SIZE_RATIO } from './utils/constants.js'; import { PatternFinder } from './PatternFinder.js'; import { isEqualsSize, isMatchPattern } from './utils/pattern.js'; import { ALIGNMENT_PATTERN_RATIOS, ALIGNMENT_PATTERN_LOOSE_MODE_RATIOS } from './PatternRatios.js'; /** * @module AlignmentPatternFinder */ class AlignmentPatternFinder extends PatternFinder { constructor(matrix, strict) { super(matrix, ALIGNMENT_PATTERN_RATIOS, strict); } filter(expectAlignment, moduleSize) { const patterns = this.patterns.filter(pattern => { return Pattern.noise(pattern) <= 2.5 && isEqualsSize(pattern.moduleSize, moduleSize, DIFF_MODULE_SIZE_RATIO); }); if (patterns.length > 1) { patterns.sort((pattern1, pattern2) => { const noise1 = Pattern.noise(pattern1); const noise2 = Pattern.noise(pattern2); const moduleSizeDiff1 = Math.abs(pattern1.moduleSize - moduleSize); const moduleSizeDiff2 = Math.abs(pattern2.moduleSize - moduleSize); const score1 = (distance(pattern1, expectAlignment) + moduleSizeDiff1) * noise1; const score2 = (distance(pattern2, expectAlignment) + moduleSizeDiff2) * noise2; return score1 - score2; }); } // Only use the first two patterns. const alignmentPatterns = patterns.slice(0, 2); // Add expect alignment for fallback. alignmentPatterns.push(expectAlignment); return alignmentPatterns; } find(left, top, width, height) { const { matrix } = this; const right = left + width; const bottom = top + height; const match = (x, y, scanline, count, scanlineBits, lastBit) => { scanlineUpdate(scanline, count); scanlineUpdate(scanlineBits, lastBit); // Match pattern when white-black-white. if ( scanlineBits[0] === 0 && scanlineBits[1] === 1 && scanlineBits[2] === 0 && isMatchPattern(scanline, ALIGNMENT_PATTERN_LOOSE_MODE_RATIOS) ) { this.match(x, y, scanline, scanline[1]); } }; for (let y = top; y < bottom; y++) { let x = left; // Burn off leading white pixels before anything else; if we start in the middle of // a white run, it doesn't make sense to count its length, since we don't know if the // white run continued to the left of the start point. while (x < right && !matrix.get(x, y)) { x++; } let count = 0; let lastBit = matrix.get(x, y); const scanline = [0, 0, 0]; const scanlineBits = [-1, -1, -1]; while (x < right) { const bit = matrix.get(x, y); if (bit === lastBit) { count++; } else { match(x, y, scanline, count, scanlineBits, lastBit); count = 1; lastBit = bit; } x++; } match(x, y, scanline, count, scanlineBits, lastBit); } } } export { AlignmentPatternFinder };