22 #include "config_auto.h"
25 #include "allheaders.h"
30 #define _(x) gettext(x)
70 #if defined(_WIN32) && !defined(VERSION)
103 osd_tesseract_(
NULL),
109 paragraph_models_(
NULL),
117 recognition_done_(false),
119 rect_left_(0), rect_top_(0), rect_width_(0), rect_height_(0),
120 image_width_(0), image_height_(0) {
166 IntParam *p = ParamUtils::FindParam<IntParam>(
168 if (p ==
NULL)
return false;
169 *value = (
inT32)(*p);
174 BoolParam *p = ParamUtils::FindParam<BoolParam>(
176 if (p ==
NULL)
return false;
177 *value = (
BOOL8)(*p);
182 StringParam *p = ParamUtils::FindParam<StringParam>(
188 DoubleParam *p = ParamUtils::FindParam<DoubleParam>(
190 if (p ==
NULL)
return false;
191 *value = (double)(*p);
217 bool set_only_non_debug_params) {
219 if (language ==
NULL) language =
"eng";
233 bool reset_classifier =
true;
235 reset_classifier =
false;
239 language,
oem, configs, configs_size, vars_vec, vars_values,
240 set_only_non_debug_params) != 0) {
285 for (
int i = 0; i < num_subs; ++i)
299 char fname[_MAX_FNAME];
300 WIN32_FIND_DATA data;
302 HANDLE handle = FindFirstFile(pattern.
string(), &data);
303 if (handle != INVALID_HANDLE_VALUE) {
304 for (; result; result = FindNextFile(handle, &data)) {
314 if (glob(pattern.
string(), 0,
NULL, &pglob) == 0) {
315 for (paths = pglob.gl_pathv; *paths !=
NULL; paths++) {
316 path = basename(*paths);
317 if ((dot = strchr(path,
'.'))) {
401 int width,
int height) {
407 int bits_per_pixel = bytes_per_pixel == 0 ? 1 : bytes_per_pixel * 8;
408 SetImage(imagedata, bytes_per_line * 8 / bits_per_pixel, height + top,
409 bytes_per_pixel, bytes_per_line);
436 int width,
int height,
437 int bytes_per_pixel,
int bytes_per_line) {
440 bytes_per_pixel, bytes_per_line);
447 tprintf(
"Please call SetImage before SetSourceResolution.\n");
549 Pixa** pixa,
int** blockids) {
557 int component_count = 0;
558 int left, top, right, bottom;
563 }
while (page_it->
Next(level));
565 Boxa* boxa = boxaCreate(component_count);
567 *pixa = pixaCreate(component_count);
568 if (blockids !=
NULL)
569 *blockids =
new int[component_count];
572 int component_index = 0;
577 Box* lbox = boxCreate(left, top, right - left, bottom - top);
578 boxaAddBox(boxa, lbox, L_INSERT);
581 pixaAddPix(*pixa, pix, L_INSERT);
582 pixaAddBox(*pixa, lbox, L_CLONE);
584 if (blockids !=
NULL) {
585 (*blockids)[component_index] = blockid;
591 }
while (page_it->
Next(level));
607 FILE *fp = fopen(filename,
"wb");
609 int width = pixGetWidth(pix);
610 int height = pixGetHeight(pix);
611 l_uint32* data = pixGetData(pix);
612 fprintf(fp,
"P5 %d %d 255\n", width, height);
613 for (
int y = 0; y < height; ++y, data += pixGetWpl(pix)) {
614 for (
int x = 0; x < width; ++x) {
615 uinT8 b = GET_DATA_BIT(data, x) ? 0 : 255;
616 fwrite(&b, 1, 1, fp);
629 Boxa* boxa_words, Pixa* pixa_words,
630 const FCOORD& reskew, Pix* page_pix,
632 int block_count = boxaGetCount(boxa_blocks);
633 ASSERT_HOST(block_count == pixaGetCount(pixa_blocks));
635 for (
int i = 0; i < block_count; ++i) {
636 Pix* pix = pixaGetPix(pixa_blocks, i, L_CLONE);
637 pixDisplayWrite(pix, 1);
639 int word_count = boxaGetCount(boxa_words);
640 ASSERT_HOST(word_count == pixaGetCount(pixa_words));
644 page_res_it.
forward(), ++pr_word) {
650 if (choice !=
NULL) {
654 filename +=
"unclassified";
655 snprintf(numbuf, 32,
"%03d", pr_word);
659 Pix* pix = pixaGetPix(pixa_words, pr_word, L_CLONE);
660 pixWrite(filename.
string(), pix, IFF_TIFF_G4);
729 #ifndef GRAPHICS_DISABLED
731 #endif // GRAPHICS_DISABLED
744 fclose(training_output_file);
761 tprintf(
"Please call SetImage before attempting recognition.");
777 while (page_res_it.
word() !=
NULL) {
781 page_res_it.
row()->
row, word_res);
804 const char* retry_config,
int timeout_millisec,
809 FILE* fp = fopen(filename,
"rb");
811 tprintf(
_(
"Image file %s cannot be opened!\n"), filename);
820 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
821 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
822 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
823 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" "
824 "lang=\"en\">\n <head>\n <title></title>\n"
825 " <meta http-equiv=\"Content-Type\" content=\"text/html; "
826 "charset=utf-8\" />\n"
827 " <meta name='ocr-system' content='tesseract " VERSION
"' />\n"
828 " <meta name='ocr-capabilities' content='ocr_page ocr_carea ocr_par"
829 " ocr_line ocrx_word'/>\n"
830 " </head>\n <body>\n";
838 for (; page < npages && (pix = pixReadTiff(filename, page)) !=
NULL;
840 if ((page >= 0) && (npages > 1))
841 tprintf(
_(
"Page %d of %d\n"), page + 1, npages);
845 success &=
ProcessPage(pix, page, filename, retry_config,
846 timeout_millisec, text_out);
854 pix = pixRead(filename);
856 success &=
ProcessPage(pix, 0, filename, retry_config,
857 timeout_millisec, text_out);
861 FILE* fimg = fopen(filename,
"rb");
863 tprintf(
_(
"File %s cannot be opened!\n"), filename);
866 tprintf(
_(
"Reading %s as a list of filenames...\n"), filename);
869 for (
int i = 0; i < page &&
870 fgets(pagename,
sizeof(pagename), fimg) !=
NULL;
872 while (fgets(pagename,
sizeof(pagename), fimg) !=
NULL) {
874 pix = pixRead(pagename);
876 tprintf(
_(
"Image file %s cannot be read!\n"), pagename);
880 tprintf(
_(
"Page %d : %s\n"), page, pagename);
881 success &=
ProcessPage(pix, page, pagename, retry_config,
882 timeout_millisec, text_out);
890 *text_out +=
" </body>\n</html>\n";
906 const char* retry_config,
int timeout_millisec,
911 if (timeout_millisec > 0) {
935 pixWrite(
"tessinput.tif", page_pix, IFF_TIFF_G4);
937 if (failed && retry_config !=
NULL && retry_config[0] !=
'\0') {
1029 char* result =
new char[text.
length() + 1];
1038 int left, top, right, bottom;
1039 it->
BoundingBox(level, &left, &top, &right, &bottom);
1060 int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1;
1061 int page_id = page_number + 1;
1068 hocr_str.
add_str_int(
" <div class='ocr_page' id='page_", page_id);
1069 hocr_str +=
"' title='image \"";
1087 hocr_str.
add_str_int(
" <div class='ocr_carea' id='block_", bcnt);
1089 AddBoxTohOCR(res_it,
RIL_BLOCK, &hocr_str);
1093 hocr_str.
add_str_int(
"\n <p class='ocr_par' dir='ltr' id='par_", pcnt);
1095 hocr_str.
add_str_int(
"\n <p class='ocr_par' dir='rtl' id='par_", pcnt);
1097 AddBoxTohOCR(res_it,
RIL_PARA, &hocr_str);
1100 hocr_str.
add_str_int(
"\n <span class='ocr_line' id='line_", lcnt);
1105 hocr_str.
add_str_int(
"<span class='ocrx_word' id='word_", wcnt);
1106 AddBoxTohOCR(res_it,
RIL_WORD, &hocr_str);
1107 const char *font_name;
1108 bool bold, italic, underlined, monospace, serif, smallcaps;
1109 int pointsize, font_id;
1111 &monospace, &serif, &smallcaps,
1112 &pointsize, &font_id);
1116 if (bold) hocr_str +=
"<strong>";
1117 if (italic) hocr_str +=
"<em>";
1120 if (grapheme && grapheme[0] != 0) {
1121 if (grapheme[1] == 0) {
1122 switch (grapheme[0]) {
1123 case '<': hocr_str +=
"<";
break;
1124 case '>': hocr_str +=
">";
break;
1125 case '&': hocr_str +=
"&";
break;
1126 case '"': hocr_str +=
""";
break;
1127 case '\'': hocr_str +=
"'";
break;
1128 default: hocr_str += grapheme;
1131 hocr_str += grapheme;
1137 if (italic) hocr_str +=
"</em>";
1138 if (bold) hocr_str +=
"</strong>";
1139 hocr_str +=
"</span> ";
1142 if (last_word_in_line) {
1143 hocr_str +=
"\n </span>";
1146 if (last_word_in_para) {
1147 hocr_str +=
"\n </p>\n";
1150 if (last_word_in_block) {
1151 hocr_str +=
" </div>\n";
1155 hocr_str +=
" </div>\n";
1157 char *ret =
new char[hocr_str.
length() + 1];
1158 strcpy(ret, hocr_str.
string());
1201 char* result =
new char[total_length];
1202 strcpy(result,
"\0");
1203 int output_length = 0;
1206 int left, top, right, bottom;
1211 for (
int i = 0; text[i] !=
'\0'; ++i) {
1215 snprintf(result + output_length, total_length - output_length,
1216 "%s %d %d %d %d %d\n",
1219 output_length += strlen(result + output_length);
1222 if (output_length + kMaxBytesPerLine > total_length)
1236 0x20ac, 0x201c, 0x201d, 0x2018, 0x2019, 0x2022, 0x2014, 0
1240 0x00a2, 0x0022, 0x0022, 0x0027, 0x0027, 0x00b7, 0x002d, 0
1252 bool tilde_crunch_written =
false;
1253 bool last_char_was_newline =
true;
1254 bool last_char_was_tilde =
false;
1258 char* result =
new char[total_length];
1266 (!tilde_crunch_written ||
1277 last_char_was_tilde =
false;
1279 if (!last_char_was_tilde) {
1281 last_char_was_tilde =
true;
1283 tilde_crunch_written =
true;
1284 last_char_was_newline =
false;
1289 tilde_crunch_written =
false;
1293 int length = lengths.
length();
1297 if (last_char_was_tilde &&
1298 word->
word->
space() == 0 && wordstr[offset] ==
' ') {
1302 offset = lengths[i++];
1304 if (i < length && wordstr[offset] != 0) {
1305 if (!last_char_was_newline)
1308 last_char_was_newline =
false;
1309 for (; i < length; offset += lengths[i++]) {
1310 if (wordstr[offset] ==
' ' ||
1313 last_char_was_tilde =
true;
1317 UNICHAR ch(wordstr + offset, lengths[i]);
1319 for (
int j = 0;
kUniChs[j] != 0; ++j) {
1325 if (uni_ch <= 0xff) {
1326 *ptr++ =
static_cast<char>(uni_ch);
1327 last_char_was_tilde =
false;
1330 last_char_was_tilde =
true;
1339 tilde_crunch_written =
false;
1340 last_char_was_newline =
true;
1341 last_char_was_tilde =
false;
1352 if (!conf)
return 0;
1355 while (*pt >= 0) sum += *pt++;
1356 if (pt != conf) sum /= pt - conf;
1371 int* conf =
new int[n_word+1];
1376 int w_conf =
static_cast<int>(100 + 5 * choice->
certainty());
1378 if (w_conf < 0) w_conf = 0;
1379 if (w_conf > 100) w_conf = 100;
1380 conf[n_word++] = w_conf;
1399 bool success =
true;
1405 tprintf(
"Trying to adapt \"%s\" to \"%s\"\n", text, wordstr);
1410 if (word_res !=
NULL) {
1418 for (t = 0; text[t] !=
'\0'; ++t) {
1419 if (text[t] ==
'\n' || text[t] ==
' ')
1421 while (wordstr[w] !=
'\0' && wordstr[w] ==
' ')
1423 if (text[t] != wordstr[w])
1427 if (text[t] !=
'\0' || wordstr[w] !=
'\0') {
1438 word_res = pr_it.
word();
1540 block_it.move_to_first();
1541 ROW_LIST* rows = block_it.data()->row_list();
1542 if (rows->length() < 1) {
1547 ROW_IT row_it(rows);
1548 row_it.move_to_first();
1549 ROW* row = row_it.data();
1552 *out_offset =
static_cast<int>(row->
base_line(0.0));
1574 for (
int i = 0; i < num_subs; ++i) {
1588 tprintf(
"Please call Init before attempting to send an image.");
1629 tprintf(
"Estimated resolution %d out of range! Corrected to %d\n",
1638 tprintf(
"Please call SetImage before attempting recognition.");
1654 tprintf(
"Image too large: (%d, %d)\n",
1682 tprintf(
"Warning: Auto orientation and script detection requested,"
1683 " but osd language failed to load\n");
1731 int total_length = 2;
1732 int total_blobs = 0;
1738 if (choice !=
NULL) {
1739 total_blobs += choice->
length() + 2;
1747 if (blob_count !=
NULL)
1748 *blob_count = total_blobs;
1749 return total_length;
1786 bool** vertical_writing) {
1787 delete[] *block_orientation;
1788 *block_orientation =
NULL;
1789 delete[] *vertical_writing;
1790 *vertical_writing =
NULL;
1793 block_it.move_to_first();
1795 for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) {
1796 if (!block_it.data()->poly_block()->IsText()) {
1802 tprintf(
"WARNING: Found no blocks\n");
1805 *block_orientation =
new int[num_blocks];
1806 *vertical_writing =
new bool[num_blocks];
1807 block_it.move_to_first();
1809 for (block_it.mark_cycle_pt(); !block_it.cycled_list();
1810 block_it.forward()) {
1811 if (!block_it.data()->poly_block()->IsText()) {
1814 FCOORD re_rotation = block_it.data()->re_rotation();
1815 float re_theta = re_rotation.
angle();
1816 FCOORD classify_rotation = block_it.data()->classify_rotation();
1817 float classify_theta = classify_rotation.
angle();
1818 double rot_theta = - (re_theta - classify_theta) * 2.0 /
PI;
1819 if (rot_theta < 0) rot_theta += 4;
1820 int num_rotations =
static_cast<int>(rot_theta + 0.5);
1821 (*block_orientation)[i] = num_rotations;
1824 (*vertical_writing)[i] = classify_rotation.
y() != 0.0f;
1854 inT32 xstarts[] = {-32000};
1855 double quad_coeffs[] = {0, 0, baseline};
1860 ascender - (baseline + xheight),
1861 descender - baseline,
1868 int width = pixGetWidth(pix);
1869 int height = pixGetHeight(pix);
1870 BLOCK block(
"a character",
TRUE, 0, 0, 0, 0, width, height);
1877 C_BLOB_IT c_blob_it(list);
1878 if (c_blob_it.empty())
1881 C_OUTLINE_IT ol_it(c_blob_it.data()->out_list());
1882 for (c_blob_it.forward();
1883 !c_blob_it.at_first();
1884 c_blob_it.forward()) {
1885 C_BLOB *c_blob = c_blob_it.data();
1886 ol_it.add_list_after(c_blob->
out_list());
1898 bool numeric_mode,
DENORM *denorm) {
1901 if (denorm !=
NULL) {
1917 float descender,
float ascender,
1918 bool numeric_mode, Pix* pix) {
1946 float best_rating = -100;
1950 BLOB_CHOICE_LIST choices;
1953 BLOB_CHOICE_IT choice_it;
1954 choice_it.set_to_list(&choices);
1955 for (choice_it.mark_cycle_pt(); !choice_it.cycled_list();
1956 choice_it.forward()) {
1957 if (choice_it.data()->rating() > best_rating) {
1958 best_rating = choice_it.data()->rating();
1959 best_class = choice_it.data()->unichar_id();
1981 pass1_result =
new PAGE_RES(block_list,
1984 return pass1_result;
1988 int debug_level = 0;
1996 result_it, &models);
2009 length = (len == -1 ? strlen(repr) : len);
2024 static
void add_space(TESS_CHAR_IT* it) {
2025 TESS_CHAR *t =
new TESS_CHAR(0,
" ");
2026 it->add_after_then_move(t);
2030 static float rating_to_cost(
float rating) {
2031 rating = 100 + rating;
2035 if (rating < 0) rating = 0;
2043 static void extract_result(TESS_CHAR_IT* out,
2047 while (page_res_it.word() !=
NULL) {
2055 int n = strlen(len);
2056 for (
int i = 0; i < n; i++) {
2060 out->add_after_then_move(tc);
2064 page_res_it.forward();
2081 TESS_CHAR_LIST tess_chars;
2082 TESS_CHAR_IT tess_chars_it(&tess_chars);
2083 extract_result(&tess_chars_it, page_res);
2084 tess_chars_it.move_to_first();
2085 int n = tess_chars.length();
2087 *lengths =
new int[n];
2088 *costs =
new float[n];
2094 for (tess_chars_it.mark_cycle_pt();
2095 !tess_chars_it.cycled_list();
2096 tess_chars_it.forward(), i++) {
2098 text_len += (*lengths)[i] = tc->
length;
2099 (*costs)[i] = tc->
cost;
2103 (*y1)[i] = tc->
box.
top();
2105 char *p = *text =
new char[text_len];
2107 tess_chars_it.move_to_first();
2108 for (tess_chars_it.mark_cycle_pt();
2109 !tess_chars_it.cycled_list();
2110 tess_chars_it.forward()) {
2122 int* FeatureOutlineIndex) {
2130 int_features, norm_array, norm_array, &len, FeatureOutlineIndex);
2131 delete [] norm_array;
2139 int left,
int top,
int right,
int bottom) {
2140 TBOX box(left, bottom, right, top);
2141 BLOCK_IT b_it(blocks);
2142 for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) {
2143 BLOCK* block = b_it.data();
2147 for (r_it.mark_cycle_pt(); !r_it.cycled_list(); r_it.forward()) {
2148 ROW* row = r_it.data();
2152 for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) {
2153 WERD* word = w_it.data();
2164 int num_max_matches,
2167 int* num_matches_returned) {
2168 BLOB_CHOICE_LIST* choices =
new BLOB_CHOICE_LIST;
2170 BLOB_CHOICE_IT choices_it(choices);
2171 int& index = *num_matches_returned;
2173 for (choices_it.mark_cycle_pt();
2174 !choices_it.cycled_list() && index < num_max_matches;
2175 choices_it.forward()) {
2178 ratings[index] = choice->
rating();
2181 *num_matches_returned = index;