ai-query对接新版freesun-agent接口的分支
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

105 lines
3.2 KiB

const fs = require('fs');
const path = require('path');
const { execFile } = require('child_process');
const { promisify } = require('util');
const execFileAsync = promisify(execFile);
// ========== 用 pdfinfo 获取页数(保持不变) ==========
async function getPDFPageCount(pdfPath) {
try {
const { stdout } = await execFileAsync('pdfinfo', [pdfPath], {
timeout: 10000,
maxBuffer: 1024 * 1024
});
const match = stdout.match(/Pages:\s*(\d+)/i);
return match ? parseInt(match[1], 10) : 1;
} catch (error) {
console.error(`[PDF2IMG] pdfinfo failed:`, error.message);
return 1;
}
}
// ========== 直接调用 pdftoppm 转换单页 ==========
async function convertPdfPageToPng(pdfPath, outputDir, pageNum, dpi = 150) {
// 通过 -singlefile + 带页码的基础名,确保输出文件名稳定为 page-<pageNum>.png
const expectedOutputPath = path.join(outputDir, `page-${pageNum}.png`);
const outputBaseName = path.join(outputDir, `page-${pageNum}`); // 不包含扩展名
try {
await execFileAsync('pdftoppm', [
'-png',
'-singlefile',
'-r', dpi.toString(),
'-f', pageNum.toString(),
'-l', pageNum.toString(),
pdfPath,
outputBaseName // 只提供基础名称
], {
timeout: 30000, // 30秒超时
windowsHide: true
});
if (fs.existsSync(expectedOutputPath)) {
const size = fs.statSync(expectedOutputPath).size;
console.log(`[PDF2IMG] Page ${pageNum} saved (${size} bytes): ${expectedOutputPath}`);
return expectedOutputPath;
} else {
throw new Error(`Expected output file not found: ${expectedOutputPath}`);
}
} catch (error) {
console.error(`[PDF2IMG] pdftoppm failed for page ${pageNum}:`, error.message);
throw error;
}
}
// ========== 主转换函数 ==========
async function convertPdfToImages(
pdfPath,
outputDir,
dpi = 150,
startPage = 1,
endPage = null
) {
const startTime = Date.now();
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const stats = fs.statSync(pdfPath);
console.log(`[PDF2IMG] Input PDF: ${pdfPath} (${(stats.size / 1024 / 1024).toFixed(2)} MB)`);
const totalPages = await getPDFPageCount(pdfPath);
console.log(`[PDF2IMG] Detected ${totalPages} pages`);
const normalizedStartPage = Math.max(
1,
Math.min(totalPages, Number(startPage) || 1)
);
const normalizedEndPage = Math.max(
normalizedStartPage,
Math.min(totalPages, Number(endPage) || totalPages)
);
const imagePaths = [];
console.log(
`[PDF2IMG] Converting pages ${normalizedStartPage}-${normalizedEndPage} with DPI=${dpi}...`
);
for (let pageNum = normalizedStartPage; pageNum <= normalizedEndPage; pageNum++) {
try {
const imagePath = await convertPdfPageToPng(pdfPath, outputDir, pageNum, dpi);
imagePaths.push(imagePath);
} catch (err) {
console.warn(`[PDF2IMG] Skipping page ${pageNum} due to error:`, err.message);
}
}
const duration = Date.now() - startTime;
const plannedPages = normalizedEndPage - normalizedStartPage + 1;
console.log(`[PDF2IMG] ✅ Converted ${imagePaths.length}/${plannedPages} pages in ${duration}ms`);
return imagePaths;
}
module.exports = { convertPdfToImages };