1+ import {
2+ fileLoaderString ,
3+ loadAllFilesOfElementAsStringWithCallback
4+ } from '../../util/fileLoader' ;
5+ import {
6+ boundingBoxesOpts
7+
8+ } from './util' ;
9+ import {
10+ createUidLookupMap
11+ } from '../../util/char_text_map' ;
12+ import {
13+ determineCorrectParserSettings
14+ } from '../../util/parserSettingsGenerator' ;
15+ import type {
16+ ImportCharacterBoundingBoxDto
17+ } from '@/types/dtos/ImportCharacterBoundingBoxDto' ;
18+ import type {
19+ ImportConfig
20+ } from '@/types/import' ;
21+ import {
22+ MissingFilesError
23+ } from '../../util/errors' ;
24+
25+ export const boundingBoxImporter : ImportConfig < ImportCharacterBoundingBoxDto [ ] > = {
26+ 'display' : 'Text UID based Bounding Box Creation ' ,
27+ 'options' : {
28+ ...boundingBoxesOpts ,
29+ 'textuid' : {
30+ 'display' : 'Text UID' ,
31+ 'value' : 'text_uid' ,
32+ 'input' : 'string' ,
33+ 'searchTerms' : [
34+ 'text_uid' ,
35+ 'textuid'
36+ ]
37+ } ,
38+ 'association' : {
39+ 'display' : 'Text to generate associations from' , // TODO: Update name, this is for texts.csv file
40+ 'value' : null ,
41+ 'input' : 'file'
42+ } ,
43+ 'assTextUID' : {
44+ 'display' : 'Text UID' , // TODO: Update name, this is for texts.csv file
45+ 'value' : 'text_uid' ,
46+ 'input' : 'string'
47+ } ,
48+ 'assTextID' : {
49+ 'display' : 'Text ID' , // TODO: Update name, this is for texts.csv file
50+ 'value' : 'text_id' ,
51+ 'input' : 'string'
52+ } ,
53+ 'assLang' : {
54+ 'display' : 'Language' , // TODO: Update name, this is for texts.csv file
55+ 'value' : 'lang' ,
56+ 'input' : 'string'
57+ }
58+ } ,
59+ 'parse' : async ( inputElement : HTMLInputElement , _textId : string , lang : string ) : Promise < ImportCharacterBoundingBoxDto [ ] > => {
60+ if ( ! inputElement . files || ! inputElement . files [ 0 ] ) throw new MissingFilesError ( ) ;
61+
62+ const assocFile = boundingBoxImporter . options . association ?. value as File | null ;
63+ const uidCol = boundingBoxImporter . options . assTextUID ?. value as string | undefined ;
64+ const idCol = boundingBoxImporter . options . assTextID ?. value as string | undefined ;
65+
66+ if ( ! assocFile || ! uidCol || ! idCol ) {
67+ throw new MissingFilesError ( ) ;
68+ }
69+
70+ // build lookup from textuid -> textid
71+ const textUidLookup = createUidLookupMap (
72+ await fileLoaderString ( assocFile ) ,
73+ uidCol ,
74+ idCol
75+ ) ;
76+ const boundingBoxStore : ImportCharacterBoundingBoxDto [ ] = [ ] ;
77+
78+ await loadAllFilesOfElementAsStringWithCallback ( inputElement , async ( data : string ) => {
79+ const lines = data . split ( / \r ? \n / ) . filter ( l => l . trim ( ) !== '' ) ;
80+ const header = lines . shift ( ) ! . split ( ',' ) . map ( h => h . trim ( ) ) ;
81+ const textUidIndex = header . indexOf ( boundingBoxImporter . options . textuid ! . value as string ) ;
82+ const charIndex = header . indexOf ( boundingBoxesOpts . char ! . value as string ) ;
83+ const xMinIndex = header . indexOf ( boundingBoxesOpts . xMin ! . value as string ) ;
84+ const xMaxIndex = header . indexOf ( boundingBoxesOpts . xMax ! . value as string ) ;
85+ const yMinIndex = header . indexOf ( boundingBoxesOpts . yMin ! . value as string ) ;
86+ const yMaxIndex = header . indexOf ( boundingBoxesOpts . yMax ! . value as string ) ;
87+ const langIndex = header . indexOf ( boundingBoxesOpts . lang ! . value as string ) ;
88+
89+ if ( textUidIndex < 0 )
90+ throw new Error ( 'text UID column not found' ) ;
91+
92+ if ( charIndex < 0 )
93+ throw new Error ( 'character column not found' ) ;
94+
95+ if ( xMinIndex < 0 || xMaxIndex < 0 || yMinIndex < 0 || yMaxIndex < 0 )
96+ throw new Error ( 'bounding box coordinate columns not found' ) ;
97+
98+ lines . forEach ( line => {
99+ const cols = line . split ( ',' ) ;
100+
101+ if ( lang === 'undefined' || ( langIndex > - 1 ? cols [ langIndex ] ! === lang : true ) ) {
102+ const uid = cols [ textUidIndex ] ! ;
103+ const mappedId = textUidLookup . get ( uid ) ;
104+
105+ if ( mappedId ) {
106+ const x1 = Number ( cols [ xMinIndex ] ) ;
107+ const x2 = Number ( cols [ xMaxIndex ] ) ;
108+ const y1 = Number ( cols [ yMinIndex ] ) ;
109+ const y2 = Number ( cols [ yMaxIndex ] ) ;
110+
111+ boundingBoxStore . push ( {
112+ 'foreignId' : Number ( mappedId ) ,
113+ 'character' : String ( cols [ charIndex ] ) ,
114+ 'xMin' : x1 < x2 ? x1 : x2 ,
115+ 'xMax' : x1 < x2 ? x2 : x1 ,
116+ 'yMin' : y1 < y2 ? y1 : y2 ,
117+ 'yMax' : y1 < y2 ? y2 : y1
118+ } ) ;
119+ }
120+ }
121+ } ) ;
122+ } ) ;
123+
124+ return boundingBoxStore ;
125+ } ,
126+ 'canParse' : ( header : string [ ] ) => {
127+ return determineCorrectParserSettings ( header , boundingBoxImporter ) ;
128+ }
129+ } ;
0 commit comments