diff --git a/environment.yml b/environment.yml index 4adfa26..974f60a 100644 --- a/environment.yml +++ b/environment.yml @@ -5,8 +5,9 @@ dependencies: - python=3.10 - pywin32 - pip - - leptonica=1.78.0 # pinned: tesserocr wheel links against leptonica-1.78.0.dll - - tesseract=5.1.0 + - tesserocr # conda-forge build — compiled against conda-forge tesseract/leptonica, + # so all DLL deps are resolved automatically within the env + - tesseract # version chosen by conda to match tesserocr - pkg-config - rapidfuzz=2.15.1 - pip: @@ -31,7 +32,6 @@ dependencies: - pillow - discord.py - parse - - dependencies/tesserocr-2.5.2-cp310-cp310-win_amd64.whl - typing_extensions - colorama - - dataclasses-json \ No newline at end of file + - dataclasses-json diff --git a/install.bat b/install.bat index 483918f..f73e2ac 100644 --- a/install.bat +++ b/install.bat @@ -91,10 +91,10 @@ exit /b 1 :env_created echo Botty Python: %PYTHON% -:: --- Force-reinstall the tesserocr wheel so the correct binary is always used --- +:: --- Remove old pip-installed tesserocr wheel if present (replaced by conda-forge package) --- echo. -echo Installing tesserocr wheel... -"%PYTHON%" -m pip install --force-reinstall "%~dp0dependencies\tesserocr-2.5.2-cp310-cp310-win_amd64.whl" >nul 2>&1 +echo Removing old pip-installed tesserocr if present... +"%PYTHON%" -m pip uninstall tesserocr -y >nul 2>&1 :: --- Smoke test via conda run (activates the full env like "conda activate botty") --- :: This is the only reliable way to ensure all DLL transitive deps are resolved. diff --git a/src/d2r_image/ocr.py b/src/d2r_image/ocr.py index 237a38e..885d06d 100644 --- a/src/d2r_image/ocr.py +++ b/src/d2r_image/ocr.py @@ -1,27 +1,15 @@ import os import sys if os.name == 'nt': - import ctypes - _dll_dirs = [d for d in [ + # Register conda DLL dirs so Python's .pyd loader (LOAD_LIBRARY_SEARCH_USER_DIRS) + # can find tesserocr's dependencies (tesseract, leptonica, etc.) + for _d in [ os.path.join(sys.prefix, 'Library', 'bin'), os.path.join(sys.prefix, 'Library', 'mingw-w64', 'bin'), os.path.join(sys.prefix, 'Library', 'usr', 'bin'), - ] if os.path.isdir(d)] - # Register dirs for Python's .pyd loader - for _d in _dll_dirs: - os.add_dll_directory(_d) - # Preload tesseract51.dll via LoadLibraryExW with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS. - # Unlike ctypes.WinDLL/LoadLibraryW, this flag propagates to the ENTIRE - # transitive dep chain (leptonica, mingw runtimes, etc.), resolving them - # all via the user DLL dirs registered above. - _LoadLibEx = ctypes.windll.kernel32.LoadLibraryExW - _LoadLibEx.restype = ctypes.c_void_p - _LoadLibEx.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_ulong] - for _d in _dll_dirs: - _tess = os.path.join(_d, 'tesseract51.dll') - if os.path.isfile(_tess): - _LoadLibEx(_tess, None, 0x1000) # LOAD_LIBRARY_SEARCH_DEFAULT_DIRS - break + ]: + if os.path.isdir(_d): + os.add_dll_directory(_d) from tesserocr import PyTessBaseAPI, OEM import numpy as np import cv2 diff --git a/src/main.py b/src/main.py index 117aca2..a62c2fe 100644 --- a/src/main.py +++ b/src/main.py @@ -1,26 +1,14 @@ -# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs -# that tesserocr depends on (tesseract51.dll, leptonica-1.78.0.dll). -# This must run BEFORE any import that might trigger tesserocr loading. +# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs. +# Must run BEFORE any import that might trigger tesserocr loading. import os, sys if sys.platform == "win32": - import ctypes - _dll_dirs = [d for d in [ + for _d in [ os.path.join(sys.prefix, "Library", "bin"), os.path.join(sys.prefix, "Library", "mingw-w64", "bin"), os.path.join(sys.prefix, "Library", "usr", "bin"), - ] if os.path.isdir(d)] - for _d in _dll_dirs: - os.add_dll_directory(_d) - # Preload tesseract51.dll via LoadLibraryExW with LOAD_LIBRARY_SEARCH_DEFAULT_DIRS - # (0x1000) so transitive deps are resolved via user DLL dirs, not just PATH. - _LoadLibEx = ctypes.windll.kernel32.LoadLibraryExW - _LoadLibEx.restype = ctypes.c_void_p - _LoadLibEx.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_ulong] - for _d in _dll_dirs: - _tess = os.path.join(_d, "tesseract51.dll") - if os.path.isfile(_tess): - _LoadLibEx(_tess, None, 0x1000) - break + ]: + if os.path.isdir(_d): + os.add_dll_directory(_d) from dataclasses import dataclass from input_layer import keyboard diff --git a/src/shopper.py b/src/shopper.py index 4e484c9..8999b4d 100644 --- a/src/shopper.py +++ b/src/shopper.py @@ -1,23 +1,13 @@ -# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs -# that tesserocr depends on (tesseract51.dll, leptonica-1.78.0.dll). +# Fix: On Windows, Python 3.8+ requires os.add_dll_directory for conda-forge DLLs. import os, sys if sys.platform == "win32": - import ctypes - _dll_dirs = [d for d in [ + for _d in [ os.path.join(sys.prefix, "Library", "bin"), os.path.join(sys.prefix, "Library", "mingw-w64", "bin"), os.path.join(sys.prefix, "Library", "usr", "bin"), - ] if os.path.isdir(d)] - for _d in _dll_dirs: - os.add_dll_directory(_d) - _LoadLibEx = ctypes.windll.kernel32.LoadLibraryExW - _LoadLibEx.restype = ctypes.c_void_p - _LoadLibEx.argtypes = [ctypes.c_wchar_p, ctypes.c_void_p, ctypes.c_ulong] - for _d in _dll_dirs: - _tess = os.path.join(_d, "tesseract51.dll") - if os.path.isfile(_tess): - _LoadLibEx(_tess, None, 0x1000) - break + ]: + if os.path.isdir(_d): + os.add_dll_directory(_d) from beautifultable import BeautifulTable import logging