UNPKG

@nuintun/qrcode

Version:

A pure JavaScript QRCode encode and decode library.

151 lines (147 loc) 4.38 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 { toInt32, accumulate } from '../../common/utils.js'; /** * @module scanline */ function calculateScanlineNoise(scanline, { ratios, modules }) { let noise = 0; const { length } = ratios; const total = accumulate(scanline); const average = total / modules; // scanline length must be equals ratios length. for (let i = 0; i < length; i++) { noise += Math.abs(scanline[i] - ratios[i] * average); } return [noise / total, average]; } function sumScanlineNonzero(scanline) { let scanlineTotal = 0; for (const count of scanline) { if (count === 0) { return NaN; } scanlineTotal += count; } return scanlineTotal; } function scanlineUpdate(scanline, count) { const { length } = scanline; const lastIndex = length - 1; for (let i = 0; i < lastIndex; i++) { scanline[i] = scanline[i + 1]; } scanline[lastIndex] = count; } function getCrossScanline(matrix, x, y, overscan, isVertical) { x = toInt32(x); y = toInt32(y); let offset = isVertical ? y : x; const scanline = [0, 0, 0, 0, 0]; const size = isVertical ? matrix.height : matrix.width; const isBlackPixel = () => { return isVertical ? matrix.get(x, offset) : matrix.get(offset, y); }; while (offset >= 0 && isBlackPixel()) { offset--; scanline[2]++; } while (offset >= 0 && !isBlackPixel()) { offset--; scanline[1]++; } while (offset >= 0 && scanline[0] < overscan && isBlackPixel()) { offset--; scanline[0]++; } offset = (isVertical ? y : x) + 1; while (offset < size && isBlackPixel()) { offset++; scanline[2]++; } while (offset < size && !isBlackPixel()) { offset++; scanline[3]++; } while (offset < size && scanline[4] < overscan && isBlackPixel()) { offset++; scanline[4]++; } return [scanline, offset]; } function getDiagonalScanline(matrix, x, y, overscan, isBackslash) { x = toInt32(x); y = toInt32(y); let step = -1; let offsetX = x; let offsetY = y; const scanline = [0, 0, 0, 0, 0]; const { width, height } = matrix; const slope = isBackslash ? -1 : 1; const updateAxis = () => { offsetX += step; offsetY -= step * slope; }; const isBlackPixel = () => { return matrix.get(offsetX, offsetY); }; // Start counting left from center finding black center mass. while (offsetX >= 0 && offsetY >= 0 && offsetY < height && isBlackPixel()) { updateAxis(); scanline[2]++; } // Start counting left from center finding black center mass. while (offsetX >= 0 && offsetY >= 0 && offsetY < height && !isBlackPixel()) { updateAxis(); scanline[1]++; } // Start counting left from center finding black center mass. while (offsetX >= 0 && offsetY >= 0 && offsetY < height && scanline[0] < overscan && isBlackPixel()) { updateAxis(); scanline[0]++; } step = 1; offsetX = x + step; offsetY = y - step * slope; // Start counting right from center finding black center mass. while (offsetX < width && offsetY >= 0 && offsetY < height && isBlackPixel()) { updateAxis(); scanline[2]++; } // Start counting right from center finding black center mass. while (offsetX < width && offsetY >= 0 && offsetY < height && !isBlackPixel()) { updateAxis(); scanline[3]++; } // Start counting right from center finding black center mass. while (offsetX < width && offsetY >= 0 && offsetY < height && scanline[4] < overscan && isBlackPixel()) { updateAxis(); scanline[4]++; } return scanline; } // @see https://github.com/zxing-cpp/zxing-cpp/blob/master/core/src/ConcentricFinder.h function centerFromScanlineEnd(scanline, end) { const centers = []; const middleIndex = toInt32(scanline.length / 2); for (let i = 0; i <= middleIndex; i++) { const splitIndex = middleIndex + i + 1; centers.push(accumulate(scanline, middleIndex - i, splitIndex) / 2 + accumulate(scanline, splitIndex)); } return end - (centers[0] * 2 + accumulate(centers, 1)) / (middleIndex + 2); } export { calculateScanlineNoise, centerFromScanlineEnd, getCrossScanline, getDiagonalScanline, scanlineUpdate, sumScanlineNonzero };