证书配置
This commit is contained in:
parent
2180950c5e
commit
66a93af122
@ -88,7 +88,13 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
// 设置 QuestPDF 许可证
|
||||
QuestPDF.Settings.License = LicenseType.Community;
|
||||
|
||||
// 尝试配置中文字体
|
||||
// 配置 QuestPDF 字体管理
|
||||
// QuestPDF 2025.12+ 会自动使用 SkiaSharp 的字体检测
|
||||
// 我们不需要显式注册字体,只需要确保系统中有可用的中文字体
|
||||
|
||||
_logger.LogInformation("QuestPDF 配置完成,使用 SkiaSharp 字体系统");
|
||||
|
||||
// 尝试配置中文字体(检测并记录)
|
||||
ConfigureChineseFonts();
|
||||
|
||||
_logger.LogInformation("PDF 字体系统初始化完成");
|
||||
@ -102,7 +108,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置中文字体 - 增强版,支持字体文件检测和注册
|
||||
/// 配置中文字体 - 修复版,正确使用 QuestPDF 字体注册机制
|
||||
/// </summary>
|
||||
private void ConfigureChineseFonts()
|
||||
{
|
||||
@ -116,105 +122,83 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
|
||||
_logger.LogInformation($"当前操作系统: {(isLinux ? "Linux" : isWindows ? "Windows" : "其他")}");
|
||||
|
||||
// Linux 字体路径列表
|
||||
// Linux 字体路径列表(优先级排序)
|
||||
var linuxFontPaths = new[]
|
||||
{
|
||||
"/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
|
||||
"/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
|
||||
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
|
||||
"/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc",
|
||||
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
|
||||
"/usr/local/share/fonts/wqy-zenhei.ttc"
|
||||
("/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", "WenQuanYi Zen Hei"),
|
||||
("/usr/share/fonts/truetype/wqy/wqy-microhei.ttc", "WenQuanYi Micro Hei"),
|
||||
("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", "Noto Sans CJK SC"),
|
||||
("/usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc", "Noto Sans CJK SC"),
|
||||
("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", "DejaVu Sans"),
|
||||
("/usr/local/share/fonts/wqy-zenhei.ttc", "WenQuanYi Zen Hei")
|
||||
};
|
||||
|
||||
// Windows 字体路径列表
|
||||
// Windows 字体路径列表(优先级排序)
|
||||
var windowsFontPaths = new[]
|
||||
{
|
||||
@"C:\Windows\Fonts\msyh.ttc", // 微软雅黑
|
||||
@"C:\Windows\Fonts\simsun.ttc", // 宋体
|
||||
@"C:\Windows\Fonts\simhei.ttf" // 黑体
|
||||
(@"C:\Windows\Fonts\msyh.ttc", "Microsoft YaHei"), // 微软雅黑
|
||||
(@"C:\Windows\Fonts\simsun.ttc", "SimSun"), // 宋体
|
||||
(@"C:\Windows\Fonts\simhei.ttf", "SimHei"), // 黑体
|
||||
(@"C:\Windows\Fonts\msyhl.ttc", "Microsoft YaHei Light"),
|
||||
(@"C:\Windows\Fonts\simkai.ttf", "KaiTi")
|
||||
};
|
||||
|
||||
string fontPathToRegister = null;
|
||||
string fontNameToUse = null;
|
||||
|
||||
// 尝试查找字体文件
|
||||
if (isLinux)
|
||||
// 尝试查找并注册字体文件
|
||||
var fontPathsToCheck = isLinux ? linuxFontPaths : windowsFontPaths;
|
||||
foreach (var (path, name) in fontPathsToCheck)
|
||||
{
|
||||
_logger.LogInformation("正在 Linux 系统中查找字体文件...");
|
||||
foreach (var path in linuxFontPaths)
|
||||
if (File.Exists(path))
|
||||
{
|
||||
if (File.Exists(path))
|
||||
_logger.LogInformation($"找到字体文件: {path} ({name})");
|
||||
fontPathToRegister = path;
|
||||
fontNameToUse = name;
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation($"找到字体文件: {path}");
|
||||
fontPathToRegister = path;
|
||||
// 尝试在 QuestPDF 中注册字体(如果支持)
|
||||
// QuestPDF 会自动搜索系统字体,也可以显式注册
|
||||
_logger.LogInformation($"尝试注册字体: {fontNameToUse}");
|
||||
|
||||
if (path.Contains("wqy-zenhei")) fontNameToUse = "WenQuanYi Zen Hei";
|
||||
else if (path.Contains("wqy-microhei")) fontNameToUse = "WenQuanYi Micro Hei";
|
||||
else if (path.Contains("Noto")) fontNameToUse = "Noto Sans CJK SC";
|
||||
else if (path.Contains("DejaVu")) fontNameToUse = "DejaVu Sans";
|
||||
else fontNameToUse = "CustomChineseFont";
|
||||
|
||||
break;
|
||||
// 先测试字体是否可用
|
||||
if (TestFontAvailability(fontNameToUse))
|
||||
{
|
||||
_selectedChineseFont = fontNameToUse;
|
||||
_logger.LogInformation($"字体配置成功: {_selectedChineseFont}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug($"字体文件不存在: {path}");
|
||||
_logger.LogWarning(ex, $"字体注册失败: {fontNameToUse},继续尝试下一个...");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isWindows)
|
||||
{
|
||||
_logger.LogInformation("正在 Windows 系统中查找字体文件...");
|
||||
foreach (var path in windowsFontPaths)
|
||||
else
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
_logger.LogInformation($"找到字体文件: {path}");
|
||||
fontPathToRegister = path;
|
||||
|
||||
if (path.Contains("msyh")) fontNameToUse = "Microsoft YaHei";
|
||||
else if (path.Contains("simsun")) fontNameToUse = "SimSun";
|
||||
else if (path.Contains("simhei")) fontNameToUse = "SimHei";
|
||||
else fontNameToUse = "CustomChineseFont";
|
||||
|
||||
break;
|
||||
}
|
||||
_logger.LogDebug($"字体文件不存在: {path}");
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找到了字体文件,尝试显式注册
|
||||
if (!string.IsNullOrEmpty(fontPathToRegister))
|
||||
// 如果没有找到字体文件,尝试使用备选字体名称
|
||||
if (string.IsNullOrEmpty(_selectedChineseFont))
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation($"正在注册字体: {fontNameToUse} ({fontPathToRegister})");
|
||||
|
||||
// 注意:QuestPDF 可能不支持直接从文件路径注册
|
||||
// 我们采用替代方案:记录字体名称,并在生成时强制使用
|
||||
_selectedChineseFont = fontNameToUse;
|
||||
_logger.LogInformation($"字体配置完成: {_selectedChineseFont}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, $"字体注册失败,将尝试自动查找: {fontNameToUse}");
|
||||
_selectedChineseFont = fontNameToUse; // 仍然记录下来
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("未找到字体文件,将使用备选字体列表...");
|
||||
_logger.LogWarning("未找到字体文件,使用备选字体名称列表...");
|
||||
|
||||
// 备选字体名称列表
|
||||
// 备选字体名称列表(按优先级)
|
||||
var chineseFontNames = new[]
|
||||
{
|
||||
"WenQuanYi Zen Hei",
|
||||
"WenQuanYi Micro Hei",
|
||||
"Noto Sans CJK SC",
|
||||
"Microsoft YaHei",
|
||||
"SimSun",
|
||||
"SimHei",
|
||||
"DejaVu Sans"
|
||||
"WenQuanYi Zen Hei",
|
||||
"WenQuanYi Micro Hei",
|
||||
"Noto Sans CJK SC",
|
||||
"DejaVu Sans",
|
||||
"Arial Unicode MS",
|
||||
"PingFang SC",
|
||||
"STSong"
|
||||
};
|
||||
|
||||
foreach (var fontName in chineseFontNames)
|
||||
@ -229,8 +213,9 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, $"字体不可用: {fontName}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -241,6 +226,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
_logger.LogError("请在系统中安装中文字体:");
|
||||
_logger.LogError(" Ubuntu/Debian: sudo apt-get install fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk");
|
||||
_logger.LogError(" CentOS/RHEL: sudo yum install wqy-microhei-fonts wqy-zenhei-fonts");
|
||||
_logger.LogError(" Windows: 确保系统中有微软雅黑或宋体");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1265,7 +1251,7 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用QuestPDF生成PDF - 增强版,确保中文字体被正确应用
|
||||
/// 使用QuestPDF生成PDF - 修复版,确保中文字体被正确应用
|
||||
/// </summary>
|
||||
private async Task GeneratePdfWithQuestPDF(Stream pdfStream, DocumentData documentData)
|
||||
{
|
||||
@ -1279,16 +1265,42 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
var fontFallbackList = new[]
|
||||
{
|
||||
chineseFontName,
|
||||
"Microsoft YaHei",
|
||||
"SimSun",
|
||||
"SimHei",
|
||||
"WenQuanYi Zen Hei",
|
||||
"WenQuanYi Micro Hei",
|
||||
"Noto Sans CJK SC",
|
||||
"Microsoft YaHei",
|
||||
"SimSun",
|
||||
"DejaVu Sans"
|
||||
"DejaVu Sans",
|
||||
"Arial Unicode MS"
|
||||
}.Where(f => !string.IsNullOrEmpty(f)).Distinct().ToArray();
|
||||
|
||||
_logger.LogInformation($"字体回退列表: {string.Join(", ", fontFallbackList)}");
|
||||
|
||||
// 选择最终要使用的字体(尝试测试每一个)
|
||||
string finalFont = null;
|
||||
foreach (var font in fontFallbackList)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (TestFontAvailability(font))
|
||||
{
|
||||
finalFont = font;
|
||||
_logger.LogInformation($"选择最终字体: {finalFont}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(finalFont))
|
||||
{
|
||||
_logger.LogWarning("未找到可用字体,将使用 QuestPDF 默认字体");
|
||||
}
|
||||
|
||||
var questDocument = QuestPDF.Fluent.Document.Create(container =>
|
||||
{
|
||||
container.Page(page =>
|
||||
@ -1296,23 +1308,22 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
page.Margin(0);
|
||||
page.Size(PageSizes.A4);
|
||||
|
||||
// 设置默认文本样式 - 强制应用字体
|
||||
// 设置默认文本样式 - 使用选定的中文字体
|
||||
page.DefaultTextStyle(x =>
|
||||
{
|
||||
var style = x.FontSize(12).FontColor(QuestPDF.Helpers.Colors.Black);
|
||||
|
||||
// 尝试应用每一个字体,直到成功
|
||||
foreach (var font in fontFallbackList)
|
||||
// 应用选定的字体
|
||||
if (!string.IsNullOrEmpty(finalFont))
|
||||
{
|
||||
try
|
||||
{
|
||||
style = style.FontFamily(font);
|
||||
_logger.LogDebug($"尝试应用字体到默认样式: {font}");
|
||||
break; // 成功应用一个就停止
|
||||
style = style.FontFamily(finalFont);
|
||||
_logger.LogDebug($"应用字体到默认样式: {finalFont}");
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
continue;
|
||||
_logger.LogWarning(ex, $"应用字体 {finalFont} 失败,使用默认字体");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1327,11 +1338,9 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
.FitArea();
|
||||
}
|
||||
|
||||
// 使用 Column 来放置所有内容,但禁用默认间距
|
||||
page.Content().Column(column =>
|
||||
// 使用绝对定位来放置文本内容(更精确)
|
||||
page.Content().Layer(layer =>
|
||||
{
|
||||
column.Spacing(0);
|
||||
|
||||
double? firstParagraphY = null;
|
||||
double? firstParagraphOriginalY = null;
|
||||
|
||||
@ -1366,24 +1375,26 @@ public class CertificateGenerateService : IDynamicApiController, ITransient
|
||||
|
||||
_logger.LogDebug("段落 {Index} 位置: X={X}, Y={Y}", i + 1, x, y);
|
||||
|
||||
// 使用 Translate 来定位,配合 Spacing(0) 确保没有额外间隔
|
||||
var textElement = column.Item().TranslateX(x).TranslateY(y).Text(paragraph.Text)
|
||||
// 使用绝对定位放置文本
|
||||
var textElement = layer
|
||||
.TranslateX(x)
|
||||
.TranslateY(y)
|
||||
.Text(paragraph.Text)
|
||||
.FontSize((float)fontSize)
|
||||
.FontColor(QuestPDF.Helpers.Colors.Black)
|
||||
.AlignLeft();
|
||||
|
||||
// 尝试应用每一个字体到这个文本元素
|
||||
foreach (var font in fontFallbackList)
|
||||
// 应用选定的字体
|
||||
if (!string.IsNullOrEmpty(finalFont))
|
||||
{
|
||||
try
|
||||
{
|
||||
textElement = textElement.FontFamily(font);
|
||||
_logger.LogDebug($"段落 {i + 1} 应用字体: {font}");
|
||||
break;
|
||||
textElement = textElement.FontFamily(finalFont);
|
||||
_logger.LogDebug($"段落 {i + 1} 应用字体: {finalFont}");
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
continue;
|
||||
_logger.LogDebug(ex, $"段落 {i + 1} 应用字体失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user