@microlee666/dom-to-pptx 1.1.4
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/.prettierrc +6 -0
- package/CHANGELOG.md +96 -0
- package/CONTRIBUTING.md +72 -0
- package/LICENSE +21 -0
- package/Readme.md +310 -0
- package/SUPPORTED.md +50 -0
- package/USAGE_CN.md +324 -0
- package/cli/.claude/settings.local.json +8 -0
- package/cli/.dockerignore +8 -0
- package/cli/Dockerfile +54 -0
- package/cli/Dockerfile.cn +22 -0
- package/cli/HTML_PPT_SPEC.md +360 -0
- package/cli/README.md +196 -0
- package/cli/docker-compose.yml +20 -0
- package/cli/dom-to-pptx.bundle.js +64731 -0
- package/cli/html2pptx.js +214 -0
- package/cli/output.pptx +1 -0
- package/cli/package-lock.json +1171 -0
- package/cli/package.json +20 -0
- package/cli/server.js +808 -0
- package/dist/dom-to-pptx.bundle.js +64917 -0
- package/dist/dom-to-pptx.cjs +2735 -0
- package/dist/dom-to-pptx.cjs.map +1 -0
- package/dist/dom-to-pptx.mjs +2705 -0
- package/dist/dom-to-pptx.mjs.map +1 -0
- package/eslint.config.js +17 -0
- package/package.json +86 -0
- package/rollup.config.js +96 -0
- package/src/font-embedder.js +163 -0
- package/src/font-utils.js +32 -0
- package/src/image-processor.js +118 -0
- package/src/index.js +1376 -0
- package/src/utils.js +1032 -0
package/USAGE_CN.md
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
# dom-to-pptx 使用指南
|
|
2
|
+
|
|
3
|
+
本文档总结了使用 `dom-to-pptx` 将 HTML 导出为 PowerPoint 的最佳实践和注意事项。
|
|
4
|
+
|
|
5
|
+
## 快速开始
|
|
6
|
+
|
|
7
|
+
### 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install dom-to-pptx
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### 基本用法
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { exportToPptx } from 'dom-to-pptx';
|
|
17
|
+
|
|
18
|
+
// 单个幻灯片
|
|
19
|
+
await exportToPptx('#slide-container', {
|
|
20
|
+
fileName: 'presentation.pptx',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// 多个幻灯片
|
|
24
|
+
const slides = document.querySelectorAll('.slide');
|
|
25
|
+
await exportToPptx(Array.from(slides), {
|
|
26
|
+
fileName: 'multi-slides.pptx',
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 浏览器直接使用(CDN)
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script src="https://cdn.jsdelivr.net/npm/dom-to-pptx@latest/dist/dom-to-pptx.bundle.js"></script>
|
|
34
|
+
<script>
|
|
35
|
+
await domToPptx.exportToPptx('#slide', { fileName: 'slide.pptx' });
|
|
36
|
+
</script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## HTML 编写规范
|
|
42
|
+
|
|
43
|
+
### 1. 幻灯片容器
|
|
44
|
+
|
|
45
|
+
推荐使用 **16:9** 比例的固定尺寸容器:
|
|
46
|
+
|
|
47
|
+
```html
|
|
48
|
+
<!-- 推荐尺寸 -->
|
|
49
|
+
<div class="slide" style="width: 1920px; height: 1080px;">
|
|
50
|
+
...
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<!-- 或者较小的等比尺寸 -->
|
|
54
|
+
<div class="slide" style="width: 960px; height: 540px;">
|
|
55
|
+
...
|
|
56
|
+
</div>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 2. 样式写法
|
|
60
|
+
|
|
61
|
+
**推荐使用内联样式**,这样可以确保导出时样式被正确读取:
|
|
62
|
+
|
|
63
|
+
```html
|
|
64
|
+
<!-- 推荐:内联样式 -->
|
|
65
|
+
<div style="background: linear-gradient(135deg, #667eea, #764ba2); padding: 60px;">
|
|
66
|
+
<h1 style="color: white; font-size: 48px;">标题</h1>
|
|
67
|
+
</div>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
如果使用 `<style>` 标签,确保样式在导出时能被正确应用:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<style>
|
|
74
|
+
.slide { ... }
|
|
75
|
+
.title { ... }
|
|
76
|
+
</style>
|
|
77
|
+
<div class="slide">
|
|
78
|
+
<h1 class="title">标题</h1>
|
|
79
|
+
</div>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 3. 定位方式
|
|
83
|
+
|
|
84
|
+
| 定位方式 | 支持程度 | 说明 |
|
|
85
|
+
|---------|---------|------|
|
|
86
|
+
| `position: relative` | ✅ 完全支持 | 推荐用于容器 |
|
|
87
|
+
| `position: absolute` | ✅ 完全支持 | 确保父级有 `position: relative` |
|
|
88
|
+
| `display: flex` | ✅ 支持 | 库会读取计算后的位置 |
|
|
89
|
+
| `display: grid` | ✅ 支持 | 库会读取计算后的位置 |
|
|
90
|
+
| `transform: translate()` | ⚠️ 部分支持 | 仅支持 `rotate`,不支持 `translate/scale` |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 支持的 CSS 属性
|
|
95
|
+
|
|
96
|
+
### 完全支持
|
|
97
|
+
|
|
98
|
+
| 属性 | 示例 |
|
|
99
|
+
|------|------|
|
|
100
|
+
| 背景颜色 | `background: #fff` / `background: rgba(0,0,0,0.5)` |
|
|
101
|
+
| 线性渐变 | `background: linear-gradient(135deg, #667eea, #764ba2)` |
|
|
102
|
+
| 圆角 | `border-radius: 16px` / `border-radius: 50%` |
|
|
103
|
+
| 边框 | `border: 1px solid #ccc` |
|
|
104
|
+
| 阴影 | `box-shadow: 0 4px 20px rgba(0,0,0,0.2)` |
|
|
105
|
+
| 字体样式 | `font-size`, `font-weight`, `font-family`, `color` |
|
|
106
|
+
| 文字变换 | `text-transform: uppercase` |
|
|
107
|
+
| 字间距 | `letter-spacing: 2px` |
|
|
108
|
+
| 内边距 | `padding: 20px` |
|
|
109
|
+
| 透明度 | `opacity: 0.8` |
|
|
110
|
+
| 模糊效果 | `filter: blur(10px)` |
|
|
111
|
+
|
|
112
|
+
### 不支持或有限支持
|
|
113
|
+
|
|
114
|
+
| 属性 | 状态 | 替代方案 |
|
|
115
|
+
|------|------|---------|
|
|
116
|
+
| `backdrop-filter` | ❌ 不支持 | 使用半透明背景色 |
|
|
117
|
+
| `transform: scale()` | ❌ 不支持 | 直接设置元素尺寸 |
|
|
118
|
+
| `animation` | ❌ 不支持 | 无 |
|
|
119
|
+
| `transition` | ❌ 不支持 | 无 |
|
|
120
|
+
| 径向渐变 | ⚠️ 有限支持 | 建议使用线性渐变 |
|
|
121
|
+
| `text-shadow` | ⚠️ 有限支持 | 可能不完全还原 |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 图片处理
|
|
126
|
+
|
|
127
|
+
### 1. 使用网络图片
|
|
128
|
+
|
|
129
|
+
图片必须使用**完整的 HTTPS URL**,且服务器需要支持 CORS:
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<!-- ✅ 正确 -->
|
|
133
|
+
<img src="https://images.unsplash.com/photo-xxx?w=400" />
|
|
134
|
+
|
|
135
|
+
<!-- ❌ 错误:相对路径 -->
|
|
136
|
+
<img src="./images/photo.jpg" />
|
|
137
|
+
|
|
138
|
+
<!-- ❌ 错误:本地文件 -->
|
|
139
|
+
<img src="file:///Users/xxx/photo.jpg" />
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2. 圆角图片
|
|
143
|
+
|
|
144
|
+
库会自动处理圆角图片,无需额外操作:
|
|
145
|
+
|
|
146
|
+
```html
|
|
147
|
+
<img
|
|
148
|
+
src="https://example.com/avatar.jpg"
|
|
149
|
+
style="width: 100px; height: 100px; border-radius: 50%;"
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 3. 背景图片
|
|
154
|
+
|
|
155
|
+
背景图片同样需要使用完整 URL:
|
|
156
|
+
|
|
157
|
+
```html
|
|
158
|
+
<!-- ✅ 正确 -->
|
|
159
|
+
<div style="background: url('https://example.com/bg.jpg') center/cover;"></div>
|
|
160
|
+
|
|
161
|
+
<!-- ❌ 错误 -->
|
|
162
|
+
<div style="background: url('./bg.jpg') center/cover;"></div>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 字体处理
|
|
168
|
+
|
|
169
|
+
### 自动字体嵌入
|
|
170
|
+
|
|
171
|
+
库默认会自动检测并嵌入使用的字体(`autoEmbedFonts: true`)。
|
|
172
|
+
|
|
173
|
+
### Google Fonts 使用
|
|
174
|
+
|
|
175
|
+
使用 Google Fonts 时,需要添加 `crossorigin` 属性:
|
|
176
|
+
|
|
177
|
+
```html
|
|
178
|
+
<!-- ✅ 正确 -->
|
|
179
|
+
<link
|
|
180
|
+
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
|
|
181
|
+
rel="stylesheet"
|
|
182
|
+
crossorigin="anonymous"
|
|
183
|
+
/>
|
|
184
|
+
|
|
185
|
+
<!-- ❌ 可能无法嵌入字体 -->
|
|
186
|
+
<link
|
|
187
|
+
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
|
|
188
|
+
rel="stylesheet"
|
|
189
|
+
/>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 手动指定字体
|
|
193
|
+
|
|
194
|
+
如果自动检测失败,可以手动指定:
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
await exportToPptx('#slide', {
|
|
198
|
+
fileName: 'slide.pptx',
|
|
199
|
+
fonts: [
|
|
200
|
+
{
|
|
201
|
+
name: 'Roboto',
|
|
202
|
+
url: 'https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Mu4mxK.woff2',
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 常见问题排查
|
|
211
|
+
|
|
212
|
+
### 1. 导出位置错乱
|
|
213
|
+
|
|
214
|
+
**原因**:导出时 DOM 元素受到 CSS `transform`、`flex` 布局或父容器影响。
|
|
215
|
+
|
|
216
|
+
**解决方案**:
|
|
217
|
+
- 确保导出的元素没有被 `transform: scale()` 影响
|
|
218
|
+
- 将要导出的 HTML 放到一个干净的容器中(无 flex/grid 影响)
|
|
219
|
+
- 参考 demo.html 中的 `#export-stage` 实现
|
|
220
|
+
|
|
221
|
+
### 2. 图片导出失败
|
|
222
|
+
|
|
223
|
+
**原因**:
|
|
224
|
+
- 图片 URL 无法访问
|
|
225
|
+
- 图片服务器不支持 CORS
|
|
226
|
+
- 使用了相对路径
|
|
227
|
+
|
|
228
|
+
**解决方案**:
|
|
229
|
+
- 使用支持 CORS 的图片服务(如 Unsplash、Cloudinary)
|
|
230
|
+
- 将图片转为 Base64 内联
|
|
231
|
+
|
|
232
|
+
### 3. 字体显示为 Arial
|
|
233
|
+
|
|
234
|
+
**原因**:字体无法嵌入,PowerPoint 回退到默认字体。
|
|
235
|
+
|
|
236
|
+
**解决方案**:
|
|
237
|
+
- 确保字体 URL 可访问
|
|
238
|
+
- 检查 CORS 设置
|
|
239
|
+
- 手动指定字体配置
|
|
240
|
+
|
|
241
|
+
### 4. 渐变显示不正确
|
|
242
|
+
|
|
243
|
+
**原因**:复杂的渐变语法可能无法完全解析。
|
|
244
|
+
|
|
245
|
+
**解决方案**:
|
|
246
|
+
- 使用标准的 `linear-gradient` 语法
|
|
247
|
+
- 避免使用 `radial-gradient` 或复杂的多色渐变
|
|
248
|
+
- 测试后调整颜色值
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Demo 使用说明
|
|
253
|
+
|
|
254
|
+
项目提供了一个本地 demo 页面 `demo.html`,可以直接在浏览器中打开测试。
|
|
255
|
+
|
|
256
|
+
### 功能
|
|
257
|
+
|
|
258
|
+
1. **HTML 编辑器**:左侧输入 HTML 代码(支持完整页面或片段)
|
|
259
|
+
2. **实时预览**:右侧自动渲染预览
|
|
260
|
+
3. **一键导出**:点击右上角按钮导出 PPTX
|
|
261
|
+
|
|
262
|
+
### 支持的 HTML 格式
|
|
263
|
+
|
|
264
|
+
**片段模式**(推荐):
|
|
265
|
+
|
|
266
|
+
```html
|
|
267
|
+
<div class="slide" style="width: 960px; height: 540px; ...">
|
|
268
|
+
<h1>标题</h1>
|
|
269
|
+
</div>
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**完整页面模式**:
|
|
273
|
+
|
|
274
|
+
```html
|
|
275
|
+
<!DOCTYPE html>
|
|
276
|
+
<html>
|
|
277
|
+
<head>
|
|
278
|
+
<style>
|
|
279
|
+
.slide { width: 960px; height: 540px; }
|
|
280
|
+
.title { font-size: 48px; }
|
|
281
|
+
</style>
|
|
282
|
+
</head>
|
|
283
|
+
<body>
|
|
284
|
+
<div class="slide">
|
|
285
|
+
<h1 class="title">标题</h1>
|
|
286
|
+
</div>
|
|
287
|
+
</body>
|
|
288
|
+
</html>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 最佳实践总结
|
|
294
|
+
|
|
295
|
+
1. **使用固定尺寸**:容器使用 `1920x1080` 或 `960x540`(16:9)
|
|
296
|
+
2. **优先内联样式**:确保样式能被正确读取
|
|
297
|
+
3. **图片用完整 URL**:避免相对路径,确保 CORS 可访问
|
|
298
|
+
4. **简化渐变**:使用标准 `linear-gradient` 语法
|
|
299
|
+
5. **测试字体**:使用 Google Fonts 时添加 `crossorigin` 属性
|
|
300
|
+
6. **避免 transform**:不要在要导出的元素上使用 `scale()` 或 `translate()`
|
|
301
|
+
7. **检查控制台**:导出失败时查看浏览器控制台的错误信息
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## API 参考
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
exportToPptx(elementOrSelector, options)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### 参数
|
|
312
|
+
|
|
313
|
+
| 参数 | 类型 | 说明 |
|
|
314
|
+
|------|------|------|
|
|
315
|
+
| `elementOrSelector` | `string \| HTMLElement \| Array` | DOM 元素或选择器 |
|
|
316
|
+
| `options.fileName` | `string` | 文件名,默认 `"export.pptx"` |
|
|
317
|
+
| `options.autoEmbedFonts` | `boolean` | 自动嵌入字体,默认 `true` |
|
|
318
|
+
| `options.fonts` | `Array<{name, url}>` | 手动指定字体 |
|
|
319
|
+
| `options.skipDownload` | `boolean` | 不自动下载,返回 Blob |
|
|
320
|
+
| `options.listConfig` | `object` | 列表样式配置 |
|
|
321
|
+
|
|
322
|
+
### 返回值
|
|
323
|
+
|
|
324
|
+
`Promise<Blob>` - 生成的 PPTX 文件 Blob 对象
|
package/cli/Dockerfile
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# dom-to-pptx 服务 Dockerfile
|
|
2
|
+
#
|
|
3
|
+
# 构建: docker build -t dom-to-pptx .
|
|
4
|
+
# 运行: docker run -p 3000:3000 dom-to-pptx
|
|
5
|
+
# 调优: docker run -p 3000:3000 -e POOL_MAX=10 dom-to-pptx
|
|
6
|
+
|
|
7
|
+
FROM node:20-slim
|
|
8
|
+
|
|
9
|
+
# 换用阿里云镜像源
|
|
10
|
+
RUN sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list.d/debian.sources
|
|
11
|
+
|
|
12
|
+
# 安装 Chromium 及中文字体
|
|
13
|
+
RUN apt-get update && apt-get install -y \
|
|
14
|
+
chromium \
|
|
15
|
+
fonts-wqy-zenhei \
|
|
16
|
+
fonts-noto-cjk \
|
|
17
|
+
fonts-freefont-ttf \
|
|
18
|
+
fonts-liberation \
|
|
19
|
+
--no-install-recommends \
|
|
20
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
21
|
+
|
|
22
|
+
# 创建非 root 用户(安全)
|
|
23
|
+
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
|
|
24
|
+
&& mkdir -p /home/pptruser /app \
|
|
25
|
+
&& chown -R pptruser:pptruser /home/pptruser /app
|
|
26
|
+
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
|
|
29
|
+
# Puppeteer 使用系统 Chromium
|
|
30
|
+
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
|
31
|
+
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
32
|
+
|
|
33
|
+
# 安装依赖
|
|
34
|
+
COPY package*.json ./
|
|
35
|
+
RUN npm install --omit=dev && npm cache clean --force
|
|
36
|
+
|
|
37
|
+
# 复制源码和内置的 dom-to-pptx bundle
|
|
38
|
+
COPY server.js html2pptx.js dom-to-pptx.bundle.js ./
|
|
39
|
+
|
|
40
|
+
# 切换用户
|
|
41
|
+
USER pptruser
|
|
42
|
+
|
|
43
|
+
# 运行配置
|
|
44
|
+
ENV NODE_ENV=production \
|
|
45
|
+
PORT=3000 \
|
|
46
|
+
POOL_MAX=5
|
|
47
|
+
|
|
48
|
+
EXPOSE 3000
|
|
49
|
+
|
|
50
|
+
# 健康检查
|
|
51
|
+
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
|
|
52
|
+
CMD node -e "fetch('http://localhost:3000/health').then(r=>r.ok?process.exit(0):process.exit(1)).catch(()=>process.exit(1))"
|
|
53
|
+
|
|
54
|
+
CMD ["node", "server.js"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
FROM node:18-slim
|
|
2
|
+
|
|
3
|
+
# 使用阿里云镜像源
|
|
4
|
+
RUN echo "deb http://mirrors.aliyun.com/debian/ bookworm main" > /etc/apt/sources.list && \
|
|
5
|
+
echo "deb http://mirrors.aliyun.com/debian/ bookworm-updates main" >> /etc/apt/sources.list
|
|
6
|
+
|
|
7
|
+
# 安装 Chromium
|
|
8
|
+
RUN apt-get update && apt-get install -y \
|
|
9
|
+
chromium \
|
|
10
|
+
fonts-freefont-ttf \
|
|
11
|
+
--no-install-recommends \
|
|
12
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
13
|
+
|
|
14
|
+
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
|
|
15
|
+
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
|
16
|
+
|
|
17
|
+
WORKDIR /app
|
|
18
|
+
COPY package.json html2pptx.js ./
|
|
19
|
+
RUN npm install --omit=dev
|
|
20
|
+
|
|
21
|
+
WORKDIR /data
|
|
22
|
+
ENTRYPOINT ["node", "/app/html2pptx.js"]
|