Solving the Problem of Garbled Characters in PDF Rendering

This commit is contained in:
马一丁
2025-11-18 14:21:41 +08:00
parent 85d75d6f74
commit 1a302ca975
2 changed files with 53 additions and 4 deletions
+33 -2
View File
@@ -259,6 +259,10 @@ class HTMLRenderer:
jspdf_tag = f"<script>{jspdf}</script>" if jspdf else '<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>' jspdf_tag = f"<script>{jspdf}</script>" if jspdf else '<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>'
mathjax_tag = f"<script defer>{mathjax}</script>" if mathjax else '<script defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>' mathjax_tag = f"<script defer>{mathjax}</script>" if mathjax else '<script defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>'
# 加载PDF字体数据
pdf_font_data = self._load_pdf_font_data()
pdf_font_script = f"<script>window.pdfFontData = '{pdf_font_data}';</script>" if pdf_font_data else ""
return f""" return f"""
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@@ -282,6 +286,7 @@ class HTMLRenderer:
}}; }};
</script> </script>
{mathjax_tag} {mathjax_tag}
{pdf_font_script}
<style> <style>
{css} {css}
</style> </style>
@@ -2353,6 +2358,7 @@ pre.code-block {{
main {{ main {{
box-shadow: none; box-shadow: none;
margin: 0; margin: 0;
max-width: 100%;
}} }}
.chapter > *, .chapter > *,
.hero-section, .hero-section,
@@ -2364,6 +2370,7 @@ figure,
blockquote {{ blockquote {{
break-inside: avoid; break-inside: avoid;
page-break-inside: avoid; page-break-inside: avoid;
max-width: 100%;
}} }}
.chapter h2, .chapter h2,
.chapter h3, .chapter h3,
@@ -2375,18 +2382,37 @@ blockquote {{
.chart-card, .chart-card,
.table-wrap {{ .table-wrap {{
overflow: visible !important; overflow: visible !important;
max-width: 100% !important;
box-sizing: border-box;
}} }}
.chart-card canvas {{ .chart-card canvas {{
width: 100% !important; width: 100% !important;
height: auto !important; height: auto !important;
max-width: 100% !important;
}}
.table-wrap {{
overflow-x: auto;
max-width: 100%;
}} }}
.table-wrap table {{ .table-wrap table {{
table-layout: fixed; table-layout: fixed;
width: 100%; width: 100%;
max-width: 100%;
}} }}
.table-wrap table th, .table-wrap table th,
.table-wrap table td {{ .table-wrap table td {{
word-break: break-word; word-break: break-word;
overflow-wrap: break-word;
}}
/* 防止图片和图表溢出 */
img, canvas, svg {{
max-width: 100% !important;
height: auto !important;
}}
/* 确保所有容器不超出页面宽度 */
* {{
box-sizing: border-box;
max-width: 100%;
}} }}
}} }}
""" """
@@ -2858,6 +2884,9 @@ function exportPdf() {
pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', window.pdfFontData); pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', window.pdfFontData);
pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal'); pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal');
pdf.setFont('SourceHanSerif'); pdf.setFont('SourceHanSerif');
console.log('PDF字体已成功加载');
} else {
console.warn('PDF字体数据未找到,将使用默认字体');
} }
} catch (err) { } catch (err) {
console.warn('Custom PDF font setup failed, fallback to default', err); console.warn('Custom PDF font setup failed, fallback to default', err);
@@ -2890,11 +2919,13 @@ function exportPdf() {
autoPaging: 'text', autoPaging: 'text',
windowWidth: pxWidth, windowWidth: pxWidth,
html2canvas: { html2canvas: {
scale: Math.min(1.2, Math.max(0.8, pageWidth / (target.clientWidth || pageWidth))), scale: Math.min(1.5, Math.max(1.0, pageWidth / (target.clientWidth || pageWidth))),
useCORS: true, useCORS: true,
scrollX: 0, scrollX: 0,
scrollY: -window.scrollY, scrollY: -window.scrollY,
logging: false logging: false,
allowTaint: true,
backgroundColor: '#ffffff'
}, },
pagebreak: { pagebreak: {
mode: ['css', 'legacy'], mode: ['css', 'legacy'],
+20 -2
View File
@@ -3867,6 +3867,22 @@
throw new Error('PDF依赖未加载'); throw new Error('PDF依赖未加载');
} }
const pdf = new jsPDF('p', 'mm', 'a4'); const pdf = new jsPDF('p', 'mm', 'a4');
// 添加中文字体支持
try {
const fontData = iframe.contentWindow.pdfFontData || window.pdfFontData;
if (fontData) {
pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', fontData);
pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal');
pdf.setFont('SourceHanSerif');
console.log('PDF字体已加载:SourceHanSerif');
} else {
console.warn('PDF字体数据未找到,将使用默认字体');
}
} catch (fontErr) {
console.warn('PDF字体加载失败:', fontErr);
}
const pageWidth = pdf.internal.pageSize.getWidth(); const pageWidth = pdf.internal.pageSize.getWidth();
const pxWidth = Math.max(target.scrollWidth || 0, Math.round(pageWidth * 3.78)); const pxWidth = Math.max(target.scrollWidth || 0, Math.round(pageWidth * 3.78));
const renderTask = pdf.html(target, { const renderTask = pdf.html(target, {
@@ -3877,11 +3893,13 @@
margin: [10, 10, 16, 10], margin: [10, 10, 16, 10],
autoPaging: 'text', autoPaging: 'text',
html2canvas: { html2canvas: {
scale: Math.min(1.2, Math.max(0.8, pageWidth / (target.clientWidth || pageWidth))), scale: Math.min(1.5, Math.max(1.0, pageWidth / (target.clientWidth || pageWidth))),
useCORS: true, useCORS: true,
scrollX: 0, scrollX: 0,
scrollY: -iframe.contentWindow.scrollY, scrollY: -iframe.contentWindow.scrollY,
logging: false logging: false,
allowTaint: true,
backgroundColor: '#ffffff'
}, },
pagebreak: { pagebreak: {
mode: ['css', 'legacy'], mode: ['css', 'legacy'],