/** * 简单的二维码生成器 * 使用Canvas API实现,不依赖外部库 */ class SimpleQRCode { constructor() { // QR码版本和大小映射 this.sizeMap = { 1: 21, 2: 25, 3: 29, 4: 33, 5: 37, 6: 41, 7: 45, 8: 49, 9: 53, 10: 57 }; } /** * 生成二维码到Canvas */ toCanvas(canvas, text, options = {}) { const size = options.width || 200; const margin = options.margin || 2; canvas.width = size; canvas.height = size; const ctx = canvas.getContext('2d'); // 白色背景 ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, size, size); // 生成QR码数据 const qrData = this.generateQRData(text); // 计算单元格大小 const moduleCount = qrData.length; const cellSize = (size - margin * 2) / moduleCount; // 绘制QR码 ctx.fillStyle = '#000000'; for (let row = 0; row < moduleCount; row++) { for (let col = 0; col < moduleCount; col++) { if (qrData[row][col]) { const x = margin + col * cellSize; const y = margin + row * cellSize; ctx.fillRect(x, y, cellSize, cellSize); } } } return canvas; } /** * 生成QR码数据矩阵 */ generateQRData(text) { // 简化版本:生成一个基本的QR码结构 const version = this.getVersion(text.length); const size = this.sizeMap[version] || 21; // 创建数据矩阵 const matrix = Array(size).fill(null).map(() => Array(size).fill(false)); // 添加定位图案 this.addFinderPattern(matrix, 0, 0); this.addFinderPattern(matrix, size - 7, 0); this.addFinderPattern(matrix, 0, size - 7); // 添加定时图案 this.addTimingPattern(matrix, size); // 添加数据(简化版本) this.addData(matrix, text, size); return matrix; } /** * 添加定位图案 */ addFinderPattern(matrix, row, col) { // 外框 for (let i = 0; i < 7; i++) { matrix[row][col + i] = true; matrix[row + 6][col + i] = true; matrix[row + i][col] = true; matrix[row + i][col + 6] = true; } // 内框 for (let i = 2; i < 5; i++) { for (let j = 2; j < 5; j++) { matrix[row + i][col + j] = true; } } } /** * 添加定时图案 */ addTimingPattern(matrix, size) { for (let i = 8; i < size - 8; i++) { matrix[6][i] = i % 2 === 0; matrix[i][6] = i % 2 === 0; } } /** * 添加数据(简化版本) */ addData(matrix, text, size) { // 将文本转换为二进制数据 const binaryData = this.textToBinary(text); let dataIndex = 0; let upward = true; // 从右下角开始填充数据 for (let col = size - 1; col > 0; col -= 2) { if (col === 6) col--; // 跳过定时图案列 for (let row = upward ? size - 1 : 0; upward ? row >= 0 : row < size; upward ? row-- : row++) { for (let c = 0; c < 2; c++) { const currentCol = col - c; if (this.isDataArea(row, currentCol, size)) { if (dataIndex < binaryData.length) { matrix[row][currentCol] = binaryData[dataIndex] === '1'; dataIndex++; } } } } upward = !upward; } } /** * 检查是否为数据区域 */ isDataArea(row, col, size) { // 检查是否在定位图案区域 if (row < 9 && col < 9) return false; if (row < 9 && col > size - 9) return false; if (row > size - 9 && col < 9) return false; // 检查是否在定时图案区域 if (row === 6 || col === 6) return false; return true; } /** * 文本转二进制 */ textToBinary(text) { let binary = ''; for (let i = 0; i < text.length; i++) { const charCode = text.charCodeAt(i); binary += charCode.toString(2).padStart(8, '0'); } return binary; } /** * 根据数据长度获取QR码版本 */ getVersion(length) { if (length <= 17) return 1; if (length <= 32) return 2; if (length <= 53) return 3; if (length <= 78) return 4; if (length <= 106) return 5; if (length <= 134) return 6; if (length <= 154) return 7; if (length <= 192) return 8; if (length <= 230) return 9; return 10; } } // 创建全局实例 window.SimpleQRCode = SimpleQRCode;