You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Node.js结合DJView库的ddjvu工具转换所有DJVU文件为PDF

如何用Node.js结合ddjvu工具批量将DJVU文件转换为PDF?

嘿,这个需求我之前折腾过,刚好可以用Node.js配合DJView里的ddjvu工具搞定,还能控制并发数不让CPU跑满。下面是完整的实现方案,完全用Node.js内置模块,不用额外装第三方包:

前置准备

  • 先安装DJView库,确保ddjvu命令已经加入系统PATH(打开终端敲ddjvu --version能正常输出版本就说明没问题)
  • 确保你的机器上已经装了Node.js(v14+版本都可以)

完整实现代码

const fs = require('fs').promises;
const os = require('os');
const { spawn } = require('child_process');
const path = require('path');

// 设置最大并发进程数:CPU核心数减1,避免占满系统资源
const MAX_CONCURRENCY = os.cpus().length - 1;
// 当前正在运行的转换进程数
let currentRunning = 0;
// 待转换的文件队列
const fileQueue = [];

/**
 * 单个DJVU文件转换为PDF的函数
 * @param {string} djvuPath - 源DJVU文件路径
 * @returns {Promise<void>}
 */
async function chpoc(djvuPath) {
  return new Promise((resolve, reject) => {
    const pdfPath = path.join(path.dirname(djvuPath), `${path.basename(djvuPath, '.djvu')}.pdf`);
    
    // 启动ddjvu进程执行转换
    const ddjvuProcess = spawn('ddjvu', ['-format=pdf', djvuPath, pdfPath]);

    // 监听进程退出事件
    ddjvuProcess.on('exit', (code) => {
      if (code === 0) {
        console.log(`✅ 转换完成:${djvuPath} -> ${pdfPath}`);
        // 转换成功后删除原DJVU文件(谨慎操作,可注释掉这行先测试)
        fs.unlink(djvuPath)
          .then(() => console.log(`🗑️ 已删除原文件:${djvuPath}`))
          .catch(err => console.error(`❌ 删除原文件失败:${err.message}`));
        resolve();
      } else {
        const errorMsg = `❌ 转换失败:${djvuPath},进程退出码:${code}`;
        console.error(errorMsg);
        reject(new Error(errorMsg));
      }
    });

    // 监听进程错误事件(比如找不到ddjvu命令)
    ddjvuProcess.on('error', (err) => {
      console.error(`❌ 启动转换进程失败:${err.message}`);
      reject(err);
    });
  });
}

/**
 * 处理队列中的文件,控制并发数
 */
async function processQueue() {
  while (fileQueue.length > 0 && currentRunning < MAX_CONCURRENCY) {
    currentRunning++;
    const filePath = fileQueue.shift();
    try {
      await chpoc(filePath);
    } catch (err) {
      // 转换失败也继续处理下一个文件
      console.error(err.message);
    } finally {
      currentRunning--;
      // 处理完一个后,继续从队列取任务
      processQueue();
    }
  }
}

/**
 * 遍历指定目录,收集所有DJVU文件
 * @param {string} dirPath - 要遍历的目录路径
 */
async function collectDjvuFiles(dirPath) {
  try {
    const files = await fs.readdir(dirPath, { withFileTypes: true });
    for (const file of files) {
      const fullPath = path.join(dirPath, file.name);
      if (file.isDirectory()) {
        // 递归遍历子目录
        await collectDjvuFiles(fullPath);
      } else if (file.isFile() && path.extname(file.name).toLowerCase() === '.djvu') {
        fileQueue.push(fullPath);
      }
    }
    // 收集完文件后启动队列处理
    processQueue();
  } catch (err) {
    console.error(`❌ 遍历目录失败:${err.message}`);
  }
}

// 替换成你要处理的目录路径,比如 './djvu-files'
const targetDir = './your-djvu-directory';
collectDjvuFiles(targetDir)
  .then(() => console.log(`📋 已开始处理目录:${targetDir}`))
  .catch(err => console.error(err.message));

关键细节说明

  • 并发控制:设置MAX_CONCURRENCY为CPU核心数减1,这样既能利用多核优势,又不会让系统因为进程过多而卡顿。
  • 转换逻辑:用child_process.spawn启动ddjvu进程,指定输出格式为PDF,监听进程退出码判断转换是否成功。
  • 删除原文件:代码里默认转换成功后删除原DJVU文件,如果你担心转换出错,可以先把这行代码注释掉,等确认转换结果没问题再打开。
  • 递归遍历:支持遍历目标目录下的所有子目录,自动收集所有DJVU文件进行转换。

注意事项

  • 如果你需要转换超大的DJVU文件,可能需要调整系统的进程资源限制,不过一般情况下默认设置就够用。
  • 转换过程中不要手动中断Node.js进程,否则可能会生成不完整的PDF文件。

内容的提问来源于stack exchange,提问作者BigClap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:58:26