From c2d3d13c894f84c92c6994c8797f1fbd549ff773 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 23 Jan 2026 16:35:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=BE=A9=E8=A1=8C=E5=B0=BE?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=EF=BC=88CRLF=20=E2=86=92=20LF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/範例/compose.production.yml | 6 +- src/converters/ocrmypdf.ts | 63 ++++++------ src/helpers/pdfOcr.ts | 13 +-- src/helpers/printVersions.ts | 120 ++++++++++++++++++---- tests/converters/babeldoc.test.ts | 54 ++++++++-- tests/converters/pdfmathtranslate.test.ts | 64 ++++++++++-- 6 files changed, 243 insertions(+), 77 deletions(-) diff --git a/docs/範例/compose.production.yml b/docs/範例/compose.production.yml index cafc0e2..b3dddb7 100644 --- a/docs/範例/compose.production.yml +++ b/docs/範例/compose.production.yml @@ -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 # 關閉公開註冊 # 清理設定 diff --git a/src/converters/ocrmypdf.ts b/src/converters/ocrmypdf.ts index 181186d..1117aa0 100644 --- a/src/converters/ocrmypdf.ts +++ b/src/converters/ocrmypdf.ts @@ -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 = { - "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-`); } - + 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/5:PDF 已有文字層,跳過 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] 🔧 解析轉換參數...`); diff --git a/src/helpers/pdfOcr.ts b/src/helpers/pdfOcr.ts index f9e337c..b227850 100644 --- a/src/helpers/pdfOcr.ts +++ b/src/helpers/pdfOcr.ts @@ -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(" ")}`); diff --git a/src/helpers/printVersions.ts b/src/helpers/printVersions.ts index 75555d0..463384b 100644 --- a/src/helpers/printVersions.ts +++ b/src/helpers/printVersions.ts @@ -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") { } })(); } - diff --git a/tests/converters/babeldoc.test.ts b/tests/converters/babeldoc.test.ts index 7975148..f13ad79 100644 --- a/tests/converters/babeldoc.test.ts +++ b/tests/converters/babeldoc.test.ts @@ -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"); diff --git a/tests/converters/pdfmathtranslate.test.ts b/tests/converters/pdfmathtranslate.test.ts index e32bcd3..79a9c8f 100644 --- a/tests/converters/pdfmathtranslate.test.ts +++ b/tests/converters/pdfmathtranslate.test.ts @@ -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") {