跳到主要内容

宝玉知识漫画与故事分镜

收藏0

把知识、教程和故事整理成连贯漫画,规划角色、分镜和逐页提示词,调用已有绘图工具出图,可将图片合成 PDF。

让 AI 安装

github最新版本 0.1.0更新于 2026-10-24下载 1 次

scripts/merge-to-pdf.ts

3.2 KB
1import { existsSync, readdirSync, readFileSync } from "fs";
2import { join, basename } from "path";
3import { PDFDocument } from "pdf-lib";
4
5interface PageInfo {
6 filename: string;
7 path: string;
8 index: number;
9 promptPath?: string;
10}
11
12function parseArgs(): { dir: string; output?: string } {
13 const args = process.argv.slice(2);
14 let dir = "";
15 let output: string | undefined;
16
17 for (let i = 0; i < args.length; i++) {
18 if (args[i] === "--output" || args[i] === "-o") {
19 output = args[++i];
20 } else if (!args[i].startsWith("-")) {
21 dir = args[i];
22 }
23 }
24
25 if (!dir) {
26 console.error("Usage: bun merge-to-pdf.ts <comic-dir> [--output filename.pdf]");
27 process.exit(1);
28 }
29
30 return { dir, output };
31}
32
33function findComicPages(dir: string): PageInfo[] {
34 if (!existsSync(dir)) {
35 console.error(`Directory not found: ${dir}`);
36 process.exit(1);
37 }
38
39 const files = readdirSync(dir);
40 const pagePattern = /^(\d+)-(cover|page)(-[\w-]+)?\.(png|jpg|jpeg)$/i;
41 const promptsDir = join(dir, "prompts");
42 const hasPrompts = existsSync(promptsDir);
43
44 const pages: PageInfo[] = files
45 .filter((f) => pagePattern.test(f))
46 .map((f) => {
47 const match = f.match(pagePattern);
48 const baseName = f.replace(/\.(png|jpg|jpeg)$/i, "");
49 const promptPath = hasPrompts ? join(promptsDir, `${baseName}.md`) : undefined;
50
51 return {
52 filename: f,
53 path: join(dir, f),
54 index: parseInt(match![1], 10),
55 promptPath: promptPath && existsSync(promptPath) ? promptPath : undefined,
56 };
57 })
58 .sort((a, b) => a.index - b.index);
59
60 if (pages.length === 0) {
61 console.error(`No comic pages found in: ${dir}`);
62 console.error("Expected format: 00-cover-slug.png, 01-page-slug.png, etc.");
63 process.exit(1);
64 }
65
66 return pages;
67}
68
69async function createPdf(pages: PageInfo[], outputPath: string) {
70 const pdfDoc = await PDFDocument.create();
71 pdfDoc.setAuthor("baoyu-comic");
72 pdfDoc.setSubject("Generated Comic");
73
74 for (const page of pages) {
75 const imageData = readFileSync(page.path);
76 const ext = page.filename.toLowerCase();
77 const image = ext.endsWith(".png")
78 ? await pdfDoc.embedPng(imageData)
79 : await pdfDoc.embedJpg(imageData);
80
81 const { width, height } = image;
82 const pdfPage = pdfDoc.addPage([width, height]);
83
84 pdfPage.drawImage(image, {
85 x: 0,
86 y: 0,
87 width,
88 height,
89 });
90
91 console.log(`Added: ${page.filename}${page.promptPath ? " (prompt available)" : ""}`);
92 }
93
94 const pdfBytes = await pdfDoc.save();
95 await Bun.write(outputPath, pdfBytes);
96
97 console.log(`\nCreated: ${outputPath}`);
98 console.log(`Total pages: ${pages.length}`);
99}
100
101async function main() {
102 const { dir, output } = parseArgs();
103 const pages = findComicPages(dir);
104
105 const dirName = basename(dir) === "comic" ? basename(join(dir, "..")) : basename(dir);
106 const outputPath = output || join(dir, `${dirName}.pdf`);
107
108 console.log(`Found ${pages.length} pages in: ${dir}\n`);
109
110 await createPdf(pages, outputPath);
111}
112
113main().catch((err) => {
114 console.error("Error:", err.message);
115 process.exit(1);
116});

文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。