~f0ma/cuneiform-linux/devel

« back to all changes in this revision

Viewing changes to cuneiform_src/cli/ocelot.cpp

  • Committer: Stanislav Ivanov
  • Date: 2017-06-07 15:03:51 UTC
  • Revision ID: ivstdm@gmail.com-20170607150351-dlzbzl54zvs57z57
New command line interface with multipage support and input image filtering.
Alpha state. No checks for build in other platform. Tests is missing.
Magick++ and C++0x is requried.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "ocelot.h"
 
2
 
 
3
// Puma Languages
 
4
 
 
5
static const PumaLangList pumaLangs[] = {
 
6
        {PUMA_LANG_ENGLISH,   "eng", "English"},
 
7
        {PUMA_LANG_GERMAN,    "ger", "German"},
 
8
        {PUMA_LANG_FRENCH,    "fra", "French"},
 
9
        {PUMA_LANG_RUSSIAN,   "rus", "Russian"},
 
10
        {PUMA_LANG_SWEDISH,   "swe", "Swedish"},
 
11
        {PUMA_LANG_SPANISH,   "spa", "Spanian"},
 
12
        {PUMA_LANG_ITALIAN,   "ita", "Italian"},
 
13
        {PUMA_LANG_RUSENG,    "ruseng", "Russian and English"},
 
14
        {PUMA_LANG_UKRAINIAN, "ukr", "Ukrainian"},
 
15
        {PUMA_LANG_SERBIAN,   "srp", "Serbian"},
 
16
        {PUMA_LANG_CROATIAN,  "hrv", "Croatian"},
 
17
        {PUMA_LANG_POLISH,    "pol", "Polish"},
 
18
        {PUMA_LANG_DANISH,    "dan", "Danish"},
 
19
        {PUMA_LANG_PORTUGUESE,"por", "Portuguese"},
 
20
        {PUMA_LANG_DUTCH,     "dut", "Dutich"},
 
21
        {PUMA_LANG_DIG,       "dig", "Digits only"},
 
22
//        {LANG_UZBEK,     "uzb"}, // These don't seem to have data files. Thus they are disabled.
 
23
//        {LANG_KAZ,       "kaz"},
 
24
//        {LANG_KAZ_ENG,   "kazeng"},
 
25
        {PUMA_LANG_CZECH,     "cze", "Czech"},
 
26
        {PUMA_LANG_ROMAN,     "rum", "Roman"},
 
27
        {PUMA_LANG_HUNGAR,    "hun", "Hungar"},
 
28
        {PUMA_LANG_BULGAR,    "bul", "Bulgar"},
 
29
        {PUMA_LANG_SLOVENIAN, "slv", "Slovenian"},
 
30
        {PUMA_LANG_LATVIAN,   "lav", "Latvian"},
 
31
        {PUMA_LANG_LITHUANIAN,"lit", "Lithuanian"},
 
32
        {PUMA_LANG_ESTONIAN,  "est", "Estonian"},
 
33
        {PUMA_LANG_TURKISH,   "tur", "Turkish"},
 
34
        {-1, NULL, NULL}
 
35
};
 
36
 
 
37
static const PumaFormatList pumaFormats[] = {
 
38
// Does not work.    {PUMA_TOTABLEDBF,   "dbf",       "DBF format"},
 
39
    {PUMA_TOHTML,       "html",      "HTML format"},
 
40
    {PUMA_TOHOCR,       "hocr",      "hOCR HTML format"},
 
41
//    {PUMA_TOEDNATIVE,   "native",    "Cuneiform 2000 format"},
 
42
//    {PUMA_TORTF,        "rtf",       "RTF format"},
 
43
    {PUMA_TOSMARTTEXT,  "smarttext", "Plain text with TeX paragraphs"},
 
44
    {PUMA_TOTEXT,       "text",      "Plain text"},
 
45
// Table code is missing. {PUMA_TOTABLETXT,   "tabletxt",  ""},
 
46
    {-1, NULL, NULL}
 
47
};
 
48
 
 
49
OcelotPage::OcelotPage(string fName, uint page){
 
50
    fileName = fName;
 
51
    pageNumber = page;
 
52
    dib = NULL;
 
53
}
 
54
 
 
55
OcelotPage::~OcelotPage(){
 
56
    delete[] dib;
 
57
    
 
58
}
 
59
    
 
60
bool OcelotPage::loadRaster(string density){
 
61
    
 
62
    delete[] dib;
 
63
 
 
64
    Magick::Image image;    
 
65
    
 
66
    image.density(density);
 
67
    image.read(textCode());
 
68
    
 
69
    
 
70
    if(applyFilterBSH){
 
71
        image.gaussianBlur(maskSize, 2);
 
72
        image.sharpen(maskSize);
 
73
    }
 
74
    
 
75
    if(applyFilterLeveler){
 
76
        double bp = 0;
 
77
        double wp = 65535;
 
78
            
 
79
        double nbp = (wp-bp)*(proportionFilterLeveler);
 
80
        double nwp = (wp-bp)*(1-proportionFilterLeveler);
 
81
        
 
82
        image.level(nbp,nwp);
 
83
    }
 
84
    
 
85
    Magick::Blob blob;
 
86
    
 
87
    if(image.type() != Magick::BilevelType) {
 
88
        if(image.totalColors() > 2)
 
89
            image.monochrome();
 
90
        image.type(Magick::BilevelType);
 
91
    }
 
92
    
 
93
    if(saveFiltredImage){
 
94
        image.write(imageDumpFilename);
 
95
    }
 
96
    
 
97
    image.write(&blob, "DIB");
 
98
    
 
99
    uint data_size = blob.length();
 
100
    dib = new char [data_size];
 
101
    memcpy(dib, blob.data(), data_size);
 
102
    
 
103
    return true;
 
104
}
 
105
 
 
106
char * OcelotPage::getDib(){
 
107
    return dib;
 
108
}
 
109
 
 
110
void OcelotPage::freeRaster(){
 
111
    delete[] dib;
 
112
    dib = NULL;
 
113
}
 
114
 
 
115
string OcelotPage::textCode(){
 
116
    return fileName + "["+to_string(pageNumber)+"]";
 
117
}
 
118
 
 
119
 
 
120
void OcelotPage::setFilterLeveler(int factor){
 
121
    applyFilterLeveler = true;
 
122
    proportionFilterLeveler = ((double) factor) / 100.0;
 
123
}
 
124
 
 
125
void OcelotPage::setFilterBSH(int size){
 
126
    applyFilterBSH = true;
 
127
    maskSize = (double) size;
 
128
}
 
129
 
 
130
void OcelotPage::setSaveRaster(string fileName){
 
131
    saveFiltredImage = true;
 
132
    imageDumpFilename = fileName;
 
133
}
 
134
 
 
135
 
 
136
OcelotBlock::OcelotBlock(POLY_ pumaBlock){
 
137
    block = pumaBlock;    
 
138
}
 
139
 
 
140
OcelotBlock::OcelotBlock(Handle type, uint x, uint y, uint w, uint h, uint tag){
 
141
 
 
142
    block.com.type = type;
 
143
    block.com.number = 0;
 
144
    block.com.Color = 0;
 
145
    block.com.count = 4;
 
146
    block.com.Vertex[0] = {x,y};
 
147
    block.com.Vertex[1] = {x+w,y};
 
148
    block.com.Vertex[2] = {x+w,y+h};
 
149
    block.com.Vertex[3] = {x,y+h};
 
150
    block.alphabet = 0;
 
151
    usernum = tag;
 
152
    
 
153
}
 
154
 
 
155
OcelotBlock::~OcelotBlock(){
 
156
};
 
157
    
 
158
uint OcelotBlock::x(){
 
159
    return block.com.Vertex[0].x;
 
160
}
 
161
 
 
162
uint OcelotBlock::y(){
 
163
    return block.com.Vertex[0].y;
 
164
}
 
165
 
 
166
uint OcelotBlock::w(){
 
167
    return block.com.Vertex[1].x - block.com.Vertex[0].x;
 
168
}
 
169
 
 
170
uint OcelotBlock::h(){
 
171
    return block.com.Vertex[3].y - block.com.Vertex[0].y;
 
172
}
 
173
 
 
174
Handle OcelotBlock::type(){
 
175
    return block.com.type;
 
176
}
 
177
 
 
178
string OcelotBlock::typeName(){
 
179
    return (string) CPAGE_GetNameInternalType(block.com.type);
 
180
}
 
181
 
 
182
POLY_ OcelotBlock::getBlock(){
 
183
    return block;
 
184
}
 
185
 
 
186
void OcelotBlock::setUserTag(uint n){
 
187
    usernum = n;    
 
188
}
 
189
 
 
190
uint OcelotBlock::getUserTag(){
 
191
    return usernum;
 
192
}
 
193
 
 
194
void OcelotBlock::setBlockNumber(uint n){
 
195
    block.com.number = n;
 
196
}
 
197
 
 
198
 
 
199
OcelotSymbol::OcelotSymbol(CSTR_rast rastr, uint tag) {
 
200
    usernum = tag;
 
201
    
 
202
    UniVersions     vers;
 
203
    CSTR_rast_attr  attr;
 
204
    unsigned char   buf[3] = {0, 0, 0};
 
205
 
 
206
    CSTR_GetAttr(rastr, &attr);
 
207
    
 
208
    flags = attr.flg;
 
209
    
 
210
    if(CSTR_GetCollectionUni(rastr, &vers)) {
 
211
        
 
212
        for(int i = 0;i<=vers.lnAltCnt;i++){
 
213
            string s (reinterpret_cast<const char*> (win1251_to_utf8 [*vers.Alt[i].Code]));
 
214
            vtext.push_back(s);
 
215
        }
 
216
    }
 
217
}
 
218
 
 
219
OcelotSymbol::~OcelotSymbol(){
 
220
}
 
221
        
 
222
bool OcelotSymbol::is(uint flag){
 
223
    return (flags & flag) > 0;
 
224
}
 
225
 
 
226
bool OcelotSymbol::isNot(uint flag){
 
227
    return !is(flag);
 
228
}
 
229
 
 
230
string OcelotSymbol::text(uint variant) {
 
231
    return vtext[0];
 
232
}
 
233
 
 
234
uint OcelotSymbol::getUserTag() {
 
235
    return usernum;
 
236
}
 
237
 
 
238
 
 
239
OcelotLine::OcelotLine(CSTR_line lin, uint tag){
 
240
    usernum = tag;
 
241
    
 
242
    CSTR_attr lattr;    
 
243
    CSTR_GetLineAttr(lin,&lattr);
 
244
    
 
245
    line_x = lattr.r_col;
 
246
    line_y = lattr.r_row;
 
247
    line_w = lattr.r_wid;
 
248
    line_h = lattr.r_hei;
 
249
    
 
250
    CSTR_rast start = CSTR_GetFirstRaster (lin),
 
251
              stop = CSTR_GetLastRaster (lin);
 
252
    
 
253
    CSTR_rast current = CSTR_GetNextRaster (start,CSTR_f_all);
 
254
    
 
255
    for(; current && current!=stop; current=CSTR_GetNextRaster (current,CSTR_f_all)){
 
256
         OcelotSymbol s(current, tag);
 
257
         symbols.push_back(s);
 
258
    }
 
259
}
 
260
 
 
261
OcelotLine::~OcelotLine(){
 
262
}
 
263
 
 
264
uint OcelotLine::x(){
 
265
    return line_x;
 
266
}
 
267
 
 
268
uint OcelotLine::y(){
 
269
    return line_y;
 
270
}
 
271
 
 
272
uint OcelotLine::w(){
 
273
    return line_w;
 
274
}
 
275
 
 
276
uint OcelotLine::h(){
 
277
    return line_h;
 
278
}
 
279
 
 
280
uint OcelotLine::getUserTag(){
 
281
    return usernum;
 
282
}
 
283
 
 
284
 
 
285
Ocelot::Ocelot() {
 
286
 
 
287
        pumaLanguage = PUMA_LANG_ENGLISH;
 
288
        pumaDataPath = "";
 
289
        pumaDotMatrix = false;
 
290
        pumaFax = false;
 
291
        pumaOneColumn = true;
 
292
 
 
293
        //setenv("MAGICK_DISK_LIMIT","200",0);
 
294
        Magick::InitializeMagick("");
 
295
        
 
296
}
 
297
 
 
298
Ocelot::~Ocelot(){
 
299
 
 
300
    if (pumaStarted)
 
301
        PUMA_XClose();
 
302
}
 
303
 
 
304
bool Ocelot::addPages(string fileName, bool multipage, int index){
 
305
    
 
306
//     list< Magick::Image> imageList; 
 
307
//     Magick::readImages( &imageList, fileName );
 
308
    
 
309
    for(int i = 0; ; i++){
 
310
        try {
 
311
        Magick::Image image;
 
312
        image.density("5");
 
313
        image.ping(fileName + "["+to_string(i)+"]"); 
 
314
 
 
315
        #ifdef _DEBUG        
 
316
        printf("found page %s\n", image.fileName().c_str());
 
317
        #endif
 
318
 
 
319
        OcelotPage op(fileName, i);
 
320
        if (index < 0 )
 
321
            pages.push_back(op);
 
322
        else
 
323
            pages.insert(pages.begin()+index, op); 
 
324
        
 
325
        } catch (Magick::WarningImage) {
 
326
            break;
 
327
        }        
 
328
    
 
329
        if (!multipage)
 
330
            break;
 
331
    }
 
332
    return true; // Check file exsist, format supported
 
333
}
 
334
 
 
335
uint Ocelot::pageCount(){
 
336
    return pages.size();    
 
337
}
 
338
     
 
339
bool Ocelot::deletePage(uint index){
 
340
    //pages.remove(index);
 
341
    return true; // Check page exsist
 
342
}
 
343
 
 
344
bool Ocelot::setCurrentPage(uint index){
 
345
    currentPage = index;
 
346
}
 
347
 
 
348
void Ocelot::startPuma(){
 
349
    setenv("CF_DATADIR", pumaDataPath.c_str(), 0);
 
350
 
 
351
    PUMA_Init(0, 0);
 
352
    
 
353
    PUMA_SetImportData(PUMA_Word32_Language, &pumaLanguage);
 
354
    PUMA_SetImportData(PUMA_Bool32_DotMatrix, &pumaDotMatrix);
 
355
    PUMA_SetImportData(PUMA_Bool32_Fax100, &pumaFax);
 
356
    PUMA_SetImportData(PUMA_Bool32_OneColumn, &pumaOneColumn);
 
357
    
 
358
    pumaStarted = true;
 
359
}
 
360
        
 
361
 
 
362
bool Ocelot::loadRaster(int index){
 
363
    if (index < 0)
 
364
        index = currentPage;
 
365
    return pages[index].loadRaster(imageDensity);
 
366
}
 
367
 
 
368
bool Ocelot::freeRaster(int index){
 
369
    if (index < 0)
 
370
        index = currentPage;
 
371
    pages[index].freeRaster();
 
372
}
 
373
 
 
374
 
 
375
bool Ocelot::layoutPage(int index){
 
376
    if (index < 0)
 
377
        index = currentPage;
 
378
    
 
379
    PUMA_XOpen(pages[index].getDib(), pages[index].textCode().c_str());
 
380
 
 
381
    PUMA_XPageAnalysis();
 
382
    
 
383
    return true;
 
384
}
 
385
 
 
386
bool Ocelot::recognizePage(int index){
 
387
    if (index < 0)
 
388
        index = currentPage;
 
389
    
 
390
    assert(index == currentPage);
 
391
    
 
392
    PUMA_XFinalRecognition();
 
393
    
 
394
    return true;
 
395
}
 
396
 
 
397
bool Ocelot::savePage(int index, int format){
 
398
    if (index < 0)
 
399
        index = currentPage;
 
400
    if (format < 0)    
 
401
        format = pumaFormat;
 
402
        
 
403
    assert(index == currentPage);
 
404
    
 
405
    if (currentPage == 0) {
 
406
        FILE* f = fopen(outputFileName.c_str(), "wb");
 
407
        
 
408
        if (format == PUMA_TOHTML || format == PUMA_TOHOCR) {
 
409
        
 
410
        string html_head =
 
411
        "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 "
 
412
        "Transitional//EN\""
 
413
        " \"http://www.w3.org/TR/html4/loose.dtd\">\n"
 
414
        "<html><head><title></title>"
 
415
        "<meta http-equiv=\"Content-Type\""
 
416
        " content=\"text/html;charset=utf-8\" >\n"
 
417
        "<meta name='ocr-system' content='openocr'></head>\n"
 
418
        "<meta name='ocr-capabilities' content='ocr_line ocr_page'></head>\n"
 
419
        "<body>";
 
420
    
 
421
        fwrite(html_head.c_str(), sizeof(char), html_head.size(), f);
 
422
        
 
423
        }
 
424
        
 
425
        fclose(f);
 
426
        
 
427
    }
 
428
    
 
429
    PUMA_XSave(outputFileName.c_str(), format, PUMA_CODE_UTF8, TRUE);
 
430
    
 
431
    if (currentPage == pageCount()-1) {
 
432
        string html_tail = "</body></html>\n";
 
433
        
 
434
        FILE* f = fopen(outputFileName.c_str(), "ab");
 
435
        fwrite(html_tail.c_str(), sizeof(char), html_tail.size(), f);
 
436
        fclose(f);
 
437
        
 
438
    }
 
439
    
 
440
    return true;
 
441
}
 
442
 
 
443
vector<OcelotBlock> Ocelot::getBlockInfo(int index){
 
444
    if (index < 0)
 
445
        index = currentPage;
 
446
    assert(index == currentPage);
 
447
    
 
448
    vector<OcelotBlock> blocks;
 
449
    
 
450
    Handle hPage = CPAGE_GetHandlePage(CPAGE_GetCurrentPage());
 
451
 
 
452
    Handle block = CPAGE_GetBlockFirst(hPage,0);
 
453
 
 
454
    while(block) {
 
455
        
 
456
        POLY_ blockData;
 
457
        
 
458
        CPAGE_GetBlockData(hPage,block,CPAGE_GetBlockType(hPage,block), &blockData, sizeof(POLY_));
 
459
        
 
460
        OcelotBlock xblock(blockData);
 
461
        xblock.setUserTag(CPAGE_GetBlockUserNum(hPage,block));
 
462
        blocks.push_back(xblock);
 
463
        block = CPAGE_GetBlockNext(hPage,block,0);
 
464
    }
 
465
    return blocks;
 
466
    
 
467
}
 
468
 
 
469
void Ocelot::setBlockInfo(vector<OcelotBlock> blks, int index){
 
470
    if (index < 0)
 
471
        index = currentPage;
 
472
    assert(index == currentPage);
 
473
    
 
474
    Handle hPage = CPAGE_GetHandlePage(CPAGE_GetCurrentPage());
 
475
    Handle block = CPAGE_GetBlockFirst(hPage,0);
 
476
    Handle nextblock;
 
477
 
 
478
    do {
 
479
        nextblock = CPAGE_GetBlockNext(hPage,block,0);
 
480
        CPAGE_DeleteBlock(hPage,block);
 
481
    } while (nextblock);
 
482
    
 
483
    int number = 0;
 
484
    
 
485
    for (auto i = blks.begin(); i<blks.end(); i++){
 
486
        i->setBlockNumber (number);
 
487
        POLY_ pol = i->getBlock();
 
488
        Handle nblk = CPAGE_CreateBlock(hPage, i->type(), 0, 0, &pol,sizeof(POLY_));
 
489
        CPAGE_SetBlockUserNum(hPage,nblk,i->getUserTag());
 
490
    }
 
491
}
 
492
 
 
493
vector<OcelotLine> Ocelot::getRecognizedLines(){
 
494
    vector<OcelotLine> ret;
 
495
    int count = CSTR_GetMaxNumber();
 
496
    vector<OcelotBlock> blks = getBlockInfo();
 
497
    
 
498
    for(int i=1;i<=count;i++) {
 
499
    
 
500
    CSTR_line lin = CSTR_GetLineHandle(i, 1);
 
501
    CSTR_attr lattr;    
 
502
    CSTR_GetLineAttr(lin,&lattr);
 
503
    
 
504
    uint userBlock = 0;
 
505
    
 
506
    for (auto i = blks.begin(); i<blks.end(); i++){
 
507
        if ( lattr.r_col >= i->x() &&
 
508
             lattr.r_row >= i->y() &&
 
509
             lattr.r_col <= i->x()+i->w() &&
 
510
             lattr.r_row <= i->y()+i->h() ) {
 
511
            userBlock = i->getUserTag();
 
512
            break;
 
513
        }
 
514
    }
 
515
    
 
516
    OcelotLine ocline (lin, userBlock);
 
517
    ret.push_back(ocline);
 
518
    }
 
519
    
 
520
    return ret;
 
521
}
 
522
 
 
523
bool Ocelot::setDataPath(string path){
 
524
    if (FILE *file = fopen((path+"/rec4cour.dat").c_str(), "r")) {
 
525
        fclose(file);
 
526
        pumaDataPath = path;
 
527
        return true;
 
528
    }
 
529
    
 
530
    return false;
 
531
}
 
532
     
 
533
bool Ocelot::setLanguage(string lang){
 
534
    for(int j=0; pumaLangs[j].puma_number >= 0; j++) {
 
535
        if(pumaLangs[j].name == lang) {
 
536
                    pumaLanguage = pumaLangs[j].puma_number;
 
537
                    return true;
 
538
                }
 
539
    }
 
540
    return false;
 
541
}
 
542
 
 
543
void Ocelot::setDotMatrixMode(bool set){
 
544
    pumaDotMatrix = set;
 
545
}
 
546
 
 
547
void Ocelot::setFaxMode(bool set){
 
548
    pumaFax = set;
 
549
}
 
550
 
 
551
void Ocelot::setOneColumn(bool set){
 
552
    pumaOneColumn = set;
 
553
}
 
554
 
 
555
void Ocelot::setDensity(string set){
 
556
    imageDensity = set;
 
557
}
 
558
 
 
559
void Ocelot::setOutputFileName(string name){
 
560
    outputFileName = name;
 
561
}
 
562
 
 
563
bool Ocelot::setOutputFormat(string format){
 
564
    for(int j=0; pumaFormats[j].puma_number >= 0; j++) {
 
565
        if(pumaFormats[j].name == format) {
 
566
                    pumaFormat = pumaFormats[j].puma_number;
 
567
                    return true;
 
568
                }
 
569
    }
 
570
    return false;
 
571
}
 
572
 
 
573
void Ocelot::filterLeveler(int factor, int index) {
 
574
    if (index < 0)
 
575
        index = currentPage;
 
576
    pages[index].setFilterLeveler(factor);
 
577
}
 
578
 
 
579
void Ocelot::filterBSH(int size, int index) {
 
580
    if (index < 0)
 
581
        index = currentPage;
 
582
    pages[index].setFilterBSH(size);
 
583
}
 
584
 
 
585
void Ocelot::filterSaveImage(string filename, int index) {
 
586
    if (index < 0)
 
587
        index = currentPage;
 
588
    pages[index].setSaveRaster(filename);
 
589
    
 
590
}