import { Sprite, SpriteFrame, Texture2D, ImageAsset, Node } from 'cc'; import qrcode from 'qrcode-generator'; import { logger } from "db://assets/Scripts/Main/Common/Logger"; /** * 二维码生成工具类 * 提供生成二维码Sprite的静态方法 */ export class QRCodeGenerator { /** * 生成二维码 Sprite 组件(异步版本) * @param text 要生成二维码的文本内容 * @param size 二维码尺寸,默认256x256 * @param margin 二维码边距,默认4 * @param callback 完成回调函数 */ public static generateQRCodeSprite(text: string, size: number = 256, margin: number = 4, callback?: (sprite: Sprite | null) => void): void { try { if (!text || text.trim().length === 0) { logger.error('QRCodeGenerator: 文本内容不能为空'); callback && callback(null); return; } this.generateQRCodeSpriteFrame(text, size, margin, (spriteFrame) => { if (!spriteFrame) { callback && callback(null); return; } try { // 创建新节点和Sprite组件 const node = new Node('QRCode'); const sprite = node.addComponent(Sprite); sprite.spriteFrame = spriteFrame; callback && callback(sprite); } catch (error) { logger.error('QRCodeGenerator: 创建Sprite组件失败', error); callback && callback(null); } }); } catch (error) { logger.error('QRCodeGenerator: 生成二维码Sprite失败', error); callback && callback(null); } } /** * 生成二维码 SpriteFrame(异步版本) * @param text 要生成二维码的文本内容 * @param size 二维码尺寸,默认256x256 * @param margin 二维码边距,默认4 * @param callback 完成回调函数 */ public static generateQRCodeSpriteFrame(text: string, size: number = 256, margin: number = 4, callback?: (spriteFrame: SpriteFrame | null) => void): void { try { if (!text || text.trim().length === 0) { logger.error('QRCodeGenerator: 文本内容不能为空'); callback && callback(null); return; } if (size <= 0 || size > 2048) { logger.error('QRCodeGenerator: 尺寸必须在1-2048之间'); callback && callback(null); return; } // 生成二维码 const qr = qrcode(0, 'M'); // 0表示自动类型选择,'M'表示中等纠错级别 qr.addData(text); qr.make(); // 创建Canvas绘制二维码 const moduleCount = qr.getModuleCount(); const cellSize = Math.floor((size - 2 * margin) / moduleCount); const actualSize = cellSize * moduleCount + 2 * margin; const canvas = document.createElement('canvas'); canvas.width = actualSize; canvas.height = actualSize; const ctx = canvas.getContext('2d'); if (!ctx) { logger.error('QRCodeGenerator: 无法获取Canvas上下文'); callback && callback(null); return; } // 绘制白色背景 ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, actualSize, actualSize); // 绘制二维码 ctx.fillStyle = '#000000'; for (let row = 0; row < moduleCount; row++) { for (let col = 0; col < moduleCount; col++) { if (qr.isDark(row, col)) { ctx.fillRect( margin + col * cellSize, margin + row * cellSize, cellSize, cellSize ); } } } // 使用异步方式处理图片创建 const img = new Image(); img.onload = () => { try { // 创建ImageAsset并直接设置图片数据 const imageAsset = new ImageAsset(img); // 创建Texture2D并设置ImageAsset const texture = new Texture2D(); texture.image = imageAsset; // 创建SpriteFrame并设置纹理 const spriteFrame = new SpriteFrame(); spriteFrame.texture = texture; callback && callback(spriteFrame); } catch (error) { logger.error('QRCodeGenerator: 创建纹理失败', error); callback && callback(null); } }; img.onerror = () => { logger.error('QRCodeGenerator: 图片加载失败'); callback && callback(null); }; // 设置图片源,触发加载 img.src = canvas.toDataURL('image/png'); } catch (error) { logger.error('QRCodeGenerator: 生成二维码SpriteFrame失败', error); callback && callback(null); } } /** * 生成二维码的Base64字符串 * @param text 要生成二维码的文本内容 * @param size 二维码尺寸,默认256x256 * @param margin 二维码边距,默认4 * @returns 二维码的Base64字符串,失败时返回空字符串 */ public static generateQRCodeBase64(text: string, size: number = 256, margin: number = 4): string { try { if (!text || text.trim().length === 0) { logger.error('QRCodeGenerator: 文本内容不能为空'); return ''; } // 生成二维码 const qr = qrcode(0, 'M'); qr.addData(text); qr.make(); // 创建Canvas绘制二维码 const moduleCount = qr.getModuleCount(); const cellSize = Math.floor((size - 2 * margin) / moduleCount); const actualSize = cellSize * moduleCount + 2 * margin; const canvas = document.createElement('canvas'); canvas.width = actualSize; canvas.height = actualSize; const ctx = canvas.getContext('2d'); if (!ctx) { logger.error('QRCodeGenerator: 无法获取Canvas上下文'); return ''; } // 绘制白色背景 ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, actualSize, actualSize); // 绘制二维码 ctx.fillStyle = '#000000'; for (let row = 0; row < moduleCount; row++) { for (let col = 0; col < moduleCount; col++) { if (qr.isDark(row, col)) { ctx.fillRect( margin + col * cellSize, margin + row * cellSize, cellSize, cellSize ); } } } // 返回Base64字符串 return canvas.toDataURL('image/png'); } catch (error) { logger.error('QRCodeGenerator: 生成二维码Base64失败', error); return ''; } } }