Showing
2 changed files
with
53 additions
and
4 deletions
| @@ -259,6 +259,10 @@ class HTMLRenderer: | @@ -259,6 +259,10 @@ class HTMLRenderer: | ||
| 259 | 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>' | 259 | 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>' |
| 260 | 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>' | 260 | 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>' |
| 261 | 261 | ||
| 262 | + # 加载PDF字体数据 | ||
| 263 | + pdf_font_data = self._load_pdf_font_data() | ||
| 264 | + pdf_font_script = f"<script>window.pdfFontData = '{pdf_font_data}';</script>" if pdf_font_data else "" | ||
| 265 | + | ||
| 262 | return f""" | 266 | return f""" |
| 263 | <head> | 267 | <head> |
| 264 | <meta charset="utf-8" /> | 268 | <meta charset="utf-8" /> |
| @@ -282,6 +286,7 @@ class HTMLRenderer: | @@ -282,6 +286,7 @@ class HTMLRenderer: | ||
| 282 | }}; | 286 | }}; |
| 283 | </script> | 287 | </script> |
| 284 | {mathjax_tag} | 288 | {mathjax_tag} |
| 289 | + {pdf_font_script} | ||
| 285 | <style> | 290 | <style> |
| 286 | {css} | 291 | {css} |
| 287 | </style> | 292 | </style> |
| @@ -2353,6 +2358,7 @@ pre.code-block {{ | @@ -2353,6 +2358,7 @@ pre.code-block {{ | ||
| 2353 | main {{ | 2358 | main {{ |
| 2354 | box-shadow: none; | 2359 | box-shadow: none; |
| 2355 | margin: 0; | 2360 | margin: 0; |
| 2361 | + max-width: 100%; | ||
| 2356 | }} | 2362 | }} |
| 2357 | .chapter > *, | 2363 | .chapter > *, |
| 2358 | .hero-section, | 2364 | .hero-section, |
| @@ -2364,6 +2370,7 @@ figure, | @@ -2364,6 +2370,7 @@ figure, | ||
| 2364 | blockquote {{ | 2370 | blockquote {{ |
| 2365 | break-inside: avoid; | 2371 | break-inside: avoid; |
| 2366 | page-break-inside: avoid; | 2372 | page-break-inside: avoid; |
| 2373 | + max-width: 100%; | ||
| 2367 | }} | 2374 | }} |
| 2368 | .chapter h2, | 2375 | .chapter h2, |
| 2369 | .chapter h3, | 2376 | .chapter h3, |
| @@ -2375,18 +2382,37 @@ blockquote {{ | @@ -2375,18 +2382,37 @@ blockquote {{ | ||
| 2375 | .chart-card, | 2382 | .chart-card, |
| 2376 | .table-wrap {{ | 2383 | .table-wrap {{ |
| 2377 | overflow: visible !important; | 2384 | overflow: visible !important; |
| 2385 | + max-width: 100% !important; | ||
| 2386 | + box-sizing: border-box; | ||
| 2378 | }} | 2387 | }} |
| 2379 | .chart-card canvas {{ | 2388 | .chart-card canvas {{ |
| 2380 | width: 100% !important; | 2389 | width: 100% !important; |
| 2381 | height: auto !important; | 2390 | height: auto !important; |
| 2391 | + max-width: 100% !important; | ||
| 2392 | +}} | ||
| 2393 | +.table-wrap {{ | ||
| 2394 | + overflow-x: auto; | ||
| 2395 | + max-width: 100%; | ||
| 2382 | }} | 2396 | }} |
| 2383 | .table-wrap table {{ | 2397 | .table-wrap table {{ |
| 2384 | table-layout: fixed; | 2398 | table-layout: fixed; |
| 2385 | width: 100%; | 2399 | width: 100%; |
| 2400 | + max-width: 100%; | ||
| 2386 | }} | 2401 | }} |
| 2387 | .table-wrap table th, | 2402 | .table-wrap table th, |
| 2388 | .table-wrap table td {{ | 2403 | .table-wrap table td {{ |
| 2389 | word-break: break-word; | 2404 | word-break: break-word; |
| 2405 | + overflow-wrap: break-word; | ||
| 2406 | +}} | ||
| 2407 | +/* 防止图片和图表溢出 */ | ||
| 2408 | +img, canvas, svg {{ | ||
| 2409 | + max-width: 100% !important; | ||
| 2410 | + height: auto !important; | ||
| 2411 | +}} | ||
| 2412 | +/* 确保所有容器不超出页面宽度 */ | ||
| 2413 | +* {{ | ||
| 2414 | + box-sizing: border-box; | ||
| 2415 | + max-width: 100%; | ||
| 2390 | }} | 2416 | }} |
| 2391 | }} | 2417 | }} |
| 2392 | """ | 2418 | """ |
| @@ -2858,6 +2884,9 @@ function exportPdf() { | @@ -2858,6 +2884,9 @@ function exportPdf() { | ||
| 2858 | pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', window.pdfFontData); | 2884 | pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', window.pdfFontData); |
| 2859 | pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal'); | 2885 | pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal'); |
| 2860 | pdf.setFont('SourceHanSerif'); | 2886 | pdf.setFont('SourceHanSerif'); |
| 2887 | + console.log('PDF字体已成功加载'); | ||
| 2888 | + } else { | ||
| 2889 | + console.warn('PDF字体数据未找到,将使用默认字体'); | ||
| 2861 | } | 2890 | } |
| 2862 | } catch (err) { | 2891 | } catch (err) { |
| 2863 | console.warn('Custom PDF font setup failed, fallback to default', err); | 2892 | console.warn('Custom PDF font setup failed, fallback to default', err); |
| @@ -2890,11 +2919,13 @@ function exportPdf() { | @@ -2890,11 +2919,13 @@ function exportPdf() { | ||
| 2890 | autoPaging: 'text', | 2919 | autoPaging: 'text', |
| 2891 | windowWidth: pxWidth, | 2920 | windowWidth: pxWidth, |
| 2892 | html2canvas: { | 2921 | html2canvas: { |
| 2893 | - scale: Math.min(1.2, Math.max(0.8, pageWidth / (target.clientWidth || pageWidth))), | 2922 | + scale: Math.min(1.5, Math.max(1.0, pageWidth / (target.clientWidth || pageWidth))), |
| 2894 | useCORS: true, | 2923 | useCORS: true, |
| 2895 | scrollX: 0, | 2924 | scrollX: 0, |
| 2896 | scrollY: -window.scrollY, | 2925 | scrollY: -window.scrollY, |
| 2897 | - logging: false | 2926 | + logging: false, |
| 2927 | + allowTaint: true, | ||
| 2928 | + backgroundColor: '#ffffff' | ||
| 2898 | }, | 2929 | }, |
| 2899 | pagebreak: { | 2930 | pagebreak: { |
| 2900 | mode: ['css', 'legacy'], | 2931 | mode: ['css', 'legacy'], |
| @@ -3867,6 +3867,22 @@ | @@ -3867,6 +3867,22 @@ | ||
| 3867 | throw new Error('PDF依赖未加载'); | 3867 | throw new Error('PDF依赖未加载'); |
| 3868 | } | 3868 | } |
| 3869 | const pdf = new jsPDF('p', 'mm', 'a4'); | 3869 | const pdf = new jsPDF('p', 'mm', 'a4'); |
| 3870 | + | ||
| 3871 | + // 添加中文字体支持 | ||
| 3872 | + try { | ||
| 3873 | + const fontData = iframe.contentWindow.pdfFontData || window.pdfFontData; | ||
| 3874 | + if (fontData) { | ||
| 3875 | + pdf.addFileToVFS('SourceHanSerifSC-Medium.otf', fontData); | ||
| 3876 | + pdf.addFont('SourceHanSerifSC-Medium.otf', 'SourceHanSerif', 'normal'); | ||
| 3877 | + pdf.setFont('SourceHanSerif'); | ||
| 3878 | + console.log('PDF字体已加载:SourceHanSerif'); | ||
| 3879 | + } else { | ||
| 3880 | + console.warn('PDF字体数据未找到,将使用默认字体'); | ||
| 3881 | + } | ||
| 3882 | + } catch (fontErr) { | ||
| 3883 | + console.warn('PDF字体加载失败:', fontErr); | ||
| 3884 | + } | ||
| 3885 | + | ||
| 3870 | const pageWidth = pdf.internal.pageSize.getWidth(); | 3886 | const pageWidth = pdf.internal.pageSize.getWidth(); |
| 3871 | const pxWidth = Math.max(target.scrollWidth || 0, Math.round(pageWidth * 3.78)); | 3887 | const pxWidth = Math.max(target.scrollWidth || 0, Math.round(pageWidth * 3.78)); |
| 3872 | const renderTask = pdf.html(target, { | 3888 | const renderTask = pdf.html(target, { |
| @@ -3877,11 +3893,13 @@ | @@ -3877,11 +3893,13 @@ | ||
| 3877 | margin: [10, 10, 16, 10], | 3893 | margin: [10, 10, 16, 10], |
| 3878 | autoPaging: 'text', | 3894 | autoPaging: 'text', |
| 3879 | html2canvas: { | 3895 | html2canvas: { |
| 3880 | - scale: Math.min(1.2, Math.max(0.8, pageWidth / (target.clientWidth || pageWidth))), | 3896 | + scale: Math.min(1.5, Math.max(1.0, pageWidth / (target.clientWidth || pageWidth))), |
| 3881 | useCORS: true, | 3897 | useCORS: true, |
| 3882 | scrollX: 0, | 3898 | scrollX: 0, |
| 3883 | scrollY: -iframe.contentWindow.scrollY, | 3899 | scrollY: -iframe.contentWindow.scrollY, |
| 3884 | - logging: false | 3900 | + logging: false, |
| 3901 | + allowTaint: true, | ||
| 3902 | + backgroundColor: '#ffffff' | ||
| 3885 | }, | 3903 | }, |
| 3886 | pagebreak: { | 3904 | pagebreak: { |
| 3887 | mode: ['css', 'legacy'], | 3905 | mode: ['css', 'legacy'], |
-
Please register or login to post a comment