@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/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 对象
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm install:*)",
5
+ "Bash(npx playwright install:*)"
6
+ ]
7
+ }
8
+ }
@@ -0,0 +1,8 @@
1
+ node_modules
2
+ npm-debug.log
3
+ .git
4
+ .gitignore
5
+ *.md
6
+ .DS_Store
7
+ *.pptx
8
+ *.html
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"]