pdf-composer 1.0.0 → 1.0.2

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 CHANGED
@@ -1,203 +1,199 @@
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
1
+ # PDF Composer
2
+
3
+ 一个基于 JavaScript 的 PDF 生成工具,支持将 Markdown 文本、SVG 图表和多种类型的图片转换为 PDF 文档。
4
+
5
+ ## 功能特性
6
+
7
+ - Markdown 文本转 PDF
8
+ - SVG 图表支持(通过容器 ID 获取)
9
+ - 多种图片类型支持(远程图片、Base64、Canvas、Image)
10
+ - 多页 PDF 自动分页
11
+ - 自定义页面格式和方向
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ npm install pdf-composer
17
+ ```
18
+
19
+ ## 使用方法
20
+
21
+ ### 基础用法
22
+
23
+ ```typescript
24
+ import { generationPDFWithOptions } from 'pdf-composer';
25
+
26
+ const result = await generationPDFWithOptions({
27
+ markdownText: '# Hello World\n\n这是一个简单的 PDF 文档。',
28
+ fileName: 'output.pdf'
29
+ });
30
+
31
+ if (result.success) {
32
+ console.log(`PDF 生成成功,共 ${result.pageCount} 页`);
33
+ }
34
+ ```
35
+
36
+ ### SVG 图表支持
37
+
38
+ 通过容器 ID 获取页面中的 SVG 元素:
39
+
40
+ ```typescript
41
+ interface SvgOptions {
42
+ domId: string; // 页面中 SVG 所在容器的 ID
43
+ maxWidth?: number; // 最大宽度(默认 1000px)
44
+ margin?: number; // 外边距(默认 25px)
45
+ textAlign?: 'left' | 'center' | 'right'; // 对齐方式(默认 center)
46
+ }
47
+
48
+ // HTML 中定义 SVG 容器
49
+ // <div id="chart1">
50
+ // <svg>...</svg>
51
+ // </div>
52
+
53
+ const result = await generationPDFWithOptions({
54
+ markdownText: '# 报告\n\n以下是数据图表:',
55
+ fileName: 'report.pdf',
56
+ svgOptions: [
57
+ { domId: 'chart1', maxWidth: 800, margin: 30, textAlign: 'center' },
58
+ { domId: 'chart2', maxWidth: 600, margin: 20, textAlign: 'left' }
59
+ ]
60
+ });
61
+ ```
62
+
63
+ ### 图片支持(兼容多种类型)
64
+
65
+ 支持远程图片、Base64、Canvas 和 HTMLImageElement:
66
+
67
+ ```typescript
68
+ interface ImageOptions {
69
+ source: string | HTMLCanvasElement | HTMLImageElement;
70
+ width?: number;
71
+ height?: number;
72
+ margin?: number;
73
+ textAlign?: 'left' | 'center' | 'right';
74
+ }
75
+
76
+ // 远程图片
77
+ const remoteImage = {
78
+ source: 'https://example.com/image.jpg',
79
+ width: 600,
80
+ margin: 25,
81
+ textAlign: 'center'
82
+ };
83
+
84
+ // Base64 图片
85
+ const base64Image = {
86
+ source: 'data:image/png;base64,iVBORw0KGgo...',
87
+ width: 200
88
+ };
89
+
90
+ // Canvas 生成的图片
91
+ const canvas = document.createElement('canvas');
92
+ canvas.width = 400;
93
+ canvas.height = 200;
94
+ const ctx = canvas.getContext('2d');
95
+ ctx.fillStyle = '#667eea';
96
+ ctx.fillRect(0, 0, 400, 200);
97
+
98
+ const canvasImage = {
99
+ source: canvas,
100
+ margin: 25
101
+ };
102
+
103
+ const result = await generationPDFWithOptions({
104
+ markdownText: '# 图片报告\n\n包含多种类型的图片:',
105
+ fileName: 'images.pdf',
106
+ imageOptions: [remoteImage, base64Image, canvasImage]
107
+ });
108
+ ```
109
+
110
+ ## API 接口
111
+
112
+ ```typescript
113
+ interface GenerationPdfOptions {
114
+ markdownText: string; // 必需:Markdown 文本
115
+ fileName?: string; // 输出文件名(默认:output.pdf)
116
+ containerWidth?: number; // 渲染容器宽度(默认:1200px)
117
+ scale?: number; // 缩放比例(默认:2)
118
+ pageFormat?: 'a3' | 'a4' | 'letter' | 'legal'; // 页面格式(默认:a4)
119
+ orientation?: 'p' | 'l'; // 方向:纵向/横向(默认:p)
120
+ padding?: number; // 页面边距(默认:10mm)
121
+
122
+ svgOptions?: SvgOptions[]; // SVG 选项
123
+ imageOptions?: ImageOptions[]; // 图片选项
124
+ }
125
+ ```
126
+
127
+ ## 综合示例
128
+
129
+ ```typescript
130
+ import { generationPDFWithOptions } from 'pdf-composer';
131
+
132
+ // 创建 Canvas 图片
133
+ const canvas = document.createElement('canvas');
134
+ canvas.width = 400;
135
+ canvas.height = 200;
136
+ const ctx = canvas.getContext('2d');
137
+ ctx.fillStyle = '#4facfe';
138
+ ctx.fillRect(0, 0, 400, 200);
139
+ ctx.fillStyle = 'white';
140
+ ctx.font = '24px Arial';
141
+ ctx.textAlign = 'center';
142
+ ctx.fillText('动态生成的图表', 200, 110);
143
+
144
+ // 生成综合 PDF
145
+ const result = await generationPDFWithOptions({
146
+ markdownText: `# 综合报告
147
+
148
+ 这是一个包含多种内容类型的综合报告。
149
+
150
+ ## 数据图表
151
+
152
+ 下面是从页面获取的 SVG 图表:
153
+
154
+ ## 动态内容
155
+
156
+ 以及通过代码生成的图片:`,
157
+ fileName: 'comprehensive-report.pdf',
158
+ pageFormat: 'a4',
159
+ orientation: 'p',
160
+ svgOptions: [
161
+ { domId: 'sales-chart', maxWidth: 800, margin: 30, textAlign: 'center' },
162
+ { domId: 'pie-chart', maxWidth: 600, margin: 30, textAlign: 'center' }
163
+ ],
164
+ imageOptions: [
165
+ { source: 'https://example.com/logo.png', width: 300, margin: 20 },
166
+ { source: canvas, margin: 25 },
167
+ { source: 'data:image/png;base64,iVBORw0KGgo...', width: 200 }
168
+ ]
169
+ });
170
+ ```
171
+
172
+ ## 测试页面
173
+
174
+ 项目提供了完整的测试页面:
175
+
176
+ - [demo.html](example/demo.html) - 包含基础测试、SVG 测试、图片测试和综合测试
177
+
178
+ ## 依赖
179
+
180
+ - **marked**:Markdown 解析
181
+ - **html2canvas**:HTML 转 Canvas
182
+ - **jsPDF**:PDF 生成
183
+
184
+ ## 开发
185
+
186
+ ```bash
187
+ # 安装依赖
188
+ npm install
189
+
190
+ # 构建
191
+ npm run build
192
+
193
+ # 启动开发服务器
194
+ npx http-server -p 8081
195
+ ```
196
+
197
+ ## 许可证
198
+
199
+ MIT
package/dist/index.d.ts CHANGED
@@ -1,6 +1,21 @@
1
+ export interface SvgOptions {
2
+ domId: string;
3
+ maxWidth?: number;
4
+ margin?: number;
5
+ textAlign?: 'left' | 'center' | 'right';
6
+ }
7
+ export interface ImageOptions {
8
+ source: string | HTMLCanvasElement | HTMLImageElement;
9
+ width?: number;
10
+ height?: number;
11
+ margin?: number;
12
+ textAlign?: 'left' | 'center' | 'right';
13
+ }
1
14
  export interface GenerationPdfOptions {
2
15
  markdownText: string;
3
16
  mermaidDomId?: string;
17
+ svgOptions?: SvgOptions[];
18
+ imageOptions?: ImageOptions[];
4
19
  fileName?: string;
5
20
  containerWidth?: number;
6
21
  containerPadding?: number;
package/dist/index.esm.js CHANGED
@@ -2,25 +2,25 @@ import { parse } from 'marked';
2
2
  import html2canvas from 'html2canvas';
3
3
  import { jsPDF } from 'jspdf';
4
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; }
5
+ #pdf-export-container h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
6
+ #pdf-export-container h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
7
+ #pdf-export-container h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
8
+ #pdf-export-container h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
9
+ #pdf-export-container h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
10
+ #pdf-export-container h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
11
+ #pdf-export-container p { margin: 12px 0; color: #2c3e50; }
12
+ #pdf-export-container ul, #pdf-export-container ol { padding-left: 30px; margin: 12px 0; }
13
+ #pdf-export-container li { margin: 8px 0; }
14
+ #pdf-export-container code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
15
+ #pdf-export-container pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
16
+ #pdf-export-container pre code { background: none; padding: 0; color: inherit; }
17
+ #pdf-export-container blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
18
+ #pdf-export-container table { width: 100%; border-collapse: collapse; margin: 16px 0; }
19
+ #pdf-export-container th, #pdf-export-container td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
20
+ #pdf-export-container th { background: #f8f9fa; font-weight: bold; }
21
+ #pdf-export-container a { color: #667eea; text-decoration: none; }
22
+ #pdf-export-container hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
23
+ #pdf-export-container img { max-width: 100%; height: auto; }
24
24
  `;
25
25
  const PAGE_SIZES = {
26
26
  a3: { width: 297, height: 420 },
@@ -28,6 +28,68 @@ const PAGE_SIZES = {
28
28
  letter: { width: 215.9, height: 279.4 },
29
29
  legal: { width: 215.9, height: 355.6 }
30
30
  };
31
+ function processSvgOptions(svgOptions, container) {
32
+ for (const option of svgOptions) {
33
+ const el = document.getElementById(option.domId);
34
+ if (!el)
35
+ continue;
36
+ const svg = el.querySelector('svg');
37
+ if (!svg)
38
+ continue;
39
+ const wrapper = document.createElement('div');
40
+ const margin = option.margin ?? 25;
41
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
42
+ const clone = svg.cloneNode(true);
43
+ clone.style.cssText = `max-width: ${option.maxWidth ?? 1000}px; width: 100%; height: auto;`;
44
+ wrapper.appendChild(clone);
45
+ container.appendChild(wrapper);
46
+ }
47
+ }
48
+ async function processImageOptions(imageOptions, container) {
49
+ for (const option of imageOptions) {
50
+ const wrapper = document.createElement('div');
51
+ const margin = option.margin ?? 25;
52
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
53
+ let imgEl = null;
54
+ if (typeof option.source === 'string') {
55
+ imgEl = document.createElement('img');
56
+ imgEl.src = option.source;
57
+ imgEl.style.maxWidth = '100%';
58
+ imgEl.style.height = 'auto';
59
+ if (option.width)
60
+ imgEl.style.width = `${option.width}px`;
61
+ if (option.height)
62
+ imgEl.style.height = `${option.height}px`;
63
+ await new Promise((resolve) => {
64
+ imgEl.onload = resolve;
65
+ imgEl.onerror = resolve;
66
+ });
67
+ }
68
+ else if (option.source instanceof HTMLCanvasElement) {
69
+ imgEl = document.createElement('img');
70
+ imgEl.src = option.source.toDataURL('image/png');
71
+ imgEl.style.maxWidth = '100%';
72
+ imgEl.style.height = 'auto';
73
+ if (option.width)
74
+ imgEl.style.width = `${option.width}px`;
75
+ if (option.height)
76
+ imgEl.style.height = `${option.height}px`;
77
+ }
78
+ else if (option.source instanceof HTMLImageElement) {
79
+ imgEl = option.source.cloneNode(true);
80
+ imgEl.style.maxWidth = '100%';
81
+ imgEl.style.height = 'auto';
82
+ if (option.width)
83
+ imgEl.style.width = `${option.width}px`;
84
+ if (option.height)
85
+ imgEl.style.height = `${option.height}px`;
86
+ }
87
+ if (imgEl) {
88
+ wrapper.appendChild(imgEl);
89
+ container.appendChild(wrapper);
90
+ }
91
+ }
92
+ }
31
93
  export async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
32
94
  return generationPDFWithOptions({
33
95
  markdownText,
@@ -36,7 +98,7 @@ export async function generationPDF(markdownText, mermaidDomId, fileName = 'outp
36
98
  });
37
99
  }
38
100
  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;
101
+ const { markdownText, mermaidDomId, svgOptions, imageOptions, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
40
102
  try {
41
103
  const markdownHtml = parse(markdownText);
42
104
  const exportContainer = document.createElement('div');
@@ -72,8 +134,14 @@ export async function generationPDFWithOptions(options) {
72
134
  }
73
135
  }
74
136
  }
137
+ if (svgOptions && svgOptions.length > 0) {
138
+ processSvgOptions(svgOptions, exportContainer);
139
+ }
140
+ if (imageOptions && imageOptions.length > 0) {
141
+ await processImageOptions(imageOptions, exportContainer);
142
+ }
75
143
  document.body.appendChild(exportContainer);
76
- await new Promise(resolve => setTimeout(resolve, 300));
144
+ await new Promise(resolve => setTimeout(resolve, 500));
77
145
  const containerHeight = exportContainer.scrollHeight;
78
146
  const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
79
147
  const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
@@ -112,9 +180,9 @@ export async function generationPDFWithOptions(options) {
112
180
  ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
113
181
  ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
114
182
  }
115
- const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
183
+ const pageImgData = pageCanvas.toDataURL('image/png');
116
184
  const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
117
- pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
185
+ pdf.addImage(pageImgData, 'PNG', padding, padding, imgWidth, pageImgHeight);
118
186
  }
119
187
  pdf.save(fileName);
120
188
  document.body.removeChild(exportContainer);
package/dist/index.js CHANGED
@@ -9,25 +9,25 @@ const marked_1 = require("marked");
9
9
  const html2canvas_1 = __importDefault(require("html2canvas"));
10
10
  const jspdf_1 = require("jspdf");
11
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; }
12
+ #pdf-export-container h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
13
+ #pdf-export-container h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
14
+ #pdf-export-container h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
15
+ #pdf-export-container h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
16
+ #pdf-export-container h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
17
+ #pdf-export-container h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
18
+ #pdf-export-container p { margin: 12px 0; color: #2c3e50; }
19
+ #pdf-export-container ul, #pdf-export-container ol { padding-left: 30px; margin: 12px 0; }
20
+ #pdf-export-container li { margin: 8px 0; }
21
+ #pdf-export-container code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
22
+ #pdf-export-container pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
23
+ #pdf-export-container pre code { background: none; padding: 0; color: inherit; }
24
+ #pdf-export-container blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
25
+ #pdf-export-container table { width: 100%; border-collapse: collapse; margin: 16px 0; }
26
+ #pdf-export-container th, #pdf-export-container td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
27
+ #pdf-export-container th { background: #f8f9fa; font-weight: bold; }
28
+ #pdf-export-container a { color: #667eea; text-decoration: none; }
29
+ #pdf-export-container hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
30
+ #pdf-export-container img { max-width: 100%; height: auto; }
31
31
  `;
32
32
  const PAGE_SIZES = {
33
33
  a3: { width: 297, height: 420 },
@@ -35,6 +35,68 @@ const PAGE_SIZES = {
35
35
  letter: { width: 215.9, height: 279.4 },
36
36
  legal: { width: 215.9, height: 355.6 }
37
37
  };
38
+ function processSvgOptions(svgOptions, container) {
39
+ for (const option of svgOptions) {
40
+ const el = document.getElementById(option.domId);
41
+ if (!el)
42
+ continue;
43
+ const svg = el.querySelector('svg');
44
+ if (!svg)
45
+ continue;
46
+ const wrapper = document.createElement('div');
47
+ const margin = option.margin ?? 25;
48
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
49
+ const clone = svg.cloneNode(true);
50
+ clone.style.cssText = `max-width: ${option.maxWidth ?? 1000}px; width: 100%; height: auto;`;
51
+ wrapper.appendChild(clone);
52
+ container.appendChild(wrapper);
53
+ }
54
+ }
55
+ async function processImageOptions(imageOptions, container) {
56
+ for (const option of imageOptions) {
57
+ const wrapper = document.createElement('div');
58
+ const margin = option.margin ?? 25;
59
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
60
+ let imgEl = null;
61
+ if (typeof option.source === 'string') {
62
+ imgEl = document.createElement('img');
63
+ imgEl.src = option.source;
64
+ imgEl.style.maxWidth = '100%';
65
+ imgEl.style.height = 'auto';
66
+ if (option.width)
67
+ imgEl.style.width = `${option.width}px`;
68
+ if (option.height)
69
+ imgEl.style.height = `${option.height}px`;
70
+ await new Promise((resolve) => {
71
+ imgEl.onload = resolve;
72
+ imgEl.onerror = resolve;
73
+ });
74
+ }
75
+ else if (option.source instanceof HTMLCanvasElement) {
76
+ imgEl = document.createElement('img');
77
+ imgEl.src = option.source.toDataURL('image/png');
78
+ imgEl.style.maxWidth = '100%';
79
+ imgEl.style.height = 'auto';
80
+ if (option.width)
81
+ imgEl.style.width = `${option.width}px`;
82
+ if (option.height)
83
+ imgEl.style.height = `${option.height}px`;
84
+ }
85
+ else if (option.source instanceof HTMLImageElement) {
86
+ imgEl = option.source.cloneNode(true);
87
+ imgEl.style.maxWidth = '100%';
88
+ imgEl.style.height = 'auto';
89
+ if (option.width)
90
+ imgEl.style.width = `${option.width}px`;
91
+ if (option.height)
92
+ imgEl.style.height = `${option.height}px`;
93
+ }
94
+ if (imgEl) {
95
+ wrapper.appendChild(imgEl);
96
+ container.appendChild(wrapper);
97
+ }
98
+ }
99
+ }
38
100
  async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
39
101
  return generationPDFWithOptions({
40
102
  markdownText,
@@ -43,7 +105,7 @@ async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf'
43
105
  });
44
106
  }
45
107
  async function generationPDFWithOptions(options) {
46
- const { markdownText, mermaidDomId, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
108
+ const { markdownText, mermaidDomId, svgOptions, imageOptions, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
47
109
  try {
48
110
  const markdownHtml = (0, marked_1.parse)(markdownText);
49
111
  const exportContainer = document.createElement('div');
@@ -79,8 +141,14 @@ async function generationPDFWithOptions(options) {
79
141
  }
80
142
  }
81
143
  }
144
+ if (svgOptions && svgOptions.length > 0) {
145
+ processSvgOptions(svgOptions, exportContainer);
146
+ }
147
+ if (imageOptions && imageOptions.length > 0) {
148
+ await processImageOptions(imageOptions, exportContainer);
149
+ }
82
150
  document.body.appendChild(exportContainer);
83
- await new Promise(resolve => setTimeout(resolve, 300));
151
+ await new Promise(resolve => setTimeout(resolve, 500));
84
152
  const containerHeight = exportContainer.scrollHeight;
85
153
  const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
86
154
  const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
@@ -119,9 +187,9 @@ async function generationPDFWithOptions(options) {
119
187
  ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
120
188
  ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
121
189
  }
122
- const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
190
+ const pageImgData = pageCanvas.toDataURL('image/png');
123
191
  const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
124
- pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
192
+ pdf.addImage(pageImgData, 'PNG', padding, padding, imgWidth, pageImgHeight);
125
193
  }
126
194
  pdf.save(fileName);
127
195
  document.body.removeChild(exportContainer);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -3,25 +3,25 @@ var marked = window.marked;
3
3
  var html2canvas = window.html2canvas;
4
4
  var jsPDF = window.jspdf.jsPDF;
5
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; }
6
+ #pdf-export-container h1 { font-size: 36px; margin-bottom: 20px; font-weight: bold; color: #2c3e50; }
7
+ #pdf-export-container h2 { font-size: 28px; margin: 25px 0 12px; font-weight: bold; color: #34495e; }
8
+ #pdf-export-container h3 { font-size: 22px; margin: 20px 0 10px; font-weight: bold; color: #34495e; }
9
+ #pdf-export-container h4 { font-size: 18px; margin: 18px 0 8px; font-weight: bold; color: #34495e; }
10
+ #pdf-export-container h5 { font-size: 16px; margin: 16px 0 6px; font-weight: bold; color: #34495e; }
11
+ #pdf-export-container h6 { font-size: 14px; margin: 14px 0 4px; font-weight: bold; color: #34495e; }
12
+ #pdf-export-container p { margin: 12px 0; color: #2c3e50; }
13
+ #pdf-export-container ul, #pdf-export-container ol { padding-left: 30px; margin: 12px 0; }
14
+ #pdf-export-container li { margin: 8px 0; }
15
+ #pdf-export-container code { background: #f4f4f4; padding: 3px 8px; border-radius: 4px; font-family: monospace; font-size: 14px; }
16
+ #pdf-export-container pre { background: #2d2d2d; color: #ccc; padding: 16px; border-radius: 8px; overflow-x: auto; font-size: 14px; }
17
+ #pdf-export-container pre code { background: none; padding: 0; color: inherit; }
18
+ #pdf-export-container blockquote { border-left: 4px solid #667eea; padding-left: 16px; margin: 16px 0; color: #7f8c8d; font-style: italic; }
19
+ #pdf-export-container table { width: 100%; border-collapse: collapse; margin: 16px 0; }
20
+ #pdf-export-container th, #pdf-export-container td { border: 1px solid #ddd; padding: 10px 14px; text-align: left; }
21
+ #pdf-export-container th { background: #f8f9fa; font-weight: bold; }
22
+ #pdf-export-container a { color: #667eea; text-decoration: none; }
23
+ #pdf-export-container hr { border: none; border-top: 1px solid #eee; margin: 20px 0; }
24
+ #pdf-export-container img { max-width: 100%; height: auto; }
25
25
  `;
26
26
  const PAGE_SIZES = {
27
27
  a3: { width: 297, height: 420 },
@@ -29,6 +29,68 @@ const PAGE_SIZES = {
29
29
  letter: { width: 215.9, height: 279.4 },
30
30
  legal: { width: 215.9, height: 355.6 }
31
31
  };
32
+ function processSvgOptions(svgOptions, container) {
33
+ for (const option of svgOptions) {
34
+ const el = document.getElementById(option.domId);
35
+ if (!el)
36
+ continue;
37
+ const svg = el.querySelector('svg');
38
+ if (!svg)
39
+ continue;
40
+ const wrapper = document.createElement('div');
41
+ const margin = option.margin ?? 25;
42
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
43
+ const clone = svg.cloneNode(true);
44
+ clone.style.cssText = `max-width: ${option.maxWidth ?? 1000}px; width: 100%; height: auto;`;
45
+ wrapper.appendChild(clone);
46
+ container.appendChild(wrapper);
47
+ }
48
+ }
49
+ async function processImageOptions(imageOptions, container) {
50
+ for (const option of imageOptions) {
51
+ const wrapper = document.createElement('div');
52
+ const margin = option.margin ?? 25;
53
+ wrapper.style.cssText = `margin: ${margin}px 0; text-align: ${option.textAlign ?? 'center'};`;
54
+ let imgEl = null;
55
+ if (typeof option.source === 'string') {
56
+ imgEl = document.createElement('img');
57
+ imgEl.src = option.source;
58
+ imgEl.style.maxWidth = '100%';
59
+ imgEl.style.height = 'auto';
60
+ if (option.width)
61
+ imgEl.style.width = `${option.width}px`;
62
+ if (option.height)
63
+ imgEl.style.height = `${option.height}px`;
64
+ await new Promise((resolve) => {
65
+ imgEl.onload = resolve;
66
+ imgEl.onerror = resolve;
67
+ });
68
+ }
69
+ else if (option.source instanceof HTMLCanvasElement) {
70
+ imgEl = document.createElement('img');
71
+ imgEl.src = option.source.toDataURL('image/png');
72
+ imgEl.style.maxWidth = '100%';
73
+ imgEl.style.height = 'auto';
74
+ if (option.width)
75
+ imgEl.style.width = `${option.width}px`;
76
+ if (option.height)
77
+ imgEl.style.height = `${option.height}px`;
78
+ }
79
+ else if (option.source instanceof HTMLImageElement) {
80
+ imgEl = option.source.cloneNode(true);
81
+ imgEl.style.maxWidth = '100%';
82
+ imgEl.style.height = 'auto';
83
+ if (option.width)
84
+ imgEl.style.width = `${option.width}px`;
85
+ if (option.height)
86
+ imgEl.style.height = `${option.height}px`;
87
+ }
88
+ if (imgEl) {
89
+ wrapper.appendChild(imgEl);
90
+ container.appendChild(wrapper);
91
+ }
92
+ }
93
+ }
32
94
  async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf') {
33
95
  return generationPDFWithOptions({
34
96
  markdownText,
@@ -37,7 +99,7 @@ async function generationPDF(markdownText, mermaidDomId, fileName = 'output.pdf'
37
99
  });
38
100
  }
39
101
  async function generationPDFWithOptions(options) {
40
- const { markdownText, mermaidDomId, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
102
+ const { markdownText, mermaidDomId, svgOptions, imageOptions, fileName = 'output.pdf', containerWidth = 1200, containerPadding = 40, scale = 2, pageFormat = 'a4', orientation = 'p', padding = 10 } = options;
41
103
  try {
42
104
  const markdownHtml = marked.parse(markdownText);
43
105
  const exportContainer = document.createElement('div');
@@ -73,8 +135,14 @@ async function generationPDFWithOptions(options) {
73
135
  }
74
136
  }
75
137
  }
138
+ if (svgOptions && svgOptions.length > 0) {
139
+ processSvgOptions(svgOptions, exportContainer);
140
+ }
141
+ if (imageOptions && imageOptions.length > 0) {
142
+ await processImageOptions(imageOptions, exportContainer);
143
+ }
76
144
  document.body.appendChild(exportContainer);
77
- await new Promise(resolve => setTimeout(resolve, 300));
145
+ await new Promise(resolve => setTimeout(resolve, 500));
78
146
  const containerHeight = exportContainer.scrollHeight;
79
147
  const pageSize = PAGE_SIZES[pageFormat] || PAGE_SIZES.a4;
80
148
  const pageWidth = orientation === 'l' ? pageSize.height : pageSize.width;
@@ -113,9 +181,9 @@ async function generationPDFWithOptions(options) {
113
181
  ctx.fillRect(0, 0, pageCanvas.width, pageCanvas.height);
114
182
  ctx.drawImage(canvas, 0, startY, canvas.width, pageCanvasHeight, 0, 0, pageCanvas.width, pageCanvasHeight);
115
183
  }
116
- const pageImgData = pageCanvas.toDataURL('image/jpeg', 0.95);
184
+ const pageImgData = pageCanvas.toDataURL('image/png');
117
185
  const pageImgHeight = (pageCanvasHeight / canvas.height) * imgHeight;
118
- pdf.addImage(pageImgData, 'JPEG', padding, padding, imgWidth, pageImgHeight);
186
+ pdf.addImage(pageImgData, 'PNG', padding, padding, imgWidth, pageImgHeight);
119
187
  }
120
188
  pdf.save(fileName);
121
189
  document.body.removeChild(exportContainer);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-composer",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "组合多种内容生成 PDF",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.esm.js",