using System; using System.IO; using QRCoder; using Furion.DependencyInjection; namespace YD_Event.Core.Certificate { /// /// 二维码服务 /// public class QRCodeService : ITransient { /// /// 生成二维码图片 /// /// 二维码内容 /// 二维码尺寸(像素) /// Logo图片路径(可选) /// 二维码图片流 public Stream GenerateQRCode(string content, int size = 200, string logoPath = null) { using (var qrGenerator = new QRCodeGenerator()) { var qrCodeData = qrGenerator.CreateQrCode(content, QRCodeGenerator.ECCLevel.M); // 使用PngByteQRCode来避免Bitmap依赖 var qrCode = new PngByteQRCode(qrCodeData); var qrCodeBytes = qrCode.GetGraphic( pixelsPerModule: CalculatePixelsPerModule(size)); var outputStream = new MemoryStream(qrCodeBytes); outputStream.Position = 0; return outputStream; } } /// /// 生成证书二维码URL /// /// 证书ID /// 基础URL /// 证书查看URL public string GenerateCertificateUrl(long certificateId, string baseUrl) { if (string.IsNullOrWhiteSpace(baseUrl)) throw new ArgumentException("Base URL cannot be null or empty", nameof(baseUrl)); var normalizedBaseUrl = baseUrl.TrimEnd('/'); return $"{normalizedBaseUrl}/certificate/view/{certificateId}"; } /// /// 生成证书PDF下载URL /// /// 证书ID /// PDF文件URL /// PDF下载URL public string GeneratePdfUrl(long certificateId, string pdfUrl) { if (string.IsNullOrWhiteSpace(pdfUrl)) throw new ArgumentException("PDF URL cannot be null or empty", nameof(pdfUrl)); return pdfUrl; } /// /// 生成带验证信息的二维码内容 /// /// 证书ID /// 验证码 /// 基础URL /// 验证URL public string GenerateVerificationUrl(long certificateId, string verificationCode, string baseUrl) { if (string.IsNullOrWhiteSpace(baseUrl)) throw new ArgumentException("Base URL cannot be null or empty", nameof(baseUrl)); if (string.IsNullOrWhiteSpace(verificationCode)) throw new ArgumentException("Verification code cannot be null or empty", nameof(verificationCode)); var normalizedBaseUrl = baseUrl.TrimEnd('/'); return $"{normalizedBaseUrl}/certificate/verify/{certificateId}?code={verificationCode}"; } /// /// 计算每个模块的像素数 /// /// 期望的二维码尺寸 /// 每个模块的像素数 private int CalculatePixelsPerModule(int desiredSize) { // 标准二维码是25x25或21x21模块,这里按25计算 const int standardModules = 25; return Math.Max(1, desiredSize / standardModules); } /// /// 验证二维码内容 /// /// 二维码内容 /// 是否有效 public bool ValidateQRContent(string content) { if (string.IsNullOrWhiteSpace(content)) return false; // 检查内容长度(二维码有容量限制) if (content.Length > 2953) // 数字模式的最大容量 return false; // 检查是否为有效URL或文本 return Uri.TryCreate(content, UriKind.Absolute, out _) || !content.Contains(" "); } /// /// 生成带样式的二维码 /// /// 二维码内容 /// 二维码选项 /// 二维码图片流 public Stream GenerateStyledQRCode(string content, QRCodeOptions options) { using (var qrGenerator = new QRCodeGenerator()) { var eccLevel = GetECCLevel(options.ErrorCorrectionLevel); var qrCodeData = qrGenerator.CreateQrCode(content, eccLevel); // 使用PngByteQRCode来避免Bitmap依赖 var qrCode = new PngByteQRCode(qrCodeData); var pixelsPerModule = options.Size > 0 ? CalculatePixelsPerModule(options.Size) : 10; var qrCodeBytes = qrCode.GetGraphic(pixelsPerModule: pixelsPerModule); var outputStream = new MemoryStream(qrCodeBytes); outputStream.Position = 0; return outputStream; } } /// /// 获取错误纠正级别 /// /// 级别字符串 /// ECC级别 private QRCodeGenerator.ECCLevel GetECCLevel(string level) { return level?.ToUpperInvariant() switch { "L" => QRCodeGenerator.ECCLevel.L, "M" => QRCodeGenerator.ECCLevel.M, "Q" => QRCodeGenerator.ECCLevel.Q, "H" => QRCodeGenerator.ECCLevel.H, _ => QRCodeGenerator.ECCLevel.M }; } } /// /// 二维码选项 /// public class QRCodeOptions { /// /// 二维码尺寸(像素) /// public int Size { get; set; } = 200; /// /// 深色(十六进制颜色代码) /// public string DarkColor { get; set; } /// /// 浅色(十六进制颜色代码) /// public string LightColor { get; set; } /// /// Logo图片路径 /// public string LogoPath { get; set; } /// /// 错误纠正级别:L(7%), M(15%), Q(25%), H(30%) /// public string ErrorCorrectionLevel { get; set; } = "M"; /// /// 是否绘制静区 /// public bool DrawQuietZones { get; set; } = true; } }