@nuintun/qrcode
Version:
A pure JavaScript QRCode encode and decode library.
83 lines (78 loc) • 3.41 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
*/
'use strict';
const Point = require('../../common/Point.cjs');
const utils = require('../../common/utils.cjs');
const Pattern = require('../Pattern.cjs');
const PlotLine = require('../../common/PlotLine.cjs');
const FinderPatternGroup = require('../FinderPatternGroup.cjs');
/**
* @module timing
*/
function calculateEstimateTimingRatio(axis, control) {
return control > axis ? 1 : control < axis ? -1 : 0;
}
function getEstimateTimingPointXAxis(pattern, ratio) {
const [left, , right] = Pattern.Pattern.rect(pattern);
return ratio > 0 ? right : ratio < 0 ? left : pattern.x;
}
function getEstimateTimingPointYAxis(pattern, ratio) {
const [, top, , bottom] = Pattern.Pattern.rect(pattern);
return ratio > 0 ? bottom : ratio < 0 ? top : pattern.y;
}
function getEstimateTimingLine(start, end, control, isVertical) {
const { x: endX, y: endY } = end;
const { x: startX, y: startY } = start;
const { x: controlX, y: controlY } = control;
const xRatio = calculateEstimateTimingRatio(endX, controlX);
const yRatio = calculateEstimateTimingRatio(endY, controlY);
const endXTranslate = getEstimateTimingPointXAxis(end, xRatio);
const endYTranslate = getEstimateTimingPointYAxis(end, yRatio);
const startXTranslate = getEstimateTimingPointXAxis(start, xRatio);
const startYTranslate = getEstimateTimingPointYAxis(start, yRatio);
if (xRatio === 0 || yRatio === 0) {
return [new Point.Point(startXTranslate, startYTranslate), new Point.Point(endXTranslate, endYTranslate)];
}
if (isVertical ? xRatio === yRatio : xRatio !== yRatio) {
return [new Point.Point(startX, startYTranslate), new Point.Point(endX, endYTranslate)];
}
return [new Point.Point(startXTranslate, startY), new Point.Point(endXTranslate, endY)];
}
function isValidTimingLine(matrix, start, end, size) {
const maxModules = size + 8;
const points = new PlotLine.PlotLine(start, end).points();
let modules = 1;
let lastBit = matrix.get(utils.toInt32(start.x), utils.toInt32(start.y));
for (const [x, y] of points) {
const bit = matrix.get(x, y);
if (bit !== lastBit) {
modules++;
lastBit = bit;
if (modules > maxModules) {
return false;
}
}
}
return modules >= size - 14 - Math.max(2, (size - 17) / 4);
}
function checkEstimateTimingLine(matrix, finderPatternGroup, isVertical) {
const { topLeft, topRight, bottomLeft } = finderPatternGroup;
const [start, end] = isVertical
? getEstimateTimingLine(topLeft, bottomLeft, topRight, true)
: getEstimateTimingLine(topLeft, topRight, bottomLeft);
return isValidTimingLine(matrix, start, end, FinderPatternGroup.FinderPatternGroup.size(finderPatternGroup));
}
function checkMappingTimingLine(matrix, transform, size, isVertical) {
const [startX, startY] = transform.mapping(isVertical ? 6.5 : 7.5, isVertical ? 7.5 : 6.5);
const [endX, endY] = transform.mapping(isVertical ? 6.5 : size - 7.5, isVertical ? size - 7.5 : 6.5);
return isValidTimingLine(matrix, new Point.Point(startX, startY), new Point.Point(endX, endY), size);
}
exports.checkEstimateTimingLine = checkEstimateTimingLine;
exports.checkMappingTimingLine = checkMappingTimingLine;