Files
18xchat/assets/utils/qrcodeGenerator.ts
T
2025-09-21 20:36:25 +08:00

210 lines
7.4 KiB
TypeScript

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 '';
}
}
}