diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6bee9b535..1dff7a97c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -81,6 +81,14 @@ jobs: - name: Copy files to directory for installer run: mkdir installer; cp ./x64/Release-Full/ccextractorwinfull.exe ./installer; cp ./x64/Release-Full/*.dll ./installer working-directory: ./windows + - name: Download tessdata for OCR support + run: | + mkdir -p ./installer/tessdata + # Download English traineddata from tessdata_fast (smaller, faster, good for most use cases) + Invoke-WebRequest -Uri "https://github.com/tesseract-ocr/tessdata_fast/raw/main/eng.traineddata" -OutFile "./installer/tessdata/eng.traineddata" + # Download OSD (Orientation and Script Detection) for automatic script detection + Invoke-WebRequest -Uri "https://github.com/tesseract-ocr/tessdata_fast/raw/main/osd.traineddata" -OutFile "./installer/tessdata/osd.traineddata" + working-directory: ./windows - name: install WiX run: dotnet tool uninstall --global wix; dotnet tool install --global wix --version 6.0.2 && wix extension add -g WixToolset.UI.wixext/6.0.2 - name: Make sure WiX works diff --git a/src/lib_ccx/ocr.c b/src/lib_ccx/ocr.c index 028aeb59f..3bbfbc54a 100644 --- a/src/lib_ccx/ocr.c +++ b/src/lib_ccx/ocr.c @@ -8,6 +8,11 @@ #include #include "ccx_encoders_helpers.h" #include "ccx_encoders_spupng.h" +#ifdef _WIN32 +#include +#elif defined(__APPLE__) +#include +#endif #include "ocr.h" struct ocrCtx @@ -100,6 +105,68 @@ void delete_ocr(void **arg) freep(arg); } +/** + * get_executable_directory + * + * Returns the directory containing the executable. + * Returns a pointer to a static buffer, or NULL on failure. + */ +static const char *get_executable_directory(void) +{ + static char exe_dir[1024] = {0}; + static int initialized = 0; + + if (initialized) + return exe_dir[0] ? exe_dir : NULL; + + initialized = 1; + +#ifdef _WIN32 + char exe_path[MAX_PATH]; + DWORD len = GetModuleFileNameA(NULL, exe_path, MAX_PATH); + if (len == 0 || len >= MAX_PATH) + return NULL; + + // Find the last backslash and truncate there + char *last_sep = strrchr(exe_path, '\\'); + if (last_sep) + { + *last_sep = '\0'; + strncpy(exe_dir, exe_path, sizeof(exe_dir) - 1); + exe_dir[sizeof(exe_dir) - 1] = '\0'; + } +#elif defined(__linux__) + char exe_path[1024]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len <= 0) + return NULL; + exe_path[len] = '\0'; + + char *last_sep = strrchr(exe_path, '/'); + if (last_sep) + { + *last_sep = '\0'; + strncpy(exe_dir, exe_path, sizeof(exe_dir) - 1); + exe_dir[sizeof(exe_dir) - 1] = '\0'; + } +#elif defined(__APPLE__) + char exe_path[1024]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) != 0) + return NULL; + + char *last_sep = strrchr(exe_path, '/'); + if (last_sep) + { + *last_sep = '\0'; + strncpy(exe_dir, exe_path, sizeof(exe_dir) - 1); + exe_dir[sizeof(exe_dir) - 1] = '\0'; + } +#endif + + return exe_dir[0] ? exe_dir : NULL; +} + /** * probe_tessdata_location * @@ -107,8 +174,10 @@ void delete_ocr(void **arg) * * Priority of Tesseract traineddata file search paths:- * 1. tessdata in TESSDATA_PREFIX, if it is specified. Overrides others - * 2. tessdata in current working directory - * 3. tessdata in /usr/share + * 2. tessdata in executable directory (for bundled tessdata) + * 3. tessdata in current working directory + * 4. tessdata in system locations (/usr/share, etc.) + * 5. tessdata in default Tesseract install location (Windows) */ char *probe_tessdata_location(const char *lang) { @@ -116,6 +185,7 @@ char *probe_tessdata_location(const char *lang) const char *paths[] = { getenv("TESSDATA_PREFIX"), + get_executable_directory(), "./", "/usr/share/", "/usr/local/share/", diff --git a/windows/installer.wxs b/windows/installer.wxs index d322361d3..b4f9b72ef 100644 --- a/windows/installer.wxs +++ b/windows/installer.wxs @@ -4,6 +4,7 @@ + @@ -40,6 +41,7 @@ + @@ -194,6 +196,15 @@ + + + + + + + + +