{ "cells": [ { "cell_type": "markdown", "id": "d603dd1d", "metadata": {}, "source": [ "# OneOCR — Wine Bridge Test na Linux (Colab)\n", "\n", "Test czy `oneocr.dll` działa na Linuxie przez Wine.\n", "\n", "**Problem znaleziony:** Ubuntu stock Wine nie wspiera `bcrypt AES-256-CFB` mode (potrzebne do deszyfrowania modelu). Rozwiązanie: instalujemy **Wine Staging** który ma pełne wsparcie bcrypt.\n", "\n", "**Kroki:**\n", "1. Instalacja Wine Staging + MinGW\n", "2. Clone repo + upload DLL\n", "3. Diagnostyka Wine (debug loader)\n", "4. Test OCR przez Wine\n", "\n", "**Potrzebne pliki** (wrzuć w komórce 4):\n", "- `oneocr.dll` (~40 MB)\n", "- `oneocr.onemodel` (~56 MB)\n", "- `onnxruntime.dll` (~13 MB)" ] }, { "cell_type": "code", "execution_count": null, "id": "2d700e20", "metadata": {}, "outputs": [], "source": [ "# 1. Install Wine STAGING + MinGW\n", "# Ubuntu stock wine64 nie wspiera bcrypt CFB mode - instalujemy Wine Staging\n", "import subprocess, os\n", "\n", "print(\"Installing Wine Staging (supports bcrypt CFB mode)...\")\n", "cmds = [\n", " 'dpkg --add-architecture i386',\n", " 'apt-get update -qq',\n", " 'apt-get install -y software-properties-common',\n", " 'mkdir -pm755 /etc/apt/keyrings',\n", " 'wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key',\n", " 'wget -NP /etc/apt/sources.list.d/ https://dl.winehq.org/wine-builds/ubuntu/dists/jammy/winehq-jammy.sources',\n", " 'apt-get update -qq',\n", " 'apt-get install -y --install-recommends winehq-staging mingw-w64',\n", "]\n", "\n", "for cmd in cmds:\n", " r = subprocess.run(cmd, shell=True, capture_output=True, text=True)\n", " if r.returncode != 0 and 'wget' not in cmd: # wget errors are OK (file exists)\n", " print(f\"ERROR: {cmd}\")\n", " print(r.stderr[:200])\n", "\n", "# Verify\n", "!wine --version\n", "!x86_64-w64-mingw32-gcc --version 2>&1 | head -1\n", "print(\"\\nOK - Wine Staging installed\")" ] }, { "cell_type": "code", "execution_count": null, "id": "f0e8cfb5", "metadata": {}, "outputs": [], "source": [ "# 2. Initialize Wine prefix\n", "import os\n", "os.environ['WINEDEBUG'] = '-all'\n", "os.environ['WINEPREFIX'] = '/root/.wine'\n", "os.environ['WINEARCH'] = 'win64'\n", "!wineboot --init 2>/dev/null\n", "print(\"Wine prefix OK\")" ] }, { "cell_type": "code", "execution_count": null, "id": "74d95c8f", "metadata": {}, "outputs": [], "source": [ "# 3. Clone repo\n", "!rm -rf /content/oneocr\n", "!git lfs install 2>/dev/null\n", "!git clone https://huggingface.co/MattyMroz/oneocr /content/oneocr\n", "!mkdir -p /content/oneocr/ocr_data\n", "!ls /content/oneocr/tools/*.c\n", "print(\"Repo OK\")" ] }, { "cell_type": "code", "execution_count": null, "id": "569afc38", "metadata": {}, "outputs": [], "source": [ "# 4. UPLOAD DLL FILES\n", "#\n", "# Kliknij \"Files\" po lewej w Colab -> Upload\n", "# Wrzuc: oneocr.dll, oneocr.onemodel, onnxruntime.dll\n", "# Potem uruchom te komorke\n", "#\n", "# Albo z Google Drive:\n", "# from google.colab import drive\n", "# drive.mount('/content/drive')\n", "# !cp /content/drive/MyDrive/path/{oneocr.dll,oneocr.onemodel,onnxruntime.dll} /content/oneocr/ocr_data/\n", "\n", "import shutil\n", "from pathlib import Path\n", "\n", "ocr_data = Path('/content/oneocr/ocr_data')\n", "needed = {'oneocr.dll': 40e6, 'oneocr.onemodel': 50e6, 'onnxruntime.dll': 10e6}\n", "\n", "for f, minsize in needed.items():\n", " dst = ocr_data / f\n", " # szukaj w /content/ (domyslny upload Colab)\n", " src = Path(f'/content/{f}')\n", " if src.exists() and not dst.exists():\n", " shutil.move(str(src), str(dst))\n", " if dst.exists():\n", " sz = dst.stat().st_size\n", " if sz > minsize:\n", " print(f' OK: {f} ({sz/1e6:.1f} MB)')\n", " elif sz < 1000:\n", " print(f' BLAD: {f} to git LFS pointer! Wrzuc prawdziwy plik.')\n", " else:\n", " print(f' UWAGA: {f} maly ({sz/1e6:.1f} MB)')\n", " else:\n", " print(f' BRAK: {f} - wrzuc plik!')\n", "\n", "ok = all((ocr_data / f).exists() and (ocr_data / f).stat().st_size > s for f, s in needed.items())\n", "print(f'\\n{\"Wszystkie pliki OK!\" if ok else \"BRAK PLIKOW - wrzuc i uruchom ponownie\"}')" ] }, { "cell_type": "code", "execution_count": null, "id": "f1a4b3c9", "metadata": {}, "outputs": [], "source": [ "# 5. Install Python deps\n", "!pip install -q pillow numpy onnxruntime" ] }, { "cell_type": "code", "execution_count": null, "id": "1a54ced1", "metadata": {}, "outputs": [], "source": [ "# 6. Compile C loaders (source written INLINE - no git dependency)\n", "import subprocess, os\n", "\n", "# ========== DEBUG LOADER SOURCE ==========\n", "DEBUG_C = r\"\"\"\n", "#include \n", "#include \n", "#include \n", "#include \n", "typedef void* BCRYPT_ALG_HANDLE;\n", "typedef void* BCRYPT_KEY_HANDLE;\n", "typedef long NTSTATUS;\n", "typedef NTSTATUS (*fn_Open)(BCRYPT_ALG_HANDLE*, const wchar_t*, const wchar_t*, unsigned long);\n", "typedef NTSTATUS (*fn_SetP)(BCRYPT_ALG_HANDLE, const wchar_t*, unsigned char*, unsigned long, unsigned long);\n", "typedef NTSTATUS (*fn_GenK)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long);\n", "typedef NTSTATUS (*fn_Dec)(BCRYPT_KEY_HANDLE, unsigned char*, unsigned long, void*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long*, unsigned long);\n", "typedef NTSTATUS (*fn_Close)(BCRYPT_ALG_HANDLE, unsigned long);\n", "typedef NTSTATUS (*fn_DestK)(BCRYPT_KEY_HANDLE);\n", "typedef long long (*fn_CrInit)(long long*);\n", "typedef long long (*fn_SetDL)(long long, char);\n", "typedef long long (*fn_CrPipe)(const char*, const char*, long long, long long*);\n", "typedef void (*fn_RelInit)(long long);\n", "typedef void (*fn_RelPipe)(long long);\n", "\n", "int main(int argc, char** argv) {\n", " if (argc < 2) { fprintf(stderr, \"Usage: %s [key_hex]\\n\", argv[0]); return 1; }\n", " const char* dd = argv[1];\n", " const char* kh = argc>2 ? argv[2] : \"6b6a29544774724b3e665d625b50696f772e67552b6e43407322222222222234\";\n", " char p[MAX_PATH];\n", "\n", " printf(\"=== TEST 1: File Access ===\\n\");\n", " const char* files[] = {\"oneocr.onemodel\", \"oneocr.dll\", \"onnxruntime.dll\", NULL};\n", " for (int i=0; files[i]; i++) {\n", " snprintf(p, sizeof(p), \"%s\\\\%s\", dd, files[i]);\n", " HANDLE h = CreateFileA(p, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\n", " if (h != INVALID_HANDLE_VALUE) {\n", " LARGE_INTEGER sz; GetFileSizeEx(h, &sz);\n", " printf(\" OK: %s (%.1f MB)\\n\", files[i], sz.QuadPart/1e6);\n", " if (sz.QuadPart < 1000000 && i==0) {\n", " char buf[200]={0}; DWORD r; ReadFile(h,buf,100,&r,NULL);\n", " if(strstr(buf,\"git-lfs\")) printf(\" *** GIT LFS POINTER! Not real file! ***\\n\");\n", " }\n", " CloseHandle(h);\n", " } else {\n", " printf(\" FAIL: %s (error %lu)\\n\", files[i], GetLastError());\n", " }\n", " }\n", "\n", " printf(\"\\n=== TEST 2: DLL Loading ===\\n\");\n", " SetDllDirectoryA(dd);\n", " snprintf(p, sizeof(p), \"%s\\\\onnxruntime.dll\", dd);\n", " HMODULE hort = LoadLibraryA(p);\n", " printf(\" onnxruntime.dll: %s\\n\", hort ? \"OK\" : \"FAIL\");\n", " snprintf(p, sizeof(p), \"%s\\\\oneocr.dll\", dd);\n", " HMODULE hmod = LoadLibraryA(p);\n", " printf(\" oneocr.dll: %s\\n\", hmod ? \"OK\" : \"FAIL\");\n", " if (hmod) {\n", " const char* ex[] = {\"CreateOcrInitOptions\",\"CreateOcrPipeline\",\"RunOcrPipeline\",\"ReleaseOcrResult\",\"ReleaseOcrPipeline\",NULL};\n", " for(int i=0;ex[i];i++) printf(\" %s: %s\\n\", ex[i], GetProcAddress(hmod,ex[i])?\"OK\":\"MISSING\");\n", " }\n", "\n", " printf(\"\\n=== TEST 3: bcrypt AES-256-CFB ===\\n\");\n", " HMODULE hbc = LoadLibraryA(\"bcrypt.dll\");\n", " if (!hbc) { printf(\" FAIL: bcrypt.dll not loaded\\n\"); }\n", " else {\n", " fn_Open pO=(fn_Open)GetProcAddress(hbc,\"BCryptOpenAlgorithmProvider\");\n", " fn_SetP pS=(fn_SetP)GetProcAddress(hbc,\"BCryptSetProperty\");\n", " fn_GenK pG=(fn_GenK)GetProcAddress(hbc,\"BCryptGenerateSymmetricKey\");\n", " fn_Dec pD=(fn_Dec)GetProcAddress(hbc,\"BCryptDecrypt\");\n", " fn_Close pC=(fn_Close)GetProcAddress(hbc,\"BCryptCloseAlgorithmProvider\");\n", " fn_DestK pDK=(fn_DestK)GetProcAddress(hbc,\"BCryptDestroyKey\");\n", " BCRYPT_ALG_HANDLE hA=NULL;\n", " NTSTATUS st=pO(&hA,L\"AES\",NULL,0);\n", " printf(\" OpenAlgorithm(AES): 0x%08lx %s\\n\",st,st==0?\"OK\":\"FAIL\");\n", " if(st==0){\n", " wchar_t cfb[]=L\"ChainingModeCFB\";\n", " st=pS(hA,L\"ChainingMode\",(unsigned char*)cfb,sizeof(cfb),0);\n", " printf(\" SetProperty(CFB): 0x%08lx %s\\n\",st,st==0?\"OK\":\"FAIL\");\n", " if(st!=0){\n", " printf(\" *** CFB NOT SUPPORTED! Trying others... ***\\n\");\n", " wchar_t cbc[]=L\"ChainingModeCBC\"; wchar_t ecb[]=L\"ChainingModeECB\"; wchar_t gcm[]=L\"ChainingModeGCM\";\n", " printf(\" CBC: 0x%08lx\\n\",pS(hA,L\"ChainingMode\",(unsigned char*)cbc,sizeof(cbc),0));\n", " printf(\" ECB: 0x%08lx\\n\",pS(hA,L\"ChainingMode\",(unsigned char*)ecb,sizeof(ecb),0));\n", " printf(\" GCM: 0x%08lx\\n\",pS(hA,L\"ChainingMode\",(unsigned char*)gcm,sizeof(gcm),0));\n", " }\n", " if(st==0){\n", " unsigned char tk[32]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32};\n", " BCRYPT_KEY_HANDLE hK=NULL; st=pG(hA,&hK,NULL,0,tk,32,0);\n", " printf(\" GenerateKey: 0x%08lx %s\\n\",st,st==0?\"OK\":\"FAIL\");\n", " if(st==0&&hK){\n", " unsigned char iv[16]={0},ct[16]={65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80},pt[16]={0};\n", " unsigned long cb=0; st=pD(hK,ct,16,NULL,iv,16,pt,16,&cb,0);\n", " printf(\" Decrypt: 0x%08lx %s (%lu bytes)\\n\",st,st==0?\"OK\":\"FAIL\",cb);\n", " pDK(hK);\n", " }\n", " }\n", " pC(hA,0);\n", " }\n", " FreeLibrary(hbc);\n", " }\n", "\n", " printf(\"\\n=== TEST 4: CreateOcrPipeline ===\\n\");\n", " if(!hmod){\n", " SetDllDirectoryA(dd);\n", " snprintf(p,sizeof(p),\"%s\\\\oneocr.dll\",dd);\n", " hmod=LoadLibraryA(p);\n", " }\n", " if(!hmod){printf(\" SKIP: DLL not loaded\\n\");}\n", " else{\n", " fn_CrInit pCI=(fn_CrInit)GetProcAddress(hmod,\"CreateOcrInitOptions\");\n", " fn_SetDL pSD=(fn_SetDL)GetProcAddress(hmod,\"OcrInitOptionsSetUseModelDelayLoad\");\n", " fn_CrPipe pCP=(fn_CrPipe)GetProcAddress(hmod,\"CreateOcrPipeline\");\n", " fn_RelInit pRI=(fn_RelInit)GetProcAddress(hmod,\"ReleaseOcrInitOptions\");\n", " fn_RelPipe pRP=(fn_RelPipe)GetProcAddress(hmod,\"ReleaseOcrPipeline\");\n", " if(!pCI||!pCP){printf(\" FAIL: Missing functions\\n\");}\n", " else{\n", " long long io=0,r2=pCI(&io);\n", " printf(\" CreateOcrInitOptions: %lld %s\\n\",r2,r2==0?\"OK\":\"FAIL\");\n", " if(pSD){r2=pSD(io,1);printf(\" SetDelayLoad(1): %lld %s\\n\",r2,r2==0?\"OK\":\"FAIL\");}\n", " snprintf(p,sizeof(p),\"%s\\\\oneocr.onemodel\",dd);\n", " int kl=(int)strlen(kh)/2; char key[64]={0};\n", " for(int i=0;if]b[Piow.gU+nC@s\\x22\\x22\\x22\\x22\\x22\\x224'\n", "key_hex = key.hex()\n", "\n", "result = subprocess.run(\n", " ['wine', '/tmp/oneocr_loader.exe',\n", " 'Z:\\\\content\\\\oneocr\\\\ocr_data', 'Z:\\\\tmp\\\\test.bmp', key_hex],\n", " capture_output=True, text=True, timeout=120,\n", " env={**os.environ, 'WINEDEBUG': '-all'}\n", ")\n", "\n", "print(f'Return code: {result.returncode}')\n", "if result.returncode == 0 and result.stdout.strip():\n", " data = json.loads(result.stdout.strip())\n", " print(f'\\nSUCCESS!')\n", " for line in data['lines']:\n", " words = ' | '.join(f\"{w['text']} ({w['confidence']:.0%})\" for w in line['words'])\n", " print(f' {words}')\n", " print(f'Total lines: {len(data[\"lines\"])}')\n", "else:\n", " print('FAILED')\n", " if result.stderr: print(f'Stderr: {result.stderr[:500]}')\n", " if result.stdout: print(f'Stdout: {result.stdout[:500]}')" ] }, { "cell_type": "code", "execution_count": null, "id": "f09f7fde", "metadata": {}, "outputs": [], "source": [ "# 9. FULL TEST: All 19 images\n", "import time\n", "\n", "test_dir = Path('/content/oneocr/working_space/input')\n", "images = sorted(test_dir.glob('*.png'))\n", "print(f'Testing {len(images)} images...\\n')\n", "\n", "ok = 0\n", "fail = 0\n", "for img_path in images:\n", " try:\n", " img = Image.open(img_path).convert('RGBA')\n", " img.save(bmp_path, format='BMP')\n", " t0 = time.time()\n", " r = subprocess.run(\n", " ['wine', '/tmp/oneocr_loader.exe',\n", " 'Z:\\\\content\\\\oneocr\\\\ocr_data', 'Z:\\\\tmp\\\\test.bmp', key_hex],\n", " capture_output=True, text=True, timeout=120,\n", " env={**os.environ, 'WINEDEBUG': '-all'}\n", " )\n", " dt = time.time() - t0\n", " if r.returncode == 0 and r.stdout.strip():\n", " data = json.loads(r.stdout.strip())\n", " txt = ' | '.join(l['text'] for l in data['lines'][:3])\n", " print(f' OK {img_path.name:25s} | {dt:.1f}s | {len(data[\"lines\"])}L | {txt[:60]}')\n", " ok += 1\n", " else:\n", " print(f' FAIL {img_path.name:25s} | {r.stderr[:80]}')\n", " fail += 1\n", " except Exception as e:\n", " print(f' FAIL {img_path.name:25s} | {e}')\n", " fail += 1\n", "\n", "print(f'\\n{\"=\"*60}')\n", "print(f'Result: {ok}/{ok+fail} ({ok/(ok+fail)*100:.0f}%)')\n", "if fail == 0:\n", " print('Wine bridge DZIALA! 100% taki sam wynik jak DLL na Windows.')" ] }, { "cell_type": "code", "execution_count": null, "id": "8abf6a75", "metadata": {}, "outputs": [], "source": [ "# 10. Unified engine test\n", "import sys\n", "sys.path.insert(0, '/content/oneocr')\n", "from ocr.engine_unified import OcrEngineUnified\n", "\n", "engine = OcrEngineUnified()\n", "print(f'Backend: {engine.backend_name}')\n", "\n", "img = Image.open('/content/oneocr/working_space/input/ocr_test (10).png')\n", "result = engine.recognize_pil(img)\n", "print(f'Text: {result.text}')\n", "print(f'Lines: {len(result.lines)}')\n", "print(f'Confidence: {result.average_confidence:.1%}')" ] } ], "metadata": { "language_info": { "name": "python" } }, "nbformat": 4, "nbformat_minor": 5 }