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