File size: 2,711 Bytes
50776af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import pytesseract
from PIL import Image, ImageFilter, ImageEnhance
import io
import re
import os

if os.name == 'nt':  # 'nt' = Windows, anything else = Linux/Mac
    pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'webp', 'bmp'}
MAX_FILE_SIZE_MB = 10


def allowed_file(filename: str) -> bool:
    return '.' in filename and filename.rsplit('.', 1)[-1].lower() in ALLOWED_EXTENSIONS


def preprocess_image(image: Image.Image) -> Image.Image:
    """Grayscale + sharpen + contrast boost — helps with dark WhatsApp screenshots."""
    image = image.convert('L')
    image = image.filter(ImageFilter.SHARPEN)
    enhancer = ImageEnhance.Contrast(image)
    return enhancer.enhance(2.0)


def clean_ocr_text(raw_text: str) -> str:
    """Strip blank lines, non-ASCII junk, and collapse whitespace."""
    lines = [line.strip() for line in raw_text.splitlines() if line.strip()]
    joined = ' '.join(lines)
    joined = re.sub(r'[^\x20-\x7E\n]', ' ', joined)
    return re.sub(r' +', ' ', joined).strip()


def extract_text_from_image(file_bytes: bytes) -> dict:
    """
    Main entry point. Takes raw image bytes, returns:
      { 'success': True,  'text': <cleaned str>, 'raw': <raw str> }
      { 'success': False, 'error': <message> }
    """
    # Size check
    size_mb = len(file_bytes) / (1024 * 1024)
    if size_mb > MAX_FILE_SIZE_MB:
        return {'success': False, 'error': f'File too large ({size_mb:.1f} MB). Max is {MAX_FILE_SIZE_MB} MB.'}

    # Open image
    try:
        image = Image.open(io.BytesIO(file_bytes))
    except Exception:
        return {'success': False, 'error': 'Could not open image. Make sure it is a valid PNG, JPG, or WEBP.'}

    # Resize if very wide (Tesseract slows down on huge images)
    if image.width > 1600:
        ratio = 1600 / image.width
        image = image.resize((1600, int(image.height * ratio)), Image.LANCZOS)

    # Preprocess and OCR
    try:
        processed = preprocess_image(image)
        raw_text = pytesseract.image_to_string(processed, config='--oem 3 --psm 6')
    except pytesseract.TesseractNotFoundError:
        return {
            'success': False,
            'error': 'Tesseract binary not found. Make sure it is installed and the path is correct in ocr.py.'
        }
    except Exception as e:
        return {'success': False, 'error': f'OCR failed: {str(e)}'}

    cleaned = clean_ocr_text(raw_text)

    if len(cleaned) < 10:
        return {
            'success': False,
            'error': 'No readable text found. Try a clearer, higher-contrast screenshot.'
        }

    return {'success': True, 'text': cleaned, 'raw': raw_text}