Files
tesseract-webgui/app.py
T

149 lines
5.5 KiB
Python

"""
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/<path:filename>")
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)