// 二维码生成、功能区识别与摆放 const QRCodeCore = require('./qrcore/qrcode') const AlignmentPattern = require('./qrcore/alignment-pattern') const SAMPLE_TEXT = '豆维·可扫码的拼豆' // 功能区(定位/时序/对齐/格式/版本)直接决定能否扫出,配色时强制高对比 function buildFunctionMask(size, version) { const mask = new Uint8Array(size * size) const mark = (x, y) => { if (x >= 0 && y >= 0 && x < size && y < size) mask[y * size + x] = 1 } for (let y = 0; y < size; y += 1) { for (let x = 0; x < size; x += 1) { const finder = (x <= 8 && y <= 8) || (x >= size - 8 && y <= 8) || (x <= 8 && y >= size - 8) if (finder || x === 6 || y === 6) mark(x, y) } } const positions = AlignmentPattern.getPositions(version) || [] positions.forEach(([row, col]) => { for (let dy = -2; dy <= 2; dy += 1) for (let dx = -2; dx <= 2; dx += 1) mark(col + dx, row + dy) }) if (version >= 7) { for (let i = 0; i < 6; i += 1) { for (let j = size - 11; j < size - 8; j += 1) { mark(i, j); mark(j, i) } } } return mask } function makeQr(text, level) { const value = String(text || '').trim() || SAMPLE_TEXT const qr = QRCodeCore.create(value, { errorCorrectionLevel: level || 'H' }) const size = qr.modules.size const version = qr.version || Math.round((size - 17) / 4) return { size, version, level: level || 'H', dark: Uint8Array.from(qr.modules.data), func: buildFunctionMask(size, version), isSample: !String(text || '').trim(), } } // scale:二维码占整张作品边长的百分比;quiet:二维码四周留白格数 function createPlacement(qrSize, { scale = 100, posX = 50, posY = 50, quiet = 0, hasImage = true } = {}) { const block = qrSize + quiet * 2 const size = hasImage ? Math.max(block, Math.ceil(block * 100 / scale)) : block const free = size - block return { size, left: quiet + Math.round(free * posX / 100), top: quiet + Math.round(free * posY / 100), quiet, scale: hasImage ? scale : 100, } } module.exports = { SAMPLE_TEXT, makeQr, createPlacement }