pdf-composer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # pdf-composer
2
+
3
+ 将组合多种内容转换为 PDF 文件的 JavaScript/TypeScript 库,支持浏览器环境。
4
+
5
+ ## 特性
6
+
7
+ - 🚀 **简单易用** - 一行代码将 Markdown 转换为 PDF
8
+ - 📦 **TypeScript 支持** - 完整的类型定义
9
+ - 🎨 **样式丰富** - 内置美观的 Markdown 样式
10
+ - 📄 **多页支持** - 自动分页处理
11
+ - 🖼️ **Mermaid 支持** - 可选集成 Mermaid 图表
12
+ - ⚙️ **高度可配置** - 支持自定义页面大小、方向、边距等
13
+
14
+ ## 安装
15
+
16
+ ```bash
17
+ npm install pdf-composer
18
+ ```
19
+
20
+ 或使用 yarn:
21
+
22
+ ```bash
23
+ yarn add pdf-composer
24
+ ```
25
+
26
+ ## 快速开始
27
+
28
+ ### 基础用法
29
+
30
+ ```javascript
31
+ import { generationPDF } from 'pdf-composer';
32
+
33
+ const markdown = `
34
+ # 标题
35
+
36
+ 这是一段 **Markdown** 文本。
37
+
38
+ ## 列表示例
39
+
40
+ - 项目 1
41
+ - 项目 2
42
+ - 项目 3
43
+
44
+ ## 代码示例
45
+
46
+ \`\`\`javascript
47
+ function hello() {
48
+ console.log('Hello, World!');
49
+ }
50
+ \`\`\`
51
+ `;
52
+
53
+ // 生成 PDF
54
+ const result = await generationPDF(markdown, undefined, 'example.pdf');
55
+
56
+ if (result.success) {
57
+ console.log(`PDF 生成成功,共 ${result.pageCount} 页`);
58
+ } else {
59
+ console.error('PDF 生成失败:', result.error);
60
+ }
61
+ ```
62
+
63
+ ### 高级用法(使用选项对象)
64
+
65
+ ```javascript
66
+ import { generationPDFWithOptions } from 'pdf-composer';
67
+
68
+ const result = await generationPDFWithOptions({
69
+ markdownText: markdown,
70
+ fileName: 'output.pdf',
71
+ pageFormat: 'a4', // 页面大小: 'a3' | 'a4' | 'letter' | 'legal'
72
+ orientation: 'p', // 方向: 'p'(纵向) | 'l'(横向)
73
+ padding: 10, // 页边距 (mm)
74
+ scale: 2, // 渲染缩放比例
75
+ containerWidth: 1200, // 容器宽度 (px)
76
+ containerPadding: 40 // 容器内边距 (px)
77
+ });
78
+ ```
79
+
80
+ ### 结合 Mermaid 使用
81
+
82
+ ```html
83
+ <!DOCTYPE html>
84
+ <html>
85
+ <head>
86
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
87
+ <script type="module">
88
+ import { generationPDF } from 'pdf-composer';
89
+
90
+ // 初始化 Mermaid
91
+ mermaid.initialize({ startOnLoad: true });
92
+
93
+ async function exportPdf() {
94
+ const markdown = `
95
+ # 流程图示例
96
+
97
+ 下面是一个流程图:
98
+ `;
99
+
100
+ // mermaid-preview 是包含 Mermaid SVG 的 DOM 元素 ID
101
+ const result = await generationPDF(markdown, 'mermaid-preview', 'diagram.pdf');
102
+ }
103
+ </script>
104
+ </head>
105
+ <body>
106
+ <div id="mermaid-preview">
107
+ <pre class="mermaid">
108
+ graph LR
109
+ A[开始] --> B{判断}
110
+ B -->|是| C[操作A]
111
+ B -->|否| D[操作B]
112
+ </pre>
113
+ </div>
114
+ <button onclick="exportPdf()">导出 PDF</button>
115
+ </body>
116
+ </html>
117
+ ```
118
+
119
+ ## API 文档
120
+
121
+ ### `generationPDF(markdownText, mermaidDomId?, fileName?)`
122
+
123
+ 基础 PDF 生成函数。
124
+
125
+ **参数:**
126
+
127
+ | 参数 | 类型 | 必填 | 默认值 | 描述 |
128
+ |------|------|------|--------|------|
129
+ | `markdownText` | `string` | 是 | - | Markdown 文本内容 |
130
+ | `mermaidDomId` | `string` | 否 | `undefined` | 包含 Mermaid SVG 的 DOM 元素 ID |
131
+ | `fileName` | `string` | 否 | `'output.pdf'` | 输出的 PDF 文件名 |
132
+
133
+ **返回值:**
134
+
135
+ ```typescript
136
+ interface GenerationPdfResult {
137
+ success: boolean; // 是否成功
138
+ pageCount?: number; // 生成的页数
139
+ error?: Error; // 错误信息(失败时)
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ### `generationPDFWithOptions(options)`
146
+
147
+ 高级 PDF 生成函数,支持更多配置选项。
148
+
149
+ **参数:**
150
+
151
+ ```typescript
152
+ interface GenerationPdfOptions {
153
+ markdownText: string; // Markdown 文本内容(必填)
154
+ mermaidDomId?: string; // Mermaid DOM 元素 ID
155
+ fileName?: string; // 输出文件名,默认 'output.pdf'
156
+ containerWidth?: number; // 容器宽度,默认 1200
157
+ containerPadding?: number; // 容器内边距,默认 40
158
+ scale?: number; // 渲染缩放比例,默认 2
159
+ pageFormat?: 'a3' | 'a4' | 'letter' | 'legal'; // 页面大小,默认 'a4'
160
+ orientation?: 'p' | 'l'; // 页面方向,默认 'p'(纵向)
161
+ padding?: number; // 页边距,默认 10
162
+ }
163
+ ```
164
+
165
+ **返回值:** 同 `generationPDF`
166
+
167
+ ## 依赖说明
168
+
169
+ 本库依赖以下 npm 包:
170
+
171
+ - [marked](https://www.npmjs.com/package/marked) - Markdown 解析器
172
+ - [html2canvas](https://www.npmjs.com/package/html2canvas) - HTML 转 Canvas
173
+ - [jspdf](https://www.npmjs.com/package/jspdf) - PDF 生成
174
+
175
+ **注意:** Mermaid 不包含在本库中,如需使用 Mermaid 图表,请通过 CDN 加载:
176
+
177
+ ```html
178
+ <script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
179
+ ```
180
+
181
+ ## 浏览器兼容性
182
+
183
+ 本库仅支持浏览器环境,不支持 Node.js。
184
+
185
+ 支持的浏览器:
186
+ - Chrome >= 60
187
+ - Firefox >= 55
188
+ - Safari >= 11
189
+ - Edge >= 79
190
+
191
+ ## 开发
192
+
193
+ ```bash
194
+ # 安装依赖
195
+ npm install
196
+
197
+ # 构建
198
+ npm run build
199
+ ```
200
+
201
+ ## 许可证
202
+
203
+ MIT
@@ -0,0 +1,19 @@
1
+ export interface GenerationPdfOptions {
2
+ markdownText: string;
3
+ mermaidDomId?: string;
4
+ fileName?: string;
5
+ containerWidth?: number;
6
+ containerPadding?: number;
7
+ scale?: number;
8
+ pageFormat?: 'a3' | 'a4' | 'letter' | 'legal';
9
+ orientation?: 'p' | 'l';
10
+ padding?: number;
11
+ }
12
+ export interface GenerationPdfResult {
13
+ success: boolean;
14
+ pageCount?: number;
15
+ error?: Error;
16
+ }
17
+ export declare function generationPDF(markdownText: string, mermaidDomId?: string, fileName?: string): Promise<GenerationPdfResult>;
18
+ export declare function generationPDFWithOptions(options: GenerationPdfOptions): Promise<GenerationPdfResult>;
19
+ export default generationPDF;
@@ -0,0 +1,129 @@
1
+ import { parse } from 'marked';
2
+ import html2canvas from 'html2canvas';
3
+ import { jsPDF } from 'jspdf';
4
+ const DEFAULT_STYLES = `
5
+ h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
6
+ h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
7
+ h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
8
+ h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
9
+ h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
10
+ h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
11
+ p { margin: 12px 0; color: #2c3e50; }
12
+ ul, ol { padding-left: 30px; margin: 12px 0; }
13
+ li { margin: 8px 0; }
14
+ code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
15
+ pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
16
+ pre code { background: none; padding: 0; color: inherit; }
17
+ blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
18
+ table { width: 100%; border-collapse: collapse; margin: 16px 0; }
19
+ th, td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
20
+ th { background: #f8f9fa; font-weight: bold; }
21
+ a { color: #667eea; text-decoration: none; }
22
+ hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
23
+ img { max-width: 100%; height: auto; }
24
+ `;
25
+ const PAGE_SIZES = {
26
+ a3: { width: 297, height: 420 },
27
+ a4: { width: 210, height: 297 },
28
+ letter: { width: 215.9, height: 279.4 },
29
+ legal: { width: 215.9, height: 355.6 }
30
+ };
31
+ export async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
32
+ return generationPDFWithOptions({
33
+ markdownText,
34
+ mermaidDomId,
35
+ fileName
36
+ });
37
+ }
38
+ export async function generationPDFWithOptions(options) {
39
+ const { markdownText, mermaidDomId, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
40
+ try {
41
+ const markdownHtml = parse(markdownText);
42
+ const exportContainer = document.createElement('div');
43
+ exportContainer.id = 'pdf-export-container';
44
+ exportContainer.style.cssText = `
45
+ position: absolute;
46
+ left: -2000px;
47
+ top: -2000px;
48
+ width: ${containerWidth}px;
49
+ padding: ${containerPadding}px;
50
+ background: white;
51
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Microsoft YaHei, sans-serif;
52
+ font-size: 18px;
53
+ line-height: 1.8;
54
+ `;
55
+ exportContainer.innerHTML = `
56
+ <style>${DEFAULT_STYLES}</style>
57
+ <div style="max-width: ${containerWidth - containerPadding * 2}px; margin: 0 auto;">
58
+ ${markdownHtml}
59
+ </div>
60
+ `;
61
+ if (mermaidDomId) {
62
+ const mermaidEl = document.getElementById(mermaidDomId);
63
+ if (mermaidEl) {
64
+ const svg = mermaidEl.querySelector('svg');
65
+ if (svg) {
66
+ const svgWrapper = document.createElement('div');
67
+ svgWrapper.style.cssText = 'margin: 25px 0; text-align: center;';
68
+ const svgClone = svg.cloneNode(true);
69
+ svgClone.style.cssText = 'max-width: 1000px; width: 100%; height: auto;';
70
+ svgWrapper.appendChild(svgClone);
71
+ exportContainer.appendChild(svgWrapper);
72
+ }
73
+ }
74
+ }
75
+ document.body.appendChild(exportContainer);
76
+ await new Promise(resolve => setTimeout(resolve, 300));
77
+ const containerHeight = exportContainer.scrollHeight;
78
+ const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
79
+ const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
80
+ const pageHeight = orientation === 'l' ? pageSize.width : pageSize.height;
81
+ const pageContentHeight = pageHeight - padding * 2;
82
+ const pdf = new jsPDF({
83
+ orientation: orientation,
84
+ unit: 'mm',
85
+ format: pageFormat
86
+ });
87
+ const canvas = await html2canvas(exportContainer, {
88
+ scale: scale,
89
+ useCORS: true,
90
+ logging: false,
91
+ width: containerWidth,
92
+ height: containerHeight,
93
+ windowHeight: containerHeight + 100,
94
+ scrollY: 0
95
+ });
96
+ const imgWidth = pageWidth - padding * 2;
97
+ const imgHeight = (canvas.height * imgWidth) / canvas.width;
98
+ const pageCount = Math.ceil(imgHeight / pageContentHeight);
99
+ for (let i = 0; i < pageCount; i++) {
100
+ if (i > 0) {
101
+ pdf.addPage();
102
+ }
103
+ const startY = Math.floor(i * pageContentHeight * canvas.height / imgHeight);
104
+ const endY = Math.min(startY + Math.floor(pageContentHeight * canvas.height / imgHeight), canvas.height);
105
+ const pageCanvasHeight = endY - startY;
106
+ const pageCanvas = document.createElement('canvas');
107
+ pageCanvas.width = canvas.width;
108
+ pageCanvas.height = pageCanvasHeight;
109
+ const ctx = pageCanvas.getContext('2d');
110
+ if (ctx) {
111
+ ctx.fillStyle = '#ffffff';
112
+ ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
113
+ ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
114
+ }
115
+ const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
116
+ const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
117
+ pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
118
+ }
119
+ pdf.save(fileName);
120
+ document.body.removeChild(exportContainer);
121
+ return { success: true, pageCount: pageCount };
122
+ }
123
+ catch (error) {
124
+ console.error('生成PDF失败:', error);
125
+ return { success: false, error: error instanceof Error ? error : new Error(String(error)) };
126
+ }
127
+ }
128
+ export default generationPDF;
129
+ //# sourceMappingURL=index.js.map
package/dist/index.js ADDED
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generationPDF = generationPDF;
7
+ exports.generationPDFWithOptions = generationPDFWithOptions;
8
+ const marked_1 = require("marked");
9
+ const html2canvas_1 = __importDefault(require("html2canvas"));
10
+ const jspdf_1 = require("jspdf");
11
+ const DEFAULT_STYLES = `
12
+ h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
13
+ h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
14
+ h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
15
+ h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
16
+ h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
17
+ h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
18
+ p { margin: 12px 0; color: #2c3e50; }
19
+ ul, ol { padding-left: 30px; margin: 12px 0; }
20
+ li { margin: 8px 0; }
21
+ code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
22
+ pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
23
+ pre code { background: none; padding: 0; color: inherit; }
24
+ blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
25
+ table { width: 100%; border-collapse: collapse; margin: 16px 0; }
26
+ th, td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
27
+ th { background: #f8f9fa; font-weight: bold; }
28
+ a { color: #667eea; text-decoration: none; }
29
+ hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
30
+ img { max-width: 100%; height: auto; }
31
+ `;
32
+ const PAGE_SIZES = {
33
+ a3: { width: 297, height: 420 },
34
+ a4: { width: 210, height: 297 },
35
+ letter: { width: 215.9, height: 279.4 },
36
+ legal: { width: 215.9, height: 355.6 }
37
+ };
38
+ async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
39
+ return generationPDFWithOptions({
40
+ markdownText,
41
+ mermaidDomId,
42
+ fileName
43
+ });
44
+ }
45
+ async function generationPDFWithOptions(options) {
46
+ const { markdownText, mermaidDomId, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
47
+ try {
48
+ const markdownHtml = (0, marked_1.parse)(markdownText);
49
+ const exportContainer = document.createElement('div');
50
+ exportContainer.id = 'pdf-export-container';
51
+ exportContainer.style.cssText = `
52
+ position: absolute;
53
+ left: -2000px;
54
+ top: -2000px;
55
+ width: ${containerWidth}px;
56
+ padding: ${containerPadding}px;
57
+ background: white;
58
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Microsoft YaHei, sans-serif;
59
+ font-size: 18px;
60
+ line-height: 1.8;
61
+ `;
62
+ exportContainer.innerHTML = `
63
+ <style>${DEFAULT_STYLES}</style>
64
+ <div style="max-width: ${containerWidth - containerPadding * 2}px; margin: 0 auto;">
65
+ ${markdownHtml}
66
+ </div>
67
+ `;
68
+ if (mermaidDomId) {
69
+ const mermaidEl = document.getElementById(mermaidDomId);
70
+ if (mermaidEl) {
71
+ const svg = mermaidEl.querySelector('svg');
72
+ if (svg) {
73
+ const svgWrapper = document.createElement('div');
74
+ svgWrapper.style.cssText = 'margin: 25px 0; text-align: center;';
75
+ const svgClone = svg.cloneNode(true);
76
+ svgClone.style.cssText = 'max-width: 1000px; width: 100%; height: auto;';
77
+ svgWrapper.appendChild(svgClone);
78
+ exportContainer.appendChild(svgWrapper);
79
+ }
80
+ }
81
+ }
82
+ document.body.appendChild(exportContainer);
83
+ await new Promise(resolve => setTimeout(resolve, 300));
84
+ const containerHeight = exportContainer.scrollHeight;
85
+ const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
86
+ const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
87
+ const pageHeight = orientation === 'l' ? pageSize.width : pageSize.height;
88
+ const pageContentHeight = pageHeight - padding * 2;
89
+ const pdf = new jspdf_1.jsPDF({
90
+ orientation: orientation,
91
+ unit: 'mm',
92
+ format: pageFormat
93
+ });
94
+ const canvas = await (0, html2canvas_1.default)(exportContainer, {
95
+ scale: scale,
96
+ useCORS: true,
97
+ logging: false,
98
+ width: containerWidth,
99
+ height: containerHeight,
100
+ windowHeight: containerHeight + 100,
101
+ scrollY: 0
102
+ });
103
+ const imgWidth = pageWidth - padding * 2;
104
+ const imgHeight = (canvas.height * imgWidth) / canvas.width;
105
+ const pageCount = Math.ceil(imgHeight / pageContentHeight);
106
+ for (let i = 0; i < pageCount; i++) {
107
+ if (i > 0) {
108
+ pdf.addPage();
109
+ }
110
+ const startY = Math.floor(i * pageContentHeight * canvas.height / imgHeight);
111
+ const endY = Math.min(startY + Math.floor(pageContentHeight * canvas.height / imgHeight), canvas.height);
112
+ const pageCanvasHeight = endY - startY;
113
+ const pageCanvas = document.createElement('canvas');
114
+ pageCanvas.width = canvas.width;
115
+ pageCanvas.height = pageCanvasHeight;
116
+ const ctx = pageCanvas.getContext('2d');
117
+ if (ctx) {
118
+ ctx.fillStyle = '#ffffff';
119
+ ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
120
+ ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
121
+ }
122
+ const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
123
+ const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
124
+ pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
125
+ }
126
+ pdf.save(fileName);
127
+ document.body.removeChild(exportContainer);
128
+ return { success: true, pageCount: pageCount };
129
+ }
130
+ catch (error) {
131
+ console.error('生成PDF失败:', error);
132
+ return { success: false, error: error instanceof Error ? error : new Error(String(error)) };
133
+ }
134
+ }
135
+ exports.default = generationPDF;
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.pdfComposer=f()}})(function(){
2
+ var marked = window.marked;
3
+ var html2canvas = window.html2canvas;
4
+ var jsPDF = window.jspdf.jsPDF;
5
+ const DEFAULT_STYLES = `
6
+ h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
7
+ h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
8
+ h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
9
+ h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
10
+ h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
11
+ h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
12
+ p { margin: 12px 0; color: #2c3e50; }
13
+ ul, ol { padding-left: 30px; margin: 12px 0; }
14
+ li { margin: 8px 0; }
15
+ code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
16
+ pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
17
+ pre code { background: none; padding: 0; color: inherit; }
18
+ blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
19
+ table { width: 100%; border-collapse: collapse; margin: 16px 0; }
20
+ th, td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
21
+ th { background: #f8f9fa; font-weight: bold; }
22
+ a { color: #667eea; text-decoration: none; }
23
+ hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
24
+ img { max-width: 100%; height: auto; }
25
+ `;
26
+ const PAGE_SIZES = {
27
+ a3: { width: 297, height: 420 },
28
+ a4: { width: 210, height: 297 },
29
+ letter: { width: 215.9, height: 279.4 },
30
+ legal: { width: 215.9, height: 355.6 }
31
+ };
32
+ async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
33
+ return generationPDFWithOptions({
34
+ markdownText,
35
+ mermaidDomId,
36
+ fileName
37
+ });
38
+ }
39
+ async function generationPDFWithOptions(options) {
40
+ const { markdownText, mermaidDomId, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
41
+ try {
42
+ const markdownHtml = marked.parse(markdownText);
43
+ const exportContainer = document.createElement('div');
44
+ exportContainer.id = 'pdf-export-container';
45
+ exportContainer.style.cssText = `
46
+ position: absolute;
47
+ left: -2000px;
48
+ top: -2000px;
49
+ width: ${containerWidth}px;
50
+ padding: ${containerPadding}px;
51
+ background: white;
52
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Microsoft YaHei, sans-serif;
53
+ font-size: 18px;
54
+ line-height: 1.8;
55
+ `;
56
+ exportContainer.innerHTML = `
57
+ <style>${DEFAULT_STYLES}</style>
58
+ <div style="max-width: ${containerWidth - containerPadding * 2}px; margin: 0 auto;">
59
+ ${markdownHtml}
60
+ </div>
61
+ `;
62
+ if (mermaidDomId) {
63
+ const mermaidEl = document.getElementById(mermaidDomId);
64
+ if (mermaidEl) {
65
+ const svg = mermaidEl.querySelector('svg');
66
+ if (svg) {
67
+ const svgWrapper = document.createElement('div');
68
+ svgWrapper.style.cssText = 'margin: 25px 0; text-align: center;';
69
+ const svgClone = svg.cloneNode(true);
70
+ svgClone.style.cssText = 'max-width: 1000px; width: 100%; height: auto;';
71
+ svgWrapper.appendChild(svgClone);
72
+ exportContainer.appendChild(svgWrapper);
73
+ }
74
+ }
75
+ }
76
+ document.body.appendChild(exportContainer);
77
+ await new Promise(resolve => setTimeout(resolve, 300));
78
+ const containerHeight = exportContainer.scrollHeight;
79
+ const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
80
+ const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
81
+ const pageHeight = orientation === 'l' ? pageSize.width : pageSize.height;
82
+ const pageContentHeight = pageHeight - padding * 2;
83
+ const pdf = new jsPDF({
84
+ orientation: orientation,
85
+ unit: 'mm',
86
+ format: pageFormat
87
+ });
88
+ const canvas = await html2canvas(exportContainer, {
89
+ scale: scale,
90
+ useCORS: true,
91
+ logging: false,
92
+ width: containerWidth,
93
+ height: containerHeight,
94
+ windowHeight: containerHeight + 100,
95
+ scrollY: 0
96
+ });
97
+ const imgWidth = pageWidth - padding * 2;
98
+ const imgHeight = (canvas.height * imgWidth) / canvas.width;
99
+ const pageCount = Math.ceil(imgHeight / pageContentHeight);
100
+ for (let i = 0; i < pageCount; i++) {
101
+ if (i > 0) {
102
+ pdf.addPage();
103
+ }
104
+ const startY = Math.floor(i * pageContentHeight * canvas.height / imgHeight);
105
+ const endY = Math.min(startY + Math.floor(pageContentHeight * canvas.height / imgHeight), canvas.height);
106
+ const pageCanvasHeight = endY - startY;
107
+ const pageCanvas = document.createElement('canvas');
108
+ pageCanvas.width = canvas.width;
109
+ pageCanvas.height = pageCanvasHeight;
110
+ const ctx = pageCanvas.getContext('2d');
111
+ if (ctx) {
112
+ ctx.fillStyle = '#ffffff';
113
+ ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
114
+ ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
115
+ }
116
+ const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
117
+ const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
118
+ pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
119
+ }
120
+ pdf.save(fileName);
121
+ document.body.removeChild(exportContainer);
122
+ return { success: true, pageCount: pageCount };
123
+ }
124
+ catch (error) {
125
+ console.error('生成PDF失败:', error);
126
+ return { success: false, error: error instanceof Error ? error : new Error(String(error)) };
127
+ }
128
+ }
129
+ return { generationPDF, generationPDFWithOptions };
130
+ });
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "pdf-composer",
3
+ "version": "1.0.0",
4
+ "description": "组合多种内容生成 PDF",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.esm.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.esm.js",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "node scripts/build.js",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "markdown",
24
+ "pdf",
25
+ "pdf-composer",
26
+ "html2canvas",
27
+ "jspdf",
28
+ "marked"
29
+ ],
30
+ "author": "xinghai.liu",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "marked": "^12.0.0",
34
+ "html2canvas": "^1.4.1",
35
+ "jspdf": "^2.5.1"
36
+ },
37
+ "devDependencies": {
38
+ "typescript": "^5.3.0"
39
+ },
40
+ "peerDependencies": {},
41
+ "engines": {
42
+ "node": ">=16.0.0"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": ""
47
+ },
48
+ "bugs": {
49
+ "url": ""
50
+ },
51
+ "homepage": ""
52
+ }