10#include <tesseract/baseapi.h>
11#include <leptonica/allheaders.h>
18#include <system_error>
28 if (data.empty())
return nullptr;
29 Pix* p = pixReadMem(data.data(),
static_cast<size_t>(data.size()));
35 char* value =
nullptr;
36 size_t valueLength = 0;
37 if (_dupenv_s(&value, &valueLength, name) != 0 || value ==
nullptr) {
41 std::string result(value, valueLength > 0 ? valueLength - 1 : 0);
45 if (
const char* value = std::getenv(name)) {
46 return std::string(value);
55 std::array<wchar_t, MAX_PATH> buffer{};
56 const DWORD length = GetModuleFileNameW(
nullptr, buffer.data(),
static_cast<DWORD
>(buffer.size()));
57 if (length == 0 || length >= buffer.size()) {
61 return std::filesystem::path(buffer.data()).parent_path();
68 auto existsNoThrow = [](
const std::filesystem::path& p) {
70 return !p.empty() && std::filesystem::exists(p, ec) && !ec;
73 if (!provided.empty()) {
74 std::filesystem::path p(provided);
75 if (existsNoThrow(p))
return p.string();
79 if (!envTessdata.empty()) {
80 if (existsNoThrow(envTessdata))
return envTessdata;
83 std::vector<std::filesystem::path> candidates;
85 if (!exeDir.empty()) {
86 candidates.push_back(exeDir /
"res" /
"tessdata");
87 candidates.push_back(exeDir /
"tessdata");
88 candidates.push_back(exeDir.parent_path() /
"res" /
"tessdata");
89 candidates.push_back(exeDir.parent_path() /
"tessdata");
91 candidates.push_back(std::filesystem::current_path() /
"res" /
"tessdata");
92 candidates.push_back(std::filesystem::current_path() /
"tessdata");
93 candidates.push_back(std::filesystem::path(__FILE__).parent_path().parent_path() /
"res" /
"tessdata");
94 candidates.push_back(std::filesystem::path(__FILE__).parent_path().parent_path() /
"tessdata");
96 for (
const auto &c : candidates) {
97 if (existsNoThrow(c))
return c.string();
100 return std::string();
105 case ports::EngineMode::LegacyOnly:
106 return tesseract::OEM_TESSERACT_ONLY;
107 case ports::EngineMode::LstmOnly:
108 return tesseract::OEM_LSTM_ONLY;
109 case ports::EngineMode::LegacyAndLstm:
110 return tesseract::OEM_TESSERACT_LSTM_COMBINED;
111 case ports::EngineMode::Default:
113 return tesseract::OEM_DEFAULT;
118 return recognition.language.empty() ? std::string(
"deu") : recognition.language;
122 ocr.SetVariable(
"preserve_interword_spaces", recognition.preserveInterwordSpaces ?
"1" :
"0");
124 if (!recognition.charWhitelist.empty()) {
125 ocr.SetVariable(
"tessedit_char_whitelist", recognition.charWhitelist.c_str());
129static void applyPsm(tesseract::TessBaseAPI& ocr,
int psm) {
130 const int maxPsm =
static_cast<int>(tesseract::PSM_COUNT) - 1;
131 if (psm < 0 || psm > maxPsm) {
134 ocr.SetPageSegMode(
static_cast<tesseract::PageSegMode
>(psm));
138 const std::string& tessdataPath,
139 const ports::Settings& recognition,
140 std::shared_ptr<core::ports::diagnostics::IDiagnostics> dbg) {
142 tesseract::TessBaseAPI ocr;
145 if (!resolved.empty()) ocr.SetVariable(
"TESSDATA_PREFIX", resolved.c_str());
146 if (resolved.empty() || ocr.Init(resolved.c_str(), language.c_str(),
toTesseractOem(recognition.engineMode)) != 0) {
148 if (ocr.Init(
nullptr, language.c_str(),
toTesseractOem(recognition.engineMode)) != 0)
return out;
155 if (!pix) { ocr.End();
return out; }
158 char* txt = ocr.GetUTF8Text();
159 if (txt) { out.text = string(txt);
delete[] txt; }
160 out.meanConfidence = ocr.MeanTextConf();
161 if (dbg && dbg->enabled()) dbg->writeText(
string(
"tesseract/output/text.txt"), out.text);
162 ocr.End(); pixDestroy(&pix);
167 const std::string& tessdataPath,
168 const ports::Settings& recognition,
169 std::shared_ptr<core::ports::diagnostics::IDiagnostics> dbg) {
170 std::vector<ports::Word> out;
172 if (!pix)
return out;
173 tesseract::TessBaseAPI ocr;
176 if (!resolved.empty()) ocr.SetVariable(
"TESSDATA_PREFIX", resolved.c_str());
177 if (resolved.empty() || ocr.Init(resolved.c_str(), language.c_str(),
toTesseractOem(recognition.engineMode)) != 0) {
178 if (ocr.Init(
nullptr, language.c_str(),
toTesseractOem(recognition.engineMode)) != 0) { pixDestroy(&pix);
return out; }
188 char* tsv = ocr.GetTSVText(0);
189 if (!tsv) { ocr.End(); pixDestroy(&pix);
return out; }
191 if (dbg && dbg->enabled()) dbg->writeText(
string(
"tesseract/tsv/words.tsv"), s);
193 istringstream iss(s);
196 while (getline(iss, line)) {
197 if (first) { first =
false;
continue; }
198 if (line.empty())
continue;
201 istringstream ls(line);
202 while (getline(ls, cell,
'\t')) cols.push_back(cell);
203 if (cols.size() < 12)
continue;
205 try { level = stoi(cols[0]); }
catch (...) {
continue; }
206 if (level != 5)
continue;
207 int left = 0, top = 0, width = 0, height = 0, conf = 0;
209 left = stoi(cols[6]);
211 width = stoi(cols[8]);
212 height = stoi(cols[9]);
213 conf = stoi(cols[10]);
217 string text = cols[11];
221 w.bbox.width = width;
222 w.bbox.height = height;
225 out.push_back(std::move(w));
235 const std::vector<uint8_t>& data,
236 const std::string& tessdataPath,
237 const ports::Settings& recognition,
238 std::shared_ptr<core::ports::diagnostics::IDiagnostics> dbg) {
Declares the diagnostics artifact writing port.
static std::string resolveTessdataPath(const std::string &provided)
static std::string resolveLanguage(const ports::Settings &recognition)
static tesseract::OcrEngineMode toTesseractOem(ports::EngineMode mode)
static ports::Text recognizeTextFromBytes(const std::vector< uint8_t > &data, const std::string &tessdataPath, const ports::Settings &recognition, std::shared_ptr< core::ports::diagnostics::IDiagnostics > dbg)
static Pix * pixFromBytes(const std::vector< uint8_t > &data)
static std::string readEnvironmentVariable(const char *name)
static void applyPsm(tesseract::TessBaseAPI &ocr, int psm)
static std::filesystem::path executableDirectory()
static vector< ports::Word > getWordsFromBytes(const std::vector< uint8_t > &data, const std::string &tessdataPath, const ports::Settings &recognition, std::shared_ptr< core::ports::diagnostics::IDiagnostics > dbg)
static void configureForStatements(tesseract::TessBaseAPI &ocr, const ports::Settings &recognition)
Declares the Tesseract implementation helpers used by the import workflow.
Shared text recognition data types.
static std::pair< core::ports::text_recognition::Text, std::vector< core::ports::text_recognition::Word > > extractFromBytes(const std::vector< uint8_t > &data, const std::string &tessdataPath, const core::ports::text_recognition::Settings &recognition, std::shared_ptr< core::ports::diagnostics::IDiagnostics > debugger=nullptr)
Extracts recognized text and word-level OCR data from image bytes.
Precompiled header for the text-recognition infrastructure module.