21 #include "config_auto.h"
29 #include "allheaders.h"
55 int* max_x,
int* max_y) {
58 for (
int f = 0; f < features.
size(); ++f) {
59 if (features[f].x_ > *max_x) *max_x = features[f].x_;
60 if (features[f].y_ > *max_y) *max_y = features[f].y_;
67 #ifndef GRAPHICS_DISABLED
68 for (
int f = 0; f < features.
size(); ++f) {
69 FCOORD pos(features[f].x_, features[f].y_);
71 dir.from_direction(features[f].dir_);
99 for (
int i = 0; i < word_features.
size(); ++i) {
101 f.
x = word_features[i].x();
102 f.
y = word_features[i].y();
103 f.
dir = word_features[i].dir();
112 const auto* f1 = static_cast<const FloatWordFeature*>(v1);
113 const auto* f2 = static_cast<const FloatWordFeature*>(v2);
114 int x_diff = f1->x_bucket - f2->x_bucket;
115 if (x_diff == 0)
return f1->y - f2->y;
123 : page_number_(0), vertical_text_(vertical) {
132 const char* imagedata,
int imagedatasize,
133 const char* truth_text,
const char* box_text) {
140 memcpy(&
image_data->image_data_[0], imagedata, imagedatasize);
142 if (truth_text ==
nullptr || truth_text[0] ==
'\0') {
143 tprintf(
"Error: No text corresponding to page %d from image %s!\n",
153 }
else if (truth_text !=
nullptr && truth_text[0] !=
'\0' &&
163 if (!imagefilename_.
Serialize(fp))
return false;
164 if (!fp->
Serialize(&page_number_))
return false;
165 if (!image_data_.
Serialize(fp))
return false;
166 if (!language_.
Serialize(fp))
return false;
167 if (!transcription_.
Serialize(fp))
return false;
171 int8_t vertical = vertical_text_;
188 vertical_text_ = vertical != 0;
210 SetPixInternal(pix, &image_data_);
215 return GetPixInternal(image_data_);
225 int* scaled_width,
int* scaled_height,
228 int input_height = 0;
231 input_width = pixGetWidth(src_pix);
232 input_height = pixGetHeight(src_pix);
233 if (target_height == 0) {
234 target_height = std::min(input_height, max_height);
236 float im_factor = static_cast<float>(target_height) / input_height;
237 if (scaled_width !=
nullptr)
239 if (scaled_height !=
nullptr)
240 *scaled_height = target_height;
242 Pix* pix = pixScale(src_pix, im_factor, im_factor);
243 if (pix ==
nullptr) {
244 tprintf(
"Scaling pix of size %d, %d by factor %g made null pix!!\n",
245 input_width, input_height, im_factor);
247 if (scaled_width !=
nullptr) *scaled_width = pixGetWidth(pix);
248 if (scaled_height !=
nullptr) *scaled_height = pixGetHeight(pix);
249 pixDestroy(&src_pix);
250 if (
boxes !=
nullptr) {
253 for (
int b = 0; b < boxes_.
size(); ++b) {
254 TBOX box = boxes_[b];
255 box.
scale(im_factor);
260 TBOX box(0, 0, im_factor * input_width, target_height);
264 if (scale_factor !=
nullptr) *scale_factor = im_factor;
269 return image_data_.
size();
274 #ifndef GRAPHICS_DISABLED
275 const int kTextSize = 64;
278 if (pix ==
nullptr)
return;
279 int width = pixGetWidth(pix);
280 int height = pixGetHeight(pix);
281 auto* win =
new ScrollView(
"Imagedata", 100, 100,
282 2 * (width + 2 * kTextSize),
283 2 * (height + 4 * kTextSize),
284 width + 10, height + 3 * kTextSize,
true);
285 win->Image(pix, 0, height - 1);
290 int text_size = kTextSize;
291 if (!boxes_.
empty() && boxes_[0].height() * 2 < text_size)
292 text_size = boxes_[0].height() * 2;
293 win->TextAttributes(
"Arial", text_size,
false,
false,
false);
294 if (!boxes_.
empty()) {
295 for (
int b = 0; b < boxes_.
size(); ++b) {
297 win->Text(boxes_[b].left(), height + kTextSize, box_texts_[b].c_str());
302 win->Text(0, height + kTextSize * 2, transcription_.
c_str());
315 for (
int i = 0; i < box_pages.
size(); ++i) {
316 if (page_number_ >= 0 && box_pages[i] != page_number_)
continue;
317 transcription_ += texts[i];
330 ret = pixWriteMem(&data, &size, pix, IFF_PNG);
332 ret = pixWriteMem(&data, &size, pix, IFF_PNM);
346 reinterpret_cast<const unsigned char*>(&
image_data[0]);
360 true, &
boxes, &texts,
nullptr,
365 tprintf(
"Error: No boxes for page %d from image %s!\n",
366 page_number_, imagefilename_.
c_str());
373 : document_name_(name),
381 std::lock_guard<std::mutex> lock_p(pages_mutex_);
382 std::lock_guard<std::mutex> lock_g(general_mutex_);
390 pages_offset_ = start_page;
391 return ReCachePages();
397 std::lock_guard<std::mutex> lock_p(pages_mutex_);
398 std::lock_guard<std::mutex> lock(general_mutex_);
399 document_name_ = filename;
401 max_memory_ = max_memory;
407 std::lock_guard<std::mutex> lock(pages_mutex_);
410 if (!pages_.Serialize(&fp) || !fp.
CloseWrite(filename, writer)) {
411 tprintf(
"Serialize failed: %s\n", filename);
417 std::lock_guard<std::mutex> lock(pages_mutex_);
420 return pages_.Serialize(&fp);
425 std::lock_guard<std::mutex> lock(pages_mutex_);
426 pages_.push_back(page);
435 std::lock_guard<std::mutex> lock(pages_mutex_);
436 if (pages_offset_ == index)
return;
437 pages_offset_ = index;
439 std::thread t(&tesseract::DocumentData::ReCachePages,
this);
450 bool needs_loading = pages_offset_ != index;
451 pages_mutex_.unlock();
455 std::this_thread::yield();
464 std::lock_guard<std::mutex> lock(pages_mutex_);
466 if (num_pages == 0 || index < 0) {
471 index =
Modulo(index, num_pages);
472 if (pages_offset_ <= index && index < pages_offset_ + pages_.size()) {
473 *page = pages_[index - pages_offset_];
483 std::lock_guard<std::mutex> lock(pages_mutex_);
489 tprintf(
"Unloaded document %s, saving %" PRId64
" memory\n",
490 document_name_.
c_str(), memory_saved);
500 int num_pages = pages_.size();
502 for (
int i = 0; i < num_pages; ++i) {
503 int src = random.
IntRand() % num_pages;
505 std::swap(pages_[src], pages_[
dest]);
511 bool DocumentData::ReCachePages() {
512 std::lock_guard<std::mutex> lock(pages_mutex_);
516 int loaded_pages = 0;
519 if (!fp.
Open(document_name_, reader_) ||
522 tprintf(
"Deserialize header failed: %s\n", document_name_.
c_str());
525 pages_offset_ %= loaded_pages;
529 for (page = 0; page < loaded_pages; ++page) {
530 if (page < pages_offset_ ||
531 (max_memory_ > 0 &&
memory_used() > max_memory_)) {
533 tprintf(
"Deserializeskip failed\n");
537 if (!pages_.DeSerializeElement(&fp))
break;
538 ImageData* image_data = pages_.back();
539 if (image_data->imagefilename().length() == 0) {
540 image_data->set_imagefilename(document_name_);
541 image_data->set_page_number(page);
543 set_memory_used(
memory_used() + image_data->MemoryUsed());
546 if (page < loaded_pages) {
547 tprintf(
"Deserialize failed: %s read %d/%d lines\n",
548 document_name_.
c_str(), page, loaded_pages);
551 tprintf(
"Loaded %d/%d lines (%d-%d) of document %s\n", pages_.size(),
552 loaded_pages, pages_offset_ + 1, pages_offset_ + pages_.size(),
553 document_name_.
c_str());
555 set_total_pages(loaded_pages);
556 return !pages_.empty();
561 : num_pages_per_doc_(0), max_memory_(max_memory) {}
569 cache_strategy_ = cache_strategy;
570 int64_t fair_share_memory = 0;
575 fair_share_memory = max_memory_ / filenames.
size();
576 for (
int arg = 0; arg < filenames.
size(); ++arg) {
577 STRING filename = filenames[arg];
579 document->SetDocument(filename.
c_str(), fair_share_memory, reader);
582 if (!documents_.empty()) {
585 tprintf(
"Load of page 0 failed!\n");
592 documents_.push_back(data);
598 for (
int i = 0; i < documents_.size(); ++i) {
599 if (documents_[i]->document_name() == document_name)
600 return documents_[i];
611 if (num_pages_per_doc_ == 0) GetPageSequential(0);
612 return num_pages_per_doc_ * documents_.size();
615 int num_docs = documents_.size();
616 for (
int d = 0; d < num_docs; ++d) {
618 documents_[d]->GetPage(0);
619 total_pages += documents_[d]->NumPages();
627 const ImageData* DocumentCache::GetPageRoundRobin(
int serial) {
628 int num_docs = documents_.size();
629 int doc_index = serial % num_docs;
630 const ImageData* doc = documents_[doc_index]->GetPage(serial / num_docs);
631 for (
int offset = 1; offset <=
kMaxReadAhead && offset < num_docs; ++offset) {
632 doc_index = (serial + offset) % num_docs;
633 int page = (serial + offset) / num_docs;
634 documents_[doc_index]->LoadPageInBackground(page);
642 const ImageData* DocumentCache::GetPageSequential(
int serial) {
643 int num_docs = documents_.size();
645 if (num_pages_per_doc_ == 0) {
647 documents_[0]->GetPage(0);
648 num_pages_per_doc_ = documents_[0]->NumPages();
649 if (num_pages_per_doc_ == 0) {
650 tprintf(
"First document cannot be empty!!\n");
654 if (serial / num_pages_per_doc_ % num_docs > 0) documents_[0]->UnCache();
656 int doc_index = serial / num_pages_per_doc_ % num_docs;
657 const ImageData* doc =
658 documents_[doc_index]->GetPage(serial % num_pages_per_doc_);
661 int64_t total_memory = 0;
662 for (
int d = 0; d < num_docs; ++d) {
663 total_memory += documents_[d]->memory_used();
665 if (total_memory >= max_memory_) {
671 int num_in_front = CountNeighbourDocs(doc_index, 1);
672 for (
int offset = num_in_front - 2;
673 offset > 1 && total_memory >= max_memory_; --offset) {
674 int next_index = (doc_index + offset) % num_docs;
675 total_memory -= documents_[next_index]->UnCache();
680 int num_behind = CountNeighbourDocs(doc_index, -1);
681 for (
int offset = num_behind; offset < 0 && total_memory >= max_memory_;
683 int next_index = (doc_index + offset + num_docs) % num_docs;
684 total_memory -= documents_[next_index]->UnCache();
687 int next_index = (doc_index + 1) % num_docs;
688 if (!documents_[next_index]->IsCached() && total_memory < max_memory_) {
689 documents_[next_index]->LoadPageInBackground(0);
696 int DocumentCache::CountNeighbourDocs(
int index,
int dir) {
697 int num_docs = documents_.size();
698 for (
int offset = dir; abs(offset) < num_docs; offset += dir) {
699 int offset_index = (index + offset + num_docs) % num_docs;
700 if (!documents_[offset_index]->IsCached())
return offset - dir;