const resolvePaths = require('./utils/resolvePaths'); const circularize = require('./utils/circularize'); const createJob = require('./createJob'); const { log } = require('./utils/log'); const getId = require('./utils/getId'); const { defaultOEM } = require('./constants/config'); const { defaultOptions, spawnWorker, terminateWorker, onMessage, loadImage, send, } = require('./worker/node'); let workerCounter = 0; module.exports = async (_options = {}) => { const id = getId('Worker', workerCounter); const { logger, errorHandler, ...options } = resolvePaths({ ...defaultOptions, ..._options, }); const resolves = {}; const rejects = {}; let workerResReject; let workerResResolve; const workerRes = new Promise((resolve, reject) => { workerResResolve = resolve; workerResReject = reject; }); const workerError = (event) => { workerResReject(event.message); }; let worker = spawnWorker(options); worker.onerror = workerError; workerCounter += 1; const setResolve = (action, res) => { resolves[action] = res; }; const setReject = (action, rej) => { rejects[action] = rej; }; const startJob = ({ id: jobId, action, payload }) => ( new Promise((resolve, reject) => { log(`[${id}]: Start ${jobId}, action=${action}`); setResolve(action, resolve); setReject(action, reject); send(worker, { workerId: id, jobId, action, payload, }); }) ); const load = () => ( console.warn('`load` is depreciated and should be removed from code (workers now come pre-loaded)') ); const loadInternal = (jobId) => ( startJob(createJob({ id: jobId, action: 'load', payload: { options }, })) ); const writeText = (path, text, jobId) => ( startJob(createJob({ id: jobId, action: 'FS', payload: { method: 'writeFile', args: [path, text] }, })) ); const readText = (path, jobId) => ( startJob(createJob({ id: jobId, action: 'FS', payload: { method: 'readFile', args: [path, { encoding: 'utf8' }] }, })) ); const removeFile = (path, jobId) => ( startJob(createJob({ id: jobId, action: 'FS', payload: { method: 'unlink', args: [path] }, })) ); const FS = (method, args, jobId) => ( startJob(createJob({ id: jobId, action: 'FS', payload: { method, args }, })) ); const loadLanguage = (langs = 'eng', jobId) => ( startJob(createJob({ id: jobId, action: 'loadLanguage', payload: { langs, options }, })) ); const initialize = (langs = 'eng', oem = defaultOEM, jobId) => ( startJob(createJob({ id: jobId, action: 'initialize', payload: { langs, oem }, })) ); const setParameters = (params = {}, jobId) => ( startJob(createJob({ id: jobId, action: 'setParameters', payload: { params }, })) ); const recognize = async (image, opts = {}, output = {blocks: true, text: true, hocr: true, tsv: true}, jobId) => ( startJob(createJob({ id: jobId, action: 'recognize', payload: { image: await loadImage(image), options: opts, output }, })) ); const getPDF = (title = 'Tesseract OCR Result', textonly = false, jobId) => { console.log('`getPDF` function is depreciated. `recognize` option `savePDF` should be used instead.'); return startJob(createJob({ id: jobId, action: 'getPDF', payload: { title, textonly }, })); }; const detect = async (image, jobId) => ( startJob(createJob({ id: jobId, action: 'detect', payload: { image: await loadImage(image) }, })) ); const terminate = async () => { if (worker !== null) { /* await startJob(createJob({ id: jobId, action: 'terminate', })); */ terminateWorker(worker); worker = null; } return Promise.resolve(); }; onMessage(worker, ({ workerId, jobId, status, action, data, }) => { if (status === 'resolve') { log(`[${workerId}]: Complete ${jobId}`); let d = data; if (action === 'recognize') { d = circularize(data); } else if (action === 'getPDF') { d = Array.from({ ...data, length: Object.keys(data).length }); } resolves[action]({ jobId, data: d }); } else if (status === 'reject') { rejects[action](data); if (action === 'load') workerResReject(data); if (errorHandler) { errorHandler(data); } else { throw Error(data); } } else if (status === 'progress') { logger({ ...data, userJobId: jobId }); } }); const resolveObj = { id, worker, setResolve, setReject, load, writeText, readText, removeFile, FS, loadLanguage, initialize, setParameters, recognize, getPDF, detect, terminate, }; loadInternal().then(() => workerResResolve(resolveObj)).catch(() => {}); return workerRes; };