fix: 修復行尾格式(CRLF → LF)

This commit is contained in:
Your Name 2026-01-23 16:35:54 +08:00
parent a1761b7da5
commit c2d3d13c89
6 changed files with 243 additions and 77 deletions

View file

@ -7,7 +7,7 @@ services:
container_name: convertx-cn
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000" # 只允許本機存取,透過反向代理對外
- "127.0.0.1:3000:3000" # 只允許本機存取,透過反向代理對外
volumes:
- ./data:/app/data
environment:
@ -18,8 +18,8 @@ services:
- TZ=Asia/Taipei
# 安全性設定
- HTTP_ALLOWED=false # 禁止 HTTP使用 HTTPS
- TRUST_PROXY=true # 信任反向代理
- HTTP_ALLOWED=false # 禁止 HTTP使用 HTTPS
- TRUST_PROXY=true # 信任反向代理
- ACCOUNT_REGISTRATION=false # 關閉公開註冊
# 清理設定

View file

@ -24,24 +24,24 @@ import type { ExecFileFn } from "./types";
// 內建支援的 OCR 語言(與 PDFMathTranslate 風格一致)
const SUPPORTED_LANGUAGES = [
"en", // English
"zh-TW", // 繁體中文
"zh", // 簡體中文
"ja", // 日本語
"ko", // 한국어
"de", // Deutsch
"fr", // Français
"en", // English
"zh-TW", // 繁體中文
"zh", // 簡體中文
"ja", // 日本語
"ko", // 한국어
"de", // Deutsch
"fr", // Français
] as const;
// Tesseract 語言代碼映射UI 代碼 → Tesseract 代碼)
const LANG_MAP: Record<string, string> = {
"en": "eng",
en: "eng",
"zh-TW": "chi_tra",
"zh": "chi_sim",
"ja": "jpn",
"ko": "kor",
"de": "deu",
"fr": "fra",
zh: "chi_sim",
ja: "jpn",
ko: "kor",
de: "deu",
fr: "fra",
};
export const properties = {
@ -64,7 +64,7 @@ function extractOcrLanguage(convertTo: string): string {
if (!match || !match[1]) {
throw new Error(`Invalid convertTo format: ${convertTo}. Expected pdf-<lang>`);
}
const uiLang = match[1];
// 轉換為 Tesseract 語言代碼
const tessLang = LANG_MAP[uiLang] || uiLang.replace(/-/g, "_");
@ -98,7 +98,7 @@ function runOcrMyPdf(
console.log(`[OCRmyPDF] ========================================`);
console.log(`[OCRmyPDF] 🔍 開始 PDF OCR 處理`);
console.log(`[OCRmyPDF] ========================================`);
// 階段 1驗證輸入檔案
console.log(`[OCRmyPDF] 📋 階段 1/5驗證輸入檔案`);
if (!existsSync(inputPath)) {
@ -108,23 +108,26 @@ function runOcrMyPdf(
const inputStats = statSync(inputPath);
console.log(`[OCRmyPDF] ✅ 輸入檔案: ${basename(inputPath)}`);
console.log(`[OCRmyPDF] ✅ 檔案大小: ${formatFileSize(inputStats.size)}`);
// 階段 2準備 OCR 參數
console.log(`[OCRmyPDF] 📋 階段 2/5準備 OCR 參數`);
console.log(`[OCRmyPDF] ✅ OCR 語言: ${lang}`);
const args = [
"-l", lang,
"--skip-text", // 跳過已有文字的頁面
"--optimize", "1", // 輕度優化
"--deskew", // 自動校正傾斜
"--rotate-pages", // 自動偵測頁面方向
"--jobs", "2", // 使用 2 個並行處理
"-l",
lang,
"--skip-text", // 跳過已有文字的頁面
"--optimize",
"1", // 輕度優化
"--deskew", // 自動校正傾斜
"--rotate-pages", // 自動偵測頁面方向
"--jobs",
"2", // 使用 2 個並行處理
inputPath,
outputPath,
];
console.log(`[OCRmyPDF] ✅ 參數: --skip-text --optimize 1 --deskew --rotate-pages`);
// 階段 3執行 OCR
console.log(`[OCRmyPDF] 📋 階段 3/5執行 Tesseract OCR...`);
console.log(`[OCRmyPDF] ⏳ 處理中(大型 PDF 可能需要數分鐘)...`);
@ -132,11 +135,11 @@ function runOcrMyPdf(
execFile("ocrmypdf", args, (error: Error | null, stdout: string, stderr: string) => {
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
if (error) {
// 階段 3 失敗處理
console.log(`[OCRmyPDF] ❌ OCR 處理失敗(耗時 ${elapsed}s`);
// 檢查特定錯誤類型
if (stderr && stderr.includes("PriorOcrFoundError")) {
console.log(`[OCRmyPDF] 📋 階段 4/5PDF 已有文字層,跳過 OCR`);
@ -187,11 +190,11 @@ function runOcrMyPdf(
reject(new Error(`OCR output file not found: ${outputPath}`));
return;
}
const outputStats = statSync(outputPath);
console.log(`[OCRmyPDF] ✅ 輸出檔案: ${basename(outputPath)}`);
console.log(`[OCRmyPDF] ✅ 檔案大小: ${formatFileSize(outputStats.size)}`);
// 階段 5完成
console.log(`[OCRmyPDF] 📋 階段 5/5處理完成`);
console.log(`[OCRmyPDF] ========================================`);
@ -200,7 +203,7 @@ function runOcrMyPdf(
console.log(`[OCRmyPDF] 📤 輸出: ${formatFileSize(outputStats.size)}`);
console.log(`[OCRmyPDF] ⏱️ 耗時: ${elapsed}s`);
console.log(`[OCRmyPDF] ========================================`);
resolve(outputPath);
});
});
@ -229,7 +232,7 @@ export async function convert(
console.log(`[OCRmyPDF] ║ OCRmyPDF - PDF OCR 處理引擎 ║`);
console.log(`[OCRmyPDF] ╚════════════════════════════════════════╝`);
console.log(``);
try {
// 步驟 1解析參數
console.log(`[OCRmyPDF] 🔧 解析轉換參數...`);

View file

@ -67,7 +67,9 @@ export async function isScannedPdf(
const isScanned = charCount < SCANNED_PDF_TEXT_THRESHOLD;
if (isScanned) {
console.log(`[PDF-OCR] ⚠️ Detected scanned PDF (chars: ${charCount} < ${SCANNED_PDF_TEXT_THRESHOLD})`);
console.log(
`[PDF-OCR] ⚠️ Detected scanned PDF (chars: ${charCount} < ${SCANNED_PDF_TEXT_THRESHOLD})`,
);
} else {
console.log(`[PDF-OCR] ✅ PDF has text layer (chars: ${charCount})`);
}
@ -103,14 +105,7 @@ export function runOcrMyPdf(
// --clean: 清理背景雜訊
// --force-ocr: 強制對所有頁面進行 OCR即使有文字層
const args = [
"-l", lang,
"--skip-text",
"--optimize", "1",
"--deskew",
inputPath,
outputPath,
];
const args = ["-l", lang, "--skip-text", "--optimize", "1", "--deskew", inputPath, outputPath];
console.log(`[PDF-OCR] Running: ocrmypdf ${args.join(" ")}`);

View file

@ -25,23 +25,108 @@ const execWithTimeout = (
// 定義所有要檢查的工具
const tools = [
{ cmd: "pandoc -v", name: "Pandoc", errorMsg: "Pandoc is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "ffmpeg -version", name: "FFmpeg", errorMsg: "FFmpeg is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "vips -v", name: "Vips", errorMsg: "Vips is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "magick --version", name: "ImageMagick", errorMsg: "ImageMagick is not installed.", formatter: (s: string) => s.split("\n")[0]?.replace("Version: ", "") },
{ cmd: "gm version", name: "GraphicsMagick", errorMsg: "GraphicsMagick is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "inkscape --version", name: "Inkscape", errorMsg: "Inkscape is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "djxl --version", name: "libjxl", errorMsg: "libjxl-tools is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "dasel --version", name: "dasel", errorMsg: "dasel is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "xelatex -version", name: "XeTeX", errorMsg: "Tex Live with XeTeX is not installed.", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "resvg -V", name: "resvg", errorMsg: "resvg is not installed", formatter: (s: string) => `resvg v${s.split("\n")[0]}` },
{ cmd: "assimp version", name: "assimp", errorMsg: "assimp is not installed", formatter: (s: string) => `assimp ${s.split("\n")[5]}` },
{ cmd: "ebook-convert --version", name: "calibre", errorMsg: "ebook-convert (calibre) is not installed", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "heif-info -v", name: "libheif", errorMsg: "libheif is not installed", formatter: (s: string) => `libheif v${s.split("\n")[0]}` },
{ cmd: "potrace -v", name: "potrace", errorMsg: "potrace is not installed", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "soffice --version", name: "LibreOffice", errorMsg: "libreoffice is not installed", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "msgconvert --version", name: "msgconvert", errorMsg: "msgconvert (libemail-outlook-message-perl) is not installed", formatter: (s: string) => s.split("\n")[0] },
{ cmd: "bun -v", name: "Bun", errorMsg: "Bun is not installed. wait what", formatter: (s: string) => `Bun v${s.split("\n")[0]}` },
{
cmd: "pandoc -v",
name: "Pandoc",
errorMsg: "Pandoc is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "ffmpeg -version",
name: "FFmpeg",
errorMsg: "FFmpeg is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "vips -v",
name: "Vips",
errorMsg: "Vips is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "magick --version",
name: "ImageMagick",
errorMsg: "ImageMagick is not installed.",
formatter: (s: string) => s.split("\n")[0]?.replace("Version: ", ""),
},
{
cmd: "gm version",
name: "GraphicsMagick",
errorMsg: "GraphicsMagick is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "inkscape --version",
name: "Inkscape",
errorMsg: "Inkscape is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "djxl --version",
name: "libjxl",
errorMsg: "libjxl-tools is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "dasel --version",
name: "dasel",
errorMsg: "dasel is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "xelatex -version",
name: "XeTeX",
errorMsg: "Tex Live with XeTeX is not installed.",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "resvg -V",
name: "resvg",
errorMsg: "resvg is not installed",
formatter: (s: string) => `resvg v${s.split("\n")[0]}`,
},
{
cmd: "assimp version",
name: "assimp",
errorMsg: "assimp is not installed",
formatter: (s: string) => `assimp ${s.split("\n")[5]}`,
},
{
cmd: "ebook-convert --version",
name: "calibre",
errorMsg: "ebook-convert (calibre) is not installed",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "heif-info -v",
name: "libheif",
errorMsg: "libheif is not installed",
formatter: (s: string) => `libheif v${s.split("\n")[0]}`,
},
{
cmd: "potrace -v",
name: "potrace",
errorMsg: "potrace is not installed",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "soffice --version",
name: "LibreOffice",
errorMsg: "libreoffice is not installed",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "msgconvert --version",
name: "msgconvert",
errorMsg: "msgconvert (libemail-outlook-message-perl) is not installed",
formatter: (s: string) => s.split("\n")[0],
},
{
cmd: "bun -v",
name: "Bun",
errorMsg: "Bun is not installed. wait what",
formatter: (s: string) => `Bun v${s.split("\n")[0]}`,
},
];
if (process.env.NODE_ENV === "production") {
@ -80,4 +165,3 @@ if (process.env.NODE_ENV === "production") {
}
})();
}

View file

@ -69,7 +69,11 @@ describe("BabelDOC converter - Chinese translation", () => {
) => {
if (cmd === "pdftotext") {
// 返回超過 100 個字元,表示 PDF 不需要 OCR
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
babeldocCalled = true;
babeldocArgs = args;
@ -135,7 +139,11 @@ describe("BabelDOC converter - English translation", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
babeldocArgs = args;
const outputIndex = args.indexOf("-o");
@ -187,7 +195,11 @@ describe("BabelDOC converter - Traditional Chinese", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
babeldocArgs = args;
const outputIndex = args.indexOf("-o");
@ -239,7 +251,11 @@ describe("BabelDOC converter - Output structure", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
const outputIndex = args.indexOf("-o");
if (outputIndex !== -1 && args[outputIndex + 1]) {
@ -277,7 +293,11 @@ describe("BabelDOC converter - Output structure", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
const outputIndex = args.indexOf("-o");
if (outputIndex !== -1 && args[outputIndex + 1]) {
@ -329,7 +349,11 @@ describe("BabelDOC converter - Error handling", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
const error = new Error("Translation failed") as ExecFileException;
error.code = 1;
@ -351,7 +375,11 @@ describe("BabelDOC converter - Error handling", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
// Don't create output file, simulating failed translation
callback(null, "Complete", "");
@ -392,7 +420,11 @@ describe("BabelDOC converter - Markdown output format", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
babeldocArgs = args;
const outputIndex = args.indexOf("-o");
@ -446,7 +478,11 @@ describe("BabelDOC converter - HTML output format", () => {
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") {
callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", "");
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "babeldoc") {
babeldocArgs = args;
const outputIndex = args.indexOf("-o");

View file

@ -55,7 +55,13 @@ describe("PDFMathTranslate converter - Chinese translation", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
pdf2zhCalled = true;
pdf2zhArgs = args;
@ -116,7 +122,13 @@ describe("PDFMathTranslate converter - English translation", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
pdf2zhArgs = args;
const outputDirIndex = args.indexOf("-o");
if (outputDirIndex !== -1 && args[outputDirIndex + 1]) {
@ -165,7 +177,13 @@ describe("PDFMathTranslate converter - Japanese translation", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
pdf2zhArgs = args;
const outputDirIndex = args.indexOf("-o");
if (outputDirIndex !== -1 && args[outputDirIndex + 1]) {
@ -214,7 +232,13 @@ describe("PDFMathTranslate converter - Traditional Chinese", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
pdf2zhArgs = args;
const outputDirIndex = args.indexOf("-o");
if (outputDirIndex !== -1 && args[outputDirIndex + 1]) {
@ -264,7 +288,13 @@ describe("PDFMathTranslate converter - Output structure", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
const outputDirIndex = args.indexOf("-o");
if (outputDirIndex !== -1 && args[outputDirIndex + 1]) {
const outputDir = args[outputDirIndex + 1];
@ -308,7 +338,13 @@ describe("PDFMathTranslate converter - Output structure", () => {
args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
const outputDirIndex = args.indexOf("-o");
if (outputDirIndex !== -1 && args[outputDirIndex + 1]) {
const outputDir = args[outputDirIndex + 1];
@ -362,7 +398,13 @@ describe("PDFMathTranslate converter - Error handling", () => {
_args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
const error = new Error("Translation failed") as ExecFileException;
callback(error, "", "Error: Translation service unavailable");
}
@ -381,7 +423,13 @@ describe("PDFMathTranslate converter - Error handling", () => {
_args: string[],
callback: (err: ExecFileException | null, stdout: string, stderr: string) => void,
) => {
if (cmd === "pdftotext") { callback(null, "This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.", ""); } else if (cmd === "pdf2zh") {
if (cmd === "pdftotext") {
callback(
null,
"This is a comprehensive test PDF with more than enough text content to ensure that the OCR detection threshold of 100 characters is exceeded and the PDF is not treated as a scanned document requiring OCR processing.",
"",
);
} else if (cmd === "pdf2zh") {
// Don't create any output files
callback(null, "Complete", "");
} else if (cmd === "tar") {