license import { DetectableImage , DetectedImage } from '../../../defs/detected-image.js' ; import { DEBUG_LEVEL , log } from '../../utils/logger.js' ; interface OutgoingWorkerMessage { type : string ; data ? : any ; id ? : string ; } interface AddCallbackVals { idx : number ; id : string ; } type ProcessCallbackValue = null | number [ ] ; class Detector { private readonly targets = new Map < number , DetectedImage > ( ) ; private isReadyInternal : Promise < void > ; private worker ! : Worker ; private workerMessageCallbacks = new Map < string , ( data : any ) => void > ( ) ; constructor ( root = '' ) { this . isReadyInternal = new Promise ( ( resolve ) => { this . worker = new Worker ( `${ root }/lib/planar/planar-image_worker.js` ) ; this . worker . onmessage = async ( e ) => { if ( e . data === 'ready' ) { resolve ( ) ; return ; } const { msgId , data } = e . data ; log ( `Message (id: ${ msgId }) from worker.` , DEBUG_LEVEL . VERBOSE ) ; const callback = this . workerMessageCallbacks . get ( msgId ) ; if ( ! callback ) { return ; } this . workerMessageCallbacks . delete ( msgId ) ; callback . apply ( undefined , [ data ] ) ; } ; this . worker . postMessage ( root ) ; ( window as any ) . planarWorker = this . worker ; } ) ; } get isReady ( ) { return this . isReadyInternal ; } detect ( data ) { if ( this . targets . size === 0 ) { return Promise . resolve ( [ ] ) ; } return new Promise ( ( resolve ) => { const startTime = performance . now ( ) ; this . send ( { type : 'process' , data } , ( processData ) => { if ( processData === null ) { return [ ] ; } const matches = processData as number [ ] ; const detectedImages = matches . map ( ( id ) => this . targets . get ( id ) ) . filter ( detectedImage => ! ! detectedImage ) as DetectedImage [ ] ; resolve ( detectedImages ) ; log ( `Time taken (ms): ${ performance . now ( ) - startTime } ` + `for ${ data . width } * ${ data . height }` , DEBUG_LEVEL . VERBOSE ) ; } ) ; } ) ; } getTarget ( id ) { for ( const target of this . targets . values ( ) ) { if ( target . id === id ) { return target ; } } } addTarget ( data , image ) { return new Promise ( ( resolve ) => { this . send ( { type : 'add' , data , id : image . id } , ( addData ) => { const { idx , id } = addData ; this . targets . set ( idx as number , { id } ) ; log ( `Target stored: ${ id }, number ${ idx }` , DEBUG_LEVEL . VERBOSE ) ; resolve ( idx ) ; } ) ; } ) ; } removeTarget ( data ) { return new Promise ( ( resolve ) => { this . send ( { type : 'remove' , data } , ( removeData ) => { this . targets . delete ( removeData ) ; log ( `Target removed: number ${ data }` , DEBUG_LEVEL . VERBOSE ) ; resolve ( ) ; } ) ; } ) ; } async clear ( ) { for ( const id of this . targets . keys ( ) ) { await this . removeTarget ( id ) ; } this . targets . clear ( ) ; return new Promise ( ( resolve ) => { this . send ( { type : 'reset' } , ( ) => { log ( `Image detector reset` , DEBUG_LEVEL . VERBOSE ) ; resolve ( ) ; } ) ; } ) ; } private send ( msg , callback ) { const makeRandId = ( ) => { return new Array ( 16 ) . fill ( 0 ) . map ( ( ) => String . fromCharCode ( 97 + ( Math . random ( ) * 26 ) | 0 ) ) . join ( '' ) ; } ; const msgId = makeRandId ( ) ; log ( `Message (id: ${ msgId }, type: ${ msg . type }) to worker.` , DEBUG_LEVEL . VERBOSE ) ; this . workerMessageCallbacks . set ( msgId , callback ) ; this . worker . postMessage ( { ... msg , msgId } ) ; } } let detector ; export async function detectPlanarImages ( data , { root = '' } = { } ) { if ( ! detector ) { detector = new Detector ( root ) ; } await detector . isReady ; return detector . detect ( data ) ; } export async function addDetectionTarget ( data , image , { root = '' } = { } ) { if ( ! detector ) { detector = new Detector ( root ) ; } await detector . isReady ; return detector . addTarget ( data , image ) ; } export async function removeDetectionTarget ( id , { root = '' } = { } ) { if ( ! detector ) { detector = new Detector ( root ) ; } await detector . isReady ; return detector . removeTarget ( id ) ; } export async function getTarget ( id , { root = '' } = { } ) { if ( ! detector ) { detector = new Detector ( root ) ; } await detector . isReady ; return detector . getTarget ( id ) ; } export async function reset ( ) { if ( ! detector ) { return ; } return detector . clear ( ) ; }