import{createWorker}from'tesseract.js';import{readFile,writeFile,stat,readdir}from'node:fs/promises';import{resolve,extname,join,dirname}from'node:path';import{fileURLToPath}from'node:url';
const root=resolve(dirname(fileURLToPath(import.meta.url)),'..');
export async function recognizeFiles(paths,{langs='rus+eng',psm='6',whitelist='',logger=()=>{}}={}){if(!['eng','rus','rus+eng'].includes(langs))throw Error('Allowed languages: eng, rus, rus+eng');if(!['3','6','7','11'].includes(String(psm)))throw Error('Allowed PSM: 3,6,7,11');if(paths.length<1||paths.length>20)throw Error('Provide 1–20 image paths');let worker;const results=[];try{worker=await createWorker(langs,1,{langPath:join(root,'public/vendor/lang'),cacheMethod:'none',logger});await worker.setParameters({tessedit_pageseg_mode:String(psm),tessedit_char_whitelist:whitelist,user_defined_dpi:'300'});for(const p of paths){if(!['.png','.jpg','.jpeg','.webp'].includes(extname(p).toLowerCase()))throw Error('CLI accepts PNG/JPEG/WebP. Render PDF separately with PDF.js.');if((await stat(p)).size>8*1024*1024)throw Error('Image is over 8 MiB');const{data}=await worker.recognize(await readFile(p),{}, {text:true,blocks:true});results.push({file:p,text:data.text,confidence:data.confidence});}return results;}finally{if(worker)await worker.terminate();}}
if(process.argv[1]&&resolve(process.argv[1])===fileURLToPath(import.meta.url)){try{const[input='fixtures/ru.png',langs='rus',output='ocr-result.json']=process.argv.slice(2);const abs=resolve(input),s=await stat(abs),paths=s.isDirectory()?(await readdir(abs)).filter(n=>/\.(png|jpe?g|webp)$/i.test(n)).sort().map(n=>join(abs,n)):[abs];const results=await recognizeFiles(paths,{langs,logger:m=>{if(m.status==='recognizing text')process.stderr.write(`OCR ${Math.round(m.progress*100)}%\n`);}});await writeFile(output,JSON.stringify({engine:'Tesseract.js 7.0.0',results},null,2)+'\n',{flag:'wx'});console.log(`Saved ${results.length} results to ${output}`);}catch(e){console.error(e.message);process.exitCode=1;}}
