node-pdf2img 0.1.7 → 0.1.9
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 +95 -9
- package/bin/cli.js +36 -20
- package/package.json +8 -3
- package/src/core/config.js +9 -0
- package/src/core/converter.js +78 -372
- package/src/core/downloader.js +98 -0
- package/src/core/output-handler.js +179 -0
- package/src/core/renderer.js +289 -0
- package/src/core/thread-pool.js +78 -0
- package/src/index.d.ts +182 -49
- package/src/index.js +18 -4
- package/src/renderers/pdfjs.js +867 -0
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# node-pdf2img
|
|
2
2
|
|
|
3
|
-
高性能 PDF
|
|
3
|
+
高性能 PDF 转图片工具,支持 PDFium 原生渲染器和 PDF.js 渲染器。
|
|
4
4
|
|
|
5
5
|
[](https://badge.fury.io/js/node-pdf2img)
|
|
6
6
|
|
|
7
7
|
## 特性
|
|
8
8
|
|
|
9
|
-
-
|
|
9
|
+
- **双渲染引擎**:PDFium 原生渲染(高性能)+ PDF.js(纯 JavaScript,无需原生依赖)
|
|
10
|
+
- **高性能**:PDFium 多线程并行处理,整体快 1.7x
|
|
11
|
+
- **流式渲染**:URL 输入支持 HTTP Range 请求,大文件无需完整下载
|
|
10
12
|
- **多种格式**:支持 WebP、PNG、JPG 输出
|
|
11
13
|
- **多种输入**:支持本地文件、URL、Buffer
|
|
12
14
|
- **多种输出**:支持本地文件、Buffer、腾讯云 COS
|
|
13
15
|
- **CLI + API**:命令行工具和 Node.js 模块双模式
|
|
16
|
+
- **广泛兼容**:支持 GLIBC 2.17+ (CentOS 7/RHEL 7+)
|
|
14
17
|
|
|
15
18
|
## 安装
|
|
16
19
|
|
|
@@ -25,14 +28,20 @@ npm install -g node-pdf2img
|
|
|
25
28
|
## 系统要求
|
|
26
29
|
|
|
27
30
|
- Node.js >= 18.0.0
|
|
28
|
-
- 支持平台:
|
|
31
|
+
- 支持平台:
|
|
32
|
+
- Linux x64/arm64 (GLIBC 2.17+,兼容 CentOS 7/RHEL 7+)
|
|
33
|
+
- macOS x64/arm64
|
|
34
|
+
- Windows x64
|
|
29
35
|
|
|
30
36
|
## CLI 使用
|
|
31
37
|
|
|
32
38
|
```bash
|
|
33
|
-
# 基本用法 -
|
|
39
|
+
# 基本用法 - 转换所有页面(默认使用 PDFium)
|
|
34
40
|
pdf2img document.pdf -o ./output
|
|
35
41
|
|
|
42
|
+
# 使用 PDF.js 渲染器
|
|
43
|
+
pdf2img document.pdf -o ./output -r pdfjs
|
|
44
|
+
|
|
36
45
|
# 转换指定页面
|
|
37
46
|
pdf2img document.pdf -p 1,2,3 -o ./output
|
|
38
47
|
|
|
@@ -51,6 +60,9 @@ pdf2img document.pdf -f jpg -q 85 -o ./output
|
|
|
51
60
|
# 显示 PDF 信息
|
|
52
61
|
pdf2img document.pdf --info
|
|
53
62
|
|
|
63
|
+
# 显示渲染器版本信息
|
|
64
|
+
pdf2img --version-info
|
|
65
|
+
|
|
54
66
|
# 上传到腾讯云 COS
|
|
55
67
|
pdf2img document.pdf --cos --cos-prefix images/doc-123
|
|
56
68
|
```
|
|
@@ -64,8 +76,10 @@ pdf2img document.pdf --cos --cos-prefix images/doc-123
|
|
|
64
76
|
| `-w, --width <width>` | 渲染宽度(像素) | `1920` |
|
|
65
77
|
| `-q, --quality <quality>` | 图片质量(0-100) | `100` |
|
|
66
78
|
| `-f, --format <format>` | 输出格式:webp, png, jpg | `webp` |
|
|
79
|
+
| `-r, --renderer <renderer>` | 渲染器:pdfium, pdfjs | `pdfium` |
|
|
67
80
|
| `--prefix <prefix>` | 文件名前缀 | `page` |
|
|
68
81
|
| `--info` | 仅显示 PDF 信息 | |
|
|
82
|
+
| `--version-info` | 显示渲染器版本信息 | |
|
|
69
83
|
| `-v, --verbose` | 详细输出 | |
|
|
70
84
|
| `--cos` | 上传到腾讯云 COS | |
|
|
71
85
|
| `--cos-prefix <prefix>` | COS key 前缀 | |
|
|
@@ -88,7 +102,7 @@ pdf2img document.pdf --cos --cos-prefix images/doc-123
|
|
|
88
102
|
### 基本用法
|
|
89
103
|
|
|
90
104
|
```javascript
|
|
91
|
-
import { convert, getPageCount, isAvailable } from 'node-pdf2img';
|
|
105
|
+
import { convert, getPageCount, isAvailable, RendererType } from 'node-pdf2img';
|
|
92
106
|
|
|
93
107
|
// 检查渲染器是否可用
|
|
94
108
|
if (!isAvailable()) {
|
|
@@ -96,7 +110,7 @@ if (!isAvailable()) {
|
|
|
96
110
|
process.exit(1);
|
|
97
111
|
}
|
|
98
112
|
|
|
99
|
-
// 转换 PDF 为图片(返回 Buffer)
|
|
113
|
+
// 转换 PDF 为图片(返回 Buffer,默认使用 PDFium)
|
|
100
114
|
const result = await convert('./document.pdf');
|
|
101
115
|
console.log(`转换了 ${result.renderedPages} 页`);
|
|
102
116
|
|
|
@@ -106,6 +120,24 @@ for (const page of result.pages) {
|
|
|
106
120
|
}
|
|
107
121
|
```
|
|
108
122
|
|
|
123
|
+
### 使用 PDF.js 渲染器
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
import { convert, RendererType, isPdfjsAvailable } from 'node-pdf2img';
|
|
127
|
+
|
|
128
|
+
// 检查 PDF.js 渲染器是否可用
|
|
129
|
+
if (isPdfjsAvailable()) {
|
|
130
|
+
const result = await convert('./document.pdf', {
|
|
131
|
+
renderer: RendererType.PDFJS, // 或直接使用 'pdfjs'
|
|
132
|
+
});
|
|
133
|
+
console.log(`使用 PDF.js 转换了 ${result.renderedPages} 页`);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> **渲染器选择建议**:
|
|
138
|
+
> - **PDFium**(默认):高性能,适合大多数场景,整体快 1.7x
|
|
139
|
+
> - **PDF.js**:纯 JavaScript,无需原生依赖,适合超大文件(>50MB)或无法使用原生模块的环境
|
|
140
|
+
|
|
109
141
|
### 保存到文件
|
|
110
142
|
|
|
111
143
|
```javascript
|
|
@@ -200,8 +232,15 @@ const result = await convert('https://example.com/document.pdf', {
|
|
|
200
232
|
outputType: 'file',
|
|
201
233
|
outputDir: './output',
|
|
202
234
|
});
|
|
235
|
+
|
|
236
|
+
// 查看流式渲染统计(仅 URL 输入时存在)
|
|
237
|
+
if (result.streamStats) {
|
|
238
|
+
console.log(`流式渲染: 缓存命中 ${result.streamStats.cacheHits} 次`);
|
|
239
|
+
}
|
|
203
240
|
```
|
|
204
241
|
|
|
242
|
+
> **流式渲染**:对于大于 2MB 的远程 PDF,会自动使用 HTTP Range 请求按需获取数据,避免完整下载。小于 2MB 的文件会直接下载后渲染,减少 Range 请求开销。
|
|
243
|
+
|
|
205
244
|
### 上传到腾讯云 COS
|
|
206
245
|
|
|
207
246
|
```javascript
|
|
@@ -256,6 +295,7 @@ PDF 转图片。
|
|
|
256
295
|
- `prefix` (string):文件名前缀,默认 'page'
|
|
257
296
|
- `format` ('webp' | 'png' | 'jpg'):输出格式,默认 'webp'
|
|
258
297
|
- `targetWidth` (number):渲染宽度,默认 1280
|
|
298
|
+
- `renderer` ('pdfium' | 'pdfjs'):渲染器,默认 'pdfium'
|
|
259
299
|
- `webp` (object):WebP 编码选项
|
|
260
300
|
- `quality` (number):质量 0-100,默认 80
|
|
261
301
|
- `jpeg` (object):JPEG 编码选项
|
|
@@ -276,15 +316,30 @@ PDF 转图片。
|
|
|
276
316
|
|
|
277
317
|
**返回:** Promise\<number\>
|
|
278
318
|
|
|
279
|
-
### `isAvailable()`
|
|
319
|
+
### `isAvailable(renderer?)`
|
|
320
|
+
|
|
321
|
+
检查渲染器是否可用。
|
|
322
|
+
|
|
323
|
+
**参数:**
|
|
324
|
+
- `renderer` ('pdfium' | 'pdfjs'):可选,指定检查的渲染器,默认检查 PDFium
|
|
325
|
+
|
|
326
|
+
**返回:** boolean
|
|
327
|
+
|
|
328
|
+
### `isPdfjsAvailable()`
|
|
280
329
|
|
|
281
|
-
|
|
330
|
+
检查 PDF.js 渲染器是否可用。
|
|
282
331
|
|
|
283
332
|
**返回:** boolean
|
|
284
333
|
|
|
285
334
|
### `getVersion()`
|
|
286
335
|
|
|
287
|
-
|
|
336
|
+
获取 PDFium 渲染器版本信息。
|
|
337
|
+
|
|
338
|
+
**返回:** string
|
|
339
|
+
|
|
340
|
+
### `getPdfjsVersion()`
|
|
341
|
+
|
|
342
|
+
获取 PDF.js 渲染器版本信息。
|
|
288
343
|
|
|
289
344
|
**返回:** string
|
|
290
345
|
|
|
@@ -299,8 +354,39 @@ PDF 转图片。
|
|
|
299
354
|
| 变量 | 说明 | 默认值 |
|
|
300
355
|
|------|------|--------|
|
|
301
356
|
| `PDF2IMG_THREAD_COUNT` | 工作线程数 | CPU 核心数 |
|
|
357
|
+
| `PDF2IMG_RENDERER` | 默认渲染器 (pdfium/pdfjs) | `pdfium` |
|
|
302
358
|
| `PDF2IMG_DEBUG` | 启用调试日志 | `false` |
|
|
303
359
|
|
|
360
|
+
## 渲染器对比
|
|
361
|
+
|
|
362
|
+
| 特性 | PDFium | PDF.js |
|
|
363
|
+
|------|--------|--------|
|
|
364
|
+
| 性能 | ⚡ 快 1.7x | 普通 |
|
|
365
|
+
| 依赖 | 原生模块 | 纯 JavaScript |
|
|
366
|
+
| 大文件 (>50MB) | 普通 | ⚡ 更快 |
|
|
367
|
+
| 兼容性 | Linux/macOS/Windows | 所有平台 |
|
|
368
|
+
| 流式渲染 | ✓ | ✓ |
|
|
369
|
+
|
|
370
|
+
## 架构
|
|
371
|
+
|
|
372
|
+
模块化设计,职责分离:
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
src/
|
|
376
|
+
├── core/
|
|
377
|
+
│ ├── converter.js # 主 API 入口
|
|
378
|
+
│ ├── renderer.js # PDF 渲染逻辑(流式/下载/本地)
|
|
379
|
+
│ ├── thread-pool.js # 线程池管理
|
|
380
|
+
│ ├── downloader.js # 远程文件下载
|
|
381
|
+
│ ├── output-handler.js # 文件保存和 COS 上传
|
|
382
|
+
│ └── config.js # 配置常量
|
|
383
|
+
├── renderers/
|
|
384
|
+
│ ├── native.js # PDFium 原生渲染器
|
|
385
|
+
│ └── pdfjs.js # PDF.js 渲染器(分片加载)
|
|
386
|
+
└── utils/
|
|
387
|
+
└── logger.js # 日志工具
|
|
388
|
+
```
|
|
389
|
+
|
|
304
390
|
## 许可证
|
|
305
391
|
|
|
306
392
|
MIT
|
package/bin/cli.js
CHANGED
|
@@ -12,8 +12,13 @@
|
|
|
12
12
|
* pdf2img document.pdf -p 1,2,3 -o ./output
|
|
13
13
|
* pdf2img document.pdf --quality 90 --width 1920 -o ./output
|
|
14
14
|
* pdf2img document.pdf --format png -o ./output # 输出 PNG 格式
|
|
15
|
+
* pdf2img document.pdf --renderer pdfjs -o ./output # 使用 PDF.js 渲染器
|
|
15
16
|
* pdf2img document.pdf --cos --cos-prefix images/doc # 上传到 COS
|
|
16
17
|
*
|
|
18
|
+
* 渲染器:
|
|
19
|
+
* pdfium - PDFium 原生渲染器(默认,高性能)
|
|
20
|
+
* pdfjs - PDF.js 渲染器(纯 JavaScript,无需原生依赖)
|
|
21
|
+
*
|
|
17
22
|
* COS 环境变量:
|
|
18
23
|
* COS_SECRET_ID - 腾讯云 SecretId
|
|
19
24
|
* COS_SECRET_KEY - 腾讯云 SecretKey
|
|
@@ -42,10 +47,10 @@ try {
|
|
|
42
47
|
|
|
43
48
|
// 处理 --version-info 选项(在解析前检查)
|
|
44
49
|
if (process.argv.includes('--version-info')) {
|
|
45
|
-
const { isAvailable, getVersion } = await import('../src/index.js');
|
|
50
|
+
const { isAvailable, getVersion, RendererType } = await import('../src/index.js');
|
|
46
51
|
console.log(`pdf2img v${pkg.version}`);
|
|
47
|
-
console.log(
|
|
48
|
-
console.log(
|
|
52
|
+
console.log(`PDFium 渲染器: ${isAvailable(RendererType.PDFIUM) ? getVersion(RendererType.PDFIUM) : '不可用'}`);
|
|
53
|
+
console.log(`PDF.js 渲染器: ${isAvailable(RendererType.PDFJS) ? '可用' : '不可用'}`);
|
|
49
54
|
process.exit(0);
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -59,6 +64,7 @@ program
|
|
|
59
64
|
.option('-w, --width <width>', '目标渲染宽度(像素)', '1920')
|
|
60
65
|
.option('-q, --quality <quality>', '图片质量(0-100,用于 webp/jpg)', '100')
|
|
61
66
|
.option('-f, --format <format>', '输出格式:webp, png, jpg', 'webp')
|
|
67
|
+
.option('-r, --renderer <renderer>', '渲染器:pdfium(默认)或 pdfjs', 'pdfium')
|
|
62
68
|
.option('--prefix <prefix>', '输出文件名前缀', 'page')
|
|
63
69
|
.option('--info', '仅显示 PDF 信息(页数)')
|
|
64
70
|
.option('--version-info', '显示原生渲染器版本')
|
|
@@ -77,20 +83,31 @@ program
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
// 动态导入主模块
|
|
80
|
-
const { convert, getPageCount, isAvailable, getVersion } = await import('../src/index.js');
|
|
86
|
+
const { convert, getPageCount, isAvailable, getVersion, RendererType } = await import('../src/index.js');
|
|
81
87
|
|
|
82
88
|
// 显示版本信息
|
|
83
89
|
if (options.versionInfo) {
|
|
84
90
|
console.log(`pdf2img v${pkg.version}`);
|
|
85
|
-
console.log(
|
|
86
|
-
console.log(
|
|
91
|
+
console.log(`PDFium 渲染器: ${isAvailable(RendererType.PDFIUM) ? getVersion(RendererType.PDFIUM) : '不可用'}`);
|
|
92
|
+
console.log(`PDF.js 渲染器: ${isAvailable(RendererType.PDFJS) ? '可用' : '不可用'}`);
|
|
87
93
|
return;
|
|
88
94
|
}
|
|
89
95
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
console.error(
|
|
96
|
+
// 验证渲染器
|
|
97
|
+
const renderer = options.renderer.toLowerCase();
|
|
98
|
+
if (renderer !== 'pdfium' && renderer !== 'pdfjs') {
|
|
99
|
+
console.error(`错误:不支持的渲染器 "${options.renderer}"。支持的渲染器:pdfium, pdfjs`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 检查渲染器可用性
|
|
104
|
+
if (!isAvailable(renderer)) {
|
|
105
|
+
if (renderer === 'pdfium') {
|
|
106
|
+
console.error('错误:PDFium 原生渲染器不可用。');
|
|
107
|
+
console.error('请确保 PDFium 库已正确安装,或使用 --renderer pdfjs 切换到 PDF.js 渲染器。');
|
|
108
|
+
} else {
|
|
109
|
+
console.error('错误:PDF.js 渲染器不可用。');
|
|
110
|
+
}
|
|
94
111
|
process.exit(1);
|
|
95
112
|
}
|
|
96
113
|
|
|
@@ -111,17 +128,15 @@ program
|
|
|
111
128
|
|
|
112
129
|
// 仅显示 PDF 信息
|
|
113
130
|
if (options.info) {
|
|
114
|
-
if (isUrl) {
|
|
115
|
-
console.error('错误:--info 选项仅支持本地文件');
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
131
|
try {
|
|
120
|
-
const pageCount = getPageCount(input);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
const pageCount = await getPageCount(input, { renderer });
|
|
133
|
+
if (!isUrl) {
|
|
134
|
+
const stat = fs.statSync(input);
|
|
135
|
+
console.log(`文件: ${path.basename(input)}`);
|
|
136
|
+
console.log(`大小: ${(stat.size / 1024 / 1024).toFixed(2)} MB`);
|
|
137
|
+
}
|
|
124
138
|
console.log(`页数: ${pageCount}`);
|
|
139
|
+
console.log(`渲染器: ${renderer}`);
|
|
125
140
|
} catch (err) {
|
|
126
141
|
console.error(`错误: ${err.message}`);
|
|
127
142
|
process.exit(1);
|
|
@@ -143,6 +158,7 @@ program
|
|
|
143
158
|
targetWidth: parseInt(options.width, 10),
|
|
144
159
|
quality: parseInt(options.quality, 10),
|
|
145
160
|
format: format,
|
|
161
|
+
renderer: renderer,
|
|
146
162
|
};
|
|
147
163
|
|
|
148
164
|
// COS 模式
|
|
@@ -195,7 +211,7 @@ program
|
|
|
195
211
|
|
|
196
212
|
const duration = Date.now() - startTime;
|
|
197
213
|
|
|
198
|
-
spinner.succeed(`${modeText}完成 ${result.renderedPages}/${result.numPages} 页,格式: ${result.format.toUpperCase()},耗时 ${duration}ms`);
|
|
214
|
+
spinner.succeed(`${modeText}完成 ${result.renderedPages}/${result.numPages} 页,格式: ${result.format.toUpperCase()},渲染器: ${result.renderer},耗时 ${duration}ms`);
|
|
199
215
|
|
|
200
216
|
// 显示结果
|
|
201
217
|
if (options.cos) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-pdf2img",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "High-performance PDF to image converter using PDFium native renderer",
|
|
3
|
+
"version": "0.1.9",
|
|
4
|
+
"description": "High-performance PDF to image converter using PDFium native renderer or PDF.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"types": "./src/index.d.ts",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"image",
|
|
30
30
|
"converter",
|
|
31
31
|
"pdfium",
|
|
32
|
+
"pdfjs",
|
|
32
33
|
"webp",
|
|
33
34
|
"native",
|
|
34
35
|
"cli"
|
|
@@ -53,9 +54,13 @@
|
|
|
53
54
|
"dotenv": "^16.0.3",
|
|
54
55
|
"ora": "^8.0.0",
|
|
55
56
|
"p-limit": "^7.2.0",
|
|
57
|
+
"pdfjs-dist": "^4.0.0",
|
|
56
58
|
"piscina": "^5.1.4",
|
|
57
59
|
"sharp": "^0.33.0",
|
|
58
|
-
"node-pdf2img-native": "^1.1.
|
|
60
|
+
"node-pdf2img-native": "^1.1.10"
|
|
61
|
+
},
|
|
62
|
+
"optionalDependencies": {
|
|
63
|
+
"canvas": "^2.11.0"
|
|
59
64
|
},
|
|
60
65
|
"devDependencies": {
|
|
61
66
|
"@types/node": "^20.0.0"
|
package/src/core/config.js
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
* PDF2IMG 配置
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
// ==================== 渲染器类型 ====================
|
|
6
|
+
export const RendererType = {
|
|
7
|
+
PDFIUM: 'pdfium', // PDFium 原生渲染器(默认,高性能)
|
|
8
|
+
PDFJS: 'pdfjs', // PDF.js 渲染器(纯 JavaScript,无需原生依赖)
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// 默认渲染器
|
|
12
|
+
export const DEFAULT_RENDERER = process.env.PDF2IMG_RENDERER || RendererType.PDFIUM;
|
|
13
|
+
|
|
5
14
|
// ==================== 渲染配置 ====================
|
|
6
15
|
export const RENDER_CONFIG = {
|
|
7
16
|
// 目标渲染宽度(像素)
|