@nuintun/qrcode
Version:
A pure JavaScript QRCode encode and decode library.
151 lines (147 loc) • 4.38 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 { 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
};