pdf-fox 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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +140 -0
- package/dist/cli.js.map +1 -0
- package/dist/converter.d.ts +4 -0
- package/dist/converter.d.ts.map +1 -0
- package/dist/converter.js +78 -0
- package/dist/converter.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +43 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { parseArgs } from "util";
|
|
3
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from "fs";
|
|
4
|
+
import { resolve, basename, extname, dirname, join } from "path";
|
|
5
|
+
import { createRequire } from "module";
|
|
6
|
+
import { convertPdfToPng, convertPdfPageToPng } from "./index.js";
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { version } = require("../package.json");
|
|
9
|
+
const PDF_BASE_DPI = 72;
|
|
10
|
+
const DEFAULT_DPI = 200;
|
|
11
|
+
const HELP = `\
|
|
12
|
+
Usage: pdf-fox <input.pdf> [options]
|
|
13
|
+
|
|
14
|
+
Arguments:
|
|
15
|
+
input.pdf 変換するPDFファイルのパス
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
-o, --output <path> 出力先ディレクトリまたはファイルパス
|
|
19
|
+
省略時は入力ファイルと同じディレクトリ
|
|
20
|
+
-p, --page <number> 変換するページ番号(省略時は全ページ)
|
|
21
|
+
-r, --dpi <number> 解像度 DPI(デフォルト: ${DEFAULT_DPI})
|
|
22
|
+
-b, --background <color> 背景色(デフォルト: white)
|
|
23
|
+
-h, --help ヘルプを表示
|
|
24
|
+
-V, --version バージョンを表示
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
pdf-fox doc.pdf 全ページ変換 → doc-1.png, doc-2.png ...
|
|
28
|
+
pdf-fox doc.pdf -o out/ 出力先ディレクトリを指定
|
|
29
|
+
pdf-fox doc.pdf -p 2 2ページ目のみ変換
|
|
30
|
+
pdf-fox doc.pdf -p 1 -o cover.png 1ページ目を cover.png として保存
|
|
31
|
+
pdf-fox doc.pdf --dpi 300 300 DPI で変換
|
|
32
|
+
`;
|
|
33
|
+
function parseCliArgs() {
|
|
34
|
+
const { values, positionals } = parseArgs({
|
|
35
|
+
options: {
|
|
36
|
+
output: { type: "string", short: "o" },
|
|
37
|
+
page: { type: "string", short: "p" },
|
|
38
|
+
dpi: { type: "string", short: "r" },
|
|
39
|
+
background: { type: "string", short: "b" },
|
|
40
|
+
help: { type: "boolean", short: "h" },
|
|
41
|
+
version: { type: "boolean", short: "V" },
|
|
42
|
+
},
|
|
43
|
+
allowPositionals: true,
|
|
44
|
+
});
|
|
45
|
+
if (values.help) {
|
|
46
|
+
process.stdout.write(HELP);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
if (values.version) {
|
|
50
|
+
process.stdout.write(`${version}\n`);
|
|
51
|
+
process.exit(0);
|
|
52
|
+
}
|
|
53
|
+
if (positionals.length === 0) {
|
|
54
|
+
process.stderr.write("Error: PDFファイルのパスを指定してください\n\n");
|
|
55
|
+
process.stderr.write(HELP);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const page = values.page !== undefined ? Number(values.page) : undefined;
|
|
59
|
+
if (page !== undefined && (!Number.isInteger(page) || page < 1)) {
|
|
60
|
+
exitWithError("--page は 1 以上の整数を指定してください");
|
|
61
|
+
}
|
|
62
|
+
const dpi = values.dpi !== undefined ? Number(values.dpi) : DEFAULT_DPI;
|
|
63
|
+
if (isNaN(dpi) || dpi <= 0) {
|
|
64
|
+
exitWithError("--dpi は正の数を指定してください");
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
inputPath: positionals[0],
|
|
68
|
+
outputOption: values.output,
|
|
69
|
+
page,
|
|
70
|
+
dpi,
|
|
71
|
+
background: values.background ?? "white",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function resolveOutputSpec(inputPath, outputOption) {
|
|
75
|
+
const stem = basename(inputPath, extname(inputPath));
|
|
76
|
+
if (!outputOption) {
|
|
77
|
+
return { kind: "directory", dir: dirname(resolve(inputPath)), stem };
|
|
78
|
+
}
|
|
79
|
+
const resolved = resolve(outputOption);
|
|
80
|
+
// 末尾スラッシュ or 既存ディレクトリはディレクトリ出力として扱う
|
|
81
|
+
if (outputOption.endsWith("/") || (existsSync(resolved) && statSync(resolved).isDirectory())) {
|
|
82
|
+
return { kind: "directory", dir: resolved, stem };
|
|
83
|
+
}
|
|
84
|
+
return { kind: "file", path: resolved };
|
|
85
|
+
}
|
|
86
|
+
function buildOutputPath(spec, pageNumber) {
|
|
87
|
+
if (spec.kind === "file")
|
|
88
|
+
return spec.path;
|
|
89
|
+
return join(spec.dir, `${spec.stem}-${pageNumber}.png`);
|
|
90
|
+
}
|
|
91
|
+
function writePage(outputPath, page) {
|
|
92
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
93
|
+
writeFileSync(outputPath, page.data);
|
|
94
|
+
process.stdout.write(`${outputPath}\n`);
|
|
95
|
+
}
|
|
96
|
+
function exitWithError(message) {
|
|
97
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
async function run() {
|
|
101
|
+
const { inputPath, outputOption, page, dpi, background } = parseCliArgs();
|
|
102
|
+
const scale = dpi / PDF_BASE_DPI;
|
|
103
|
+
let pdfBuffer;
|
|
104
|
+
try {
|
|
105
|
+
pdfBuffer = readFileSync(resolve(inputPath));
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
exitWithError(`ファイルを読み込めません: ${inputPath}`);
|
|
109
|
+
}
|
|
110
|
+
const outputSpec = resolveOutputSpec(inputPath, outputOption);
|
|
111
|
+
if (page !== undefined) {
|
|
112
|
+
let result;
|
|
113
|
+
try {
|
|
114
|
+
result = await convertPdfPageToPng(pdfBuffer, page, { scale, background });
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
exitWithError(err instanceof Error ? err.message : String(err));
|
|
118
|
+
}
|
|
119
|
+
writePage(buildOutputPath(outputSpec, result.pageNumber), result);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
let pages;
|
|
123
|
+
try {
|
|
124
|
+
pages = await convertPdfToPng(pdfBuffer, { scale, background });
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
exitWithError(err instanceof Error ? err.message : String(err));
|
|
128
|
+
}
|
|
129
|
+
if (outputSpec.kind === "file" && pages.length > 1) {
|
|
130
|
+
exitWithError(`複数ページ(${pages.length}ページ)のPDFを1ファイルに出力できません。` +
|
|
131
|
+
`-o にディレクトリを指定するか、-p でページを指定してください`);
|
|
132
|
+
}
|
|
133
|
+
for (const p of pages) {
|
|
134
|
+
writePage(buildOutputPath(outputSpec, p.pageNumber), p);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
run().catch((err) => {
|
|
138
|
+
exitWithError(err instanceof Error ? err.message : String(err));
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ConvertOptions, PngPage } from "./types.js";
|
|
2
|
+
export declare function convertPdfPageToPng(input: Buffer | Uint8Array, pageNumber: number, options?: ConvertOptions): Promise<PngPage>;
|
|
3
|
+
export declare function convertPdfToPng(input: Buffer | Uint8Array, options?: ConvertOptions): Promise<PngPage[]>;
|
|
4
|
+
//# sourceMappingURL=converter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.d.ts","sourceRoot":"","sources":["../src/converter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AA6D1D,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,CAAC,CAIlB;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,GAAG,UAAU,EAC1B,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,OAAO,EAAE,CAAC,CAWpB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createCanvas } from "@napi-rs/canvas";
|
|
2
|
+
import { createRequire } from "module";
|
|
3
|
+
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist/legacy/build/pdf.mjs";
|
|
4
|
+
const DEFAULT_SCALE = 1.5;
|
|
5
|
+
const DEFAULT_BACKGROUND = "white";
|
|
6
|
+
// Use createRequire so Node.js resolves paths from node_modules,
|
|
7
|
+
// not relative to this source file.
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const workerPath = require.resolve("pdfjs-dist/legacy/build/pdf.worker.min.mjs");
|
|
10
|
+
GlobalWorkerOptions.workerSrc = `file://${workerPath}`;
|
|
11
|
+
// pdfjs-dist's NodeBinaryDataFactory uses fs.readFile(url) which accepts plain
|
|
12
|
+
// file paths but not "file://" string URLs. Passing the directory path directly
|
|
13
|
+
// (with trailing slash) lets fs.readFile resolve font files correctly.
|
|
14
|
+
const standardFontsDir = require
|
|
15
|
+
.resolve("pdfjs-dist/standard_fonts/FoxitSerif.pfb")
|
|
16
|
+
.replace("FoxitSerif.pfb", "");
|
|
17
|
+
const STANDARD_FONT_DATA_URL = standardFontsDir;
|
|
18
|
+
async function renderPageToPng(pdfData, pageNumber, options) {
|
|
19
|
+
// PDF.js transfers the ArrayBuffer to the worker thread (detaching it), so we
|
|
20
|
+
// must pass a fresh copy per getDocument call to allow parallel rendering.
|
|
21
|
+
const loadingTask = getDocument({ data: new Uint8Array(pdfData), standardFontDataUrl: STANDARD_FONT_DATA_URL });
|
|
22
|
+
const pdfDocument = await loadingTask.promise;
|
|
23
|
+
try {
|
|
24
|
+
const page = await pdfDocument.getPage(pageNumber);
|
|
25
|
+
const viewport = page.getViewport({ scale: options.scale });
|
|
26
|
+
const canvas = createCanvas(viewport.width, viewport.height);
|
|
27
|
+
const context = canvas.getContext("2d");
|
|
28
|
+
context.fillStyle = options.background;
|
|
29
|
+
context.fillRect(0, 0, viewport.width, viewport.height);
|
|
30
|
+
// canvasContext only (canvas: null) — PDF.js uses the provided 2D context
|
|
31
|
+
// directly without trying to call canvas.getContext() internally.
|
|
32
|
+
await page.render({
|
|
33
|
+
canvas: null,
|
|
34
|
+
canvasContext: context,
|
|
35
|
+
viewport,
|
|
36
|
+
}).promise;
|
|
37
|
+
const data = canvas.toBuffer("image/png");
|
|
38
|
+
return {
|
|
39
|
+
pageNumber,
|
|
40
|
+
data,
|
|
41
|
+
width: viewport.width,
|
|
42
|
+
height: viewport.height,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await pdfDocument.cleanup();
|
|
47
|
+
await loadingTask.destroy();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function convertPdfPageToPng(input, pageNumber, options) {
|
|
51
|
+
const resolvedOptions = resolveOptions(options);
|
|
52
|
+
const pdfData = toUint8Array(input);
|
|
53
|
+
return renderPageToPng(pdfData, pageNumber, resolvedOptions);
|
|
54
|
+
}
|
|
55
|
+
export async function convertPdfToPng(input, options) {
|
|
56
|
+
const resolvedOptions = resolveOptions(options);
|
|
57
|
+
const pdfData = toUint8Array(input);
|
|
58
|
+
const pageCount = await getPageCount(pdfData);
|
|
59
|
+
return Promise.all(Array.from({ length: pageCount }, (_, i) => renderPageToPng(pdfData, i + 1, resolvedOptions)));
|
|
60
|
+
}
|
|
61
|
+
async function getPageCount(pdfData) {
|
|
62
|
+
const loadingTask = getDocument({ data: new Uint8Array(pdfData), standardFontDataUrl: STANDARD_FONT_DATA_URL });
|
|
63
|
+
const pdfDocument = await loadingTask.promise;
|
|
64
|
+
const count = pdfDocument.numPages;
|
|
65
|
+
await pdfDocument.cleanup();
|
|
66
|
+
await loadingTask.destroy();
|
|
67
|
+
return count;
|
|
68
|
+
}
|
|
69
|
+
function resolveOptions(options) {
|
|
70
|
+
return {
|
|
71
|
+
scale: options?.scale ?? DEFAULT_SCALE,
|
|
72
|
+
background: options?.background ?? DEFAULT_BACKGROUND,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function toUint8Array(input) {
|
|
76
|
+
return new Uint8Array(input);
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"converter.js","sourceRoot":"","sources":["../src/converter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtE,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ConvertOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Rendering scale. 1.0 = original size, 2.0 = double resolution.
|
|
4
|
+
* @default 1.5
|
|
5
|
+
*/
|
|
6
|
+
scale?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Canvas background color. Any valid CSS color string.
|
|
9
|
+
* @default "white"
|
|
10
|
+
*/
|
|
11
|
+
background?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PngPage {
|
|
14
|
+
/** 1-indexed page number */
|
|
15
|
+
pageNumber: number;
|
|
16
|
+
/** PNG image data */
|
|
17
|
+
data: Buffer;
|
|
18
|
+
/** Rendered width in pixels */
|
|
19
|
+
width: number;
|
|
20
|
+
/** Rendered height in pixels */
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,4BAA4B;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pdf-fox",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "PDF to PNG converter using PDF.js",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"pdf-fox": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"prepare": "tsc",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"pdf",
|
|
28
|
+
"png",
|
|
29
|
+
"converter",
|
|
30
|
+
"pdfjs"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "ISC",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@napi-rs/canvas": "^1.0.0",
|
|
36
|
+
"pdfjs-dist": "^6.0.227"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.9.2",
|
|
40
|
+
"typescript": "^6.0.3",
|
|
41
|
+
"vitest": "^4.1.8"
|
|
42
|
+
}
|
|
43
|
+
}
|