commit 330b79288b81e0b9badc6630e252e7cd85e15f69 Author: Sivarius Date: Fri Jul 3 16:59:26 2026 +0800 Initial: Tesseract Web GUI with Flask + start.bat diff --git a/README.md b/README.md new file mode 100644 index 0000000..db0849c --- /dev/null +++ b/README.md @@ -0,0 +1,59 @@ +# Tesseract Web GUI + +Простой локальный веб-сервис для OCR через Tesseract. + +## Структура + +``` +tesseract-webgui/ +├── app.py # Flask сервер +├── start.bat # Запуск на Windows +├── templates/ +│ └── index.html # Веб-интерфейс +└── uploads/ # Сюда сохраняются загруженные и обработанные картинки +``` + +## Запуск + +```bash +start.bat +``` + +Или вручную: + +```bash +cd tesseract-webgui +python -m pip install flask pillow pytesseract +python app.py +``` + +Затем открывай в браузере: **http://127.0.0.1:5000/** + +## Возможности + +- Загрузка картинки drag-&-drop или через кнопку +- Настройка языка (`rus+eng`, `eng`, и т.д.) +- PSM режимы (авто, блок текста, одна строка и др.) +- Предобработка: увеличение, контраст, резкость, бинаризация +- Whitelist символов +- Предпросмотр загруженной картинки +- Сохранение всех параметров OCR в выводе + +## Требования + +- Python 3.10+ +- Tesseract OCR (должен быть в `C:\Program Files\Tesseract-OCR\tesseract.exe`) +- Русский языковой пакет: `rus.traineddata` в `C:\Program Files\Tesseract-OCR\tessdata\` + +## Установка Tesseract + +```bash +winget install UB-Mannheim.TesseractOCR +``` + +Русский язык (если не установился): + +```bash +curl -L -o "%TEMP%\rus.traineddata" "https://github.com/tesseract-ocr/tessdata/raw/main/rus.traineddata" +copy "%TEMP%\rus.traineddata" "C:\Program Files\Tesseract-OCR\tessdata\" +``` diff --git a/app.py b/app.py new file mode 100644 index 0000000..65380ec --- /dev/null +++ b/app.py @@ -0,0 +1,148 @@ +""" +Tesseract Web GUI +Локальный веб-сервис для распознавания текста с картинок. +Запуск: start.bat +""" + +import os +import io +import uuid +import base64 +from pathlib import Path +from datetime import datetime + +from PIL import Image, ImageEnhance, ImageFilter, ImageOps +import pytesseract +from flask import Flask, render_template, request, jsonify, send_from_directory +from werkzeug.utils import secure_filename + +# ── Конфиг ───────────────────────────────────────────────────────────── +BASE_DIR = Path(__file__).resolve().parent +UPLOAD_DIR = BASE_DIR / "uploads" +UPLOAD_DIR.mkdir(exist_ok=True) + +# Путь к Tesseract (Windows) +TESSERACT_CMD = r"C:\Program Files\Tesseract-OCR\tesseract.exe" +if Path(TESSERACT_CMD).exists(): + pytesseract.pytesseract.tesseract_cmd = TESSERACT_CMD + +ALLOWED_EXTENSIONS = {"png", "jpg", "jpeg", "bmp", "tiff", "webp", "gif"} + +app = Flask(__name__) +app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 # 16 MB + +# ── Хелперы ──────────────────────────────────────────────────────────── + +def allowed_file(filename: str) -> bool: + return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS + + +def preprocess_image(img: Image.Image, scale: int, contrast: float, sharpen: bool, binary: bool, binary_thresh: int) -> Image.Image: + """Предобработка перед OCR.""" + if scale > 1: + w, h = img.size + img = img.resize((w * scale, h * scale), Image.LANCZOS) + + img = img.convert("L") + + if contrast != 1.0: + img = ImageEnhance.Contrast(img).enhance(contrast) + + if sharpen: + img = img.filter(ImageFilter.SHARPEN) + + if binary: + img = img.point(lambda x: 0 if x < binary_thresh else 255) + + return img + + +def do_ocr(image_path: Path, lang: str, psm: int, + scale: int, contrast: float, sharpen: bool, + binary: bool, binary_thresh: int, + whitelist: str = "") -> dict: + """Выполняет OCR и возвращает словарь с результатом.""" + img = Image.open(image_path) + + # Для preview сохраняем оригинал как base64 + buf = io.BytesIO() + img.convert("RGB").save(buf, format="PNG") + preview_b64 = base64.b64encode(buf.getvalue()).decode("utf-8") + + # Предобработка + proc = preprocess_image(img, scale, contrast, sharpen, binary, binary_thresh) + + config = f"--psm {psm}" + if whitelist: + config += f' -c tessedit_char_whitelist="{whitelist}"' + + text = pytesseract.image_to_string(proc, lang=lang, config=config) + + # Сохраняем обработанную картинку + proc_id = uuid.uuid4().hex[:8] + proc_path = UPLOAD_DIR / f"proc_{proc_id}.png" + proc.save(proc_path) + + return { + "text": text, + "preview": preview_b64, + "proc_path": str(proc_path), + "config_used": f"lang={lang}, psm={psm}, scale={scale}, contrast={contrast}, sharpen={sharpen}, binary={binary}, thresh={binary_thresh}, whitelist={whitelist or 'none'}", + } + + +# ── Роуты ────────────────────────────────────────────────────────────── + +@app.route("/") +def index(): + return render_template("index.html") + + +@app.route("/ocr", methods=["POST"]) +def ocr(): + if "file" not in request.files: + return jsonify({"error": "Файл не загружен"}), 400 + + file = request.files["file"] + if file.filename == "" or not allowed_file(file.filename): + return jsonify({"error": "Неверный или пустой файл (разрешены PNG, JPG, JPEG, BMP, TIFF, WEBP, GIF)"}), 400 + + # Параметры из формы + lang = request.form.get("lang", "rus+eng").strip() + psm = int(request.form.get("psm", 6)) + scale = int(request.form.get("scale", 2)) + contrast = float(request.form.get("contrast", 2.0)) + sharpen = request.form.get("sharpen", "true").lower() in ("true", "1", "on") + binary = request.form.get("binary", "false").lower() in ("true", "1", "on") + binary_thresh = int(request.form.get("binary_thresh", 140)) + whitelist = request.form.get("whitelist", "").strip() + + # Сохраняем оригинал + ext = secure_filename(file.filename).rsplit(".", 1)[1].lower() + uid = uuid.uuid4().hex[:8] + original_path = UPLOAD_DIR / f"{uid}_{datetime.now():%Y%m%d_%H%M%S}.{ext}" + file.save(original_path) + + try: + result = do_ocr( + original_path, lang, psm, + scale, contrast, sharpen, + binary, binary_thresh, whitelist + ) + return jsonify(result) + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +@app.route("/uploads/") +def uploads(filename): + return send_from_directory(UPLOAD_DIR, filename) + + +# ── Запуск ───────────────────────────────────────────────────────────── + +if __name__ == "__main__": + port = int(os.environ.get("PORT", 5000)) + print(f"[Tesseract Web GUI] http://127.0.0.1:{port}/") + # debug=False, потому что иначе батник не закроется нормально + app.run(host="127.0.0.1", port=port, debug=False) diff --git a/start.bat b/start.bat new file mode 100644 index 0000000..f25dc39 --- /dev/null +++ b/start.bat @@ -0,0 +1,36 @@ +@echo off +chcp 65001 > nul +title Tesseract Web GUI + +:: Путь к папке проекта +set APP_DIR=%~dp0 +cd /d "%APP_DIR%" + +:: Проверяем Python +where python > nul 2> nul +if errorlevel 1 ( + echo [Ошибка] Python не найден. Установи Python 3.10+ и добавь в PATH. + pause + exit /b 1 +) + +:: Установка зависимостей (пропустит если уже стоят) +echo [1/3] Проверка зависимостей... +python -m pip install -q flask pillow pytesseract + +:: Проверяем Tesseract +if not exist "C:\Program Files\Tesseract-OCR\tesseract.exe" ( + echo [Предупреждение] Tesseract не найден по пути C:\Program Files\Tesseract-OCR\tesseract.exe + echo Установи: winget install UB-Mannheim.TesseractOCR + pause + exit /b 1 +) + +:: Запуск +echo [2/3] Запуск веб-сервиса... +echo [3/3] Открой браузер: http://127.0.0.1:5000/ +echo. + +python app.py + +pause diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..823ebee --- /dev/null +++ b/templates/index.html @@ -0,0 +1,291 @@ + + + + + + Tesseract Web GUI + + + +
+

🔍 Tesseract Web GUI

+
Загрузи картинку — получи текст. Всё локально, без интернета.
+ +
+
+
+

1. Картинка

+
+ 📁 Перетащи сюда файл или кликни для выбора + +
+
+
+ +
+

2. Настройки OCR

+ + + + + + + + + + + + +
+ + +
+ +
+ + +
+ + + + + + + + +
+
+
+ +
+

3. Результат

+ +
+
+
+
+ + + + diff --git a/uploads/47b13fb4_20260703_165917.png b/uploads/47b13fb4_20260703_165917.png new file mode 100644 index 0000000..a22147f Binary files /dev/null and b/uploads/47b13fb4_20260703_165917.png differ diff --git a/uploads/proc_ba6fc1d7.png b/uploads/proc_ba6fc1d7.png new file mode 100644 index 0000000..42f15ef Binary files /dev/null and b/uploads/proc_ba6fc1d7.png differ