Implement reading from unix sockets
This commit is contained in:
@@ -561,4 +561,4 @@ class RapidOCR:
|
|||||||
return x
|
return x
|
||||||
|
|
||||||
def _preprocess(self, img):
|
def _preprocess(self, img):
|
||||||
return pil_image_to_numpy_array(img)
|
return pil_image_to_numpy_array(img)
|
||||||
76
owocr/run.py
76
owocr/run.py
@@ -11,6 +11,7 @@ import mss
|
|||||||
import pywinctl
|
import pywinctl
|
||||||
import asyncio
|
import asyncio
|
||||||
import websockets
|
import websockets
|
||||||
|
import socketserver
|
||||||
import queue
|
import queue
|
||||||
import io
|
import io
|
||||||
|
|
||||||
@@ -125,6 +126,29 @@ class WebsocketServerThread(threading.Thread):
|
|||||||
self.loop.close()
|
self.loop.close()
|
||||||
|
|
||||||
|
|
||||||
|
class RequestHandler(socketserver.BaseRequestHandler):
|
||||||
|
def handle(self):
|
||||||
|
conn = self.request
|
||||||
|
conn.settimeout(3)
|
||||||
|
data = conn.recv(4)
|
||||||
|
img_size = int.from_bytes(data)
|
||||||
|
img = bytearray()
|
||||||
|
try:
|
||||||
|
while len(img) < img_size:
|
||||||
|
data = conn.recv(4096)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
img.extend(data)
|
||||||
|
except TimeoutError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not paused:
|
||||||
|
unixsocket_queue.put(img)
|
||||||
|
conn.sendall(b'True')
|
||||||
|
else:
|
||||||
|
conn.sendall(b'False')
|
||||||
|
|
||||||
|
|
||||||
class TextFiltering:
|
class TextFiltering:
|
||||||
accurate_filtering = False
|
accurate_filtering = False
|
||||||
|
|
||||||
@@ -358,11 +382,7 @@ def process_and_write_results(img_or_path, write_to, notifications, enable_filte
|
|||||||
elif write_to == 'clipboard':
|
elif write_to == 'clipboard':
|
||||||
pyperclipfix.copy(text)
|
pyperclipfix.copy(text)
|
||||||
else:
|
else:
|
||||||
write_to = Path(write_to)
|
with Path(write_to).open('a', encoding='utf-8') as f:
|
||||||
if write_to.suffix.lower() != '.txt':
|
|
||||||
raise ValueError('write_to must be either "websocket", "clipboard" or a path to a text file')
|
|
||||||
|
|
||||||
with write_to.open('a', encoding='utf-8') as f:
|
|
||||||
f.write(text + '\n')
|
f.write(text + '\n')
|
||||||
else:
|
else:
|
||||||
logger.opt(ansi=True).info(f'<{engine_color}>{engine_instance.readable_name}</{engine_color}> reported an error after {t1 - t0:0.03f}s: {text}')
|
logger.opt(ansi=True).info(f'<{engine_color}>{engine_instance.readable_name}</{engine_color}> reported an error after {t1 - t0:0.03f}s: {text}')
|
||||||
@@ -400,7 +420,7 @@ def run(read_from=None,
|
|||||||
Run OCR in the background, waiting for new images to appear either in system clipboard or a directory, or to be sent via a websocket.
|
Run OCR in the background, waiting for new images to appear either in system clipboard or a directory, or to be sent via a websocket.
|
||||||
Recognized texts can be either saved to system clipboard, appended to a text file or sent via a websocket.
|
Recognized texts can be either saved to system clipboard, appended to a text file or sent via a websocket.
|
||||||
|
|
||||||
:param read_from: Specifies where to read input images from. Can be either "clipboard", "websocket", "screencapture", or a path to a directory.
|
:param read_from: Specifies where to read input images from. Can be either "clipboard", "websocket", "unixsocket" (on macOS/Linux), "screencapture", or a path to a directory.
|
||||||
:param write_to: Specifies where to save recognized texts to. Can be either "clipboard", "websocket", or a path to a text file.
|
:param write_to: Specifies where to save recognized texts to. Can be either "clipboard", "websocket", or a path to a text file.
|
||||||
:param delay_secs: How often to check for new images, in seconds.
|
:param delay_secs: How often to check for new images, in seconds.
|
||||||
:param engine: OCR engine to use. Available: "mangaocr", "glens", "gvision", "avision", "alivetext", "azure", "winrtocr", "easyocr", "rapidocr".
|
:param engine: OCR engine to use. Available: "mangaocr", "glens", "gvision", "avision", "alivetext", "azure", "winrtocr", "easyocr", "rapidocr".
|
||||||
@@ -496,7 +516,20 @@ def run(read_from=None,
|
|||||||
if read_from == 'websocket':
|
if read_from == 'websocket':
|
||||||
global websocket_queue
|
global websocket_queue
|
||||||
websocket_queue = queue.Queue()
|
websocket_queue = queue.Queue()
|
||||||
logger.opt(ansi=True).info(f"Reading from websocket using <{engine_color}>{engine_instances[engine_index].readable_name}</{engine_color}>{' (paused)' if paused else ''}")
|
read_from_readable = 'websocket'
|
||||||
|
elif read_from == 'unixsocket':
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
raise ValueError('"unixsocket" is not currently supported on Windows')
|
||||||
|
|
||||||
|
global unixsocket_queue
|
||||||
|
unixsocket_queue = queue.Queue()
|
||||||
|
socket_path = Path('/tmp/owocr.sock')
|
||||||
|
if socket_path.exists():
|
||||||
|
socket_path.unlink()
|
||||||
|
unix_socket_server = socketserver.ThreadingUnixStreamServer(str(socket_path), RequestHandler)
|
||||||
|
unix_socket_server_thread = threading.Thread(target=unix_socket_server.serve_forever, daemon=True)
|
||||||
|
unix_socket_server_thread.start()
|
||||||
|
read_from_readable = 'unix socket'
|
||||||
elif read_from == 'clipboard':
|
elif read_from == 'clipboard':
|
||||||
mac_clipboard_polling = False
|
mac_clipboard_polling = False
|
||||||
windows_clipboard_polling = False
|
windows_clipboard_polling = False
|
||||||
@@ -516,7 +549,7 @@ def run(read_from=None,
|
|||||||
else:
|
else:
|
||||||
from PIL import ImageGrab
|
from PIL import ImageGrab
|
||||||
|
|
||||||
logger.opt(ansi=True).info(f"Reading from clipboard using <{engine_color}>{engine_instances[engine_index].readable_name}</{engine_color}>{' (paused)' if paused else ''}")
|
read_from_readable = 'clipboard'
|
||||||
elif read_from == 'screencapture':
|
elif read_from == 'screencapture':
|
||||||
if screen_capture_combo != '':
|
if screen_capture_combo != '':
|
||||||
screen_capture_on_combo = True
|
screen_capture_on_combo = True
|
||||||
@@ -577,11 +610,11 @@ def run(read_from=None,
|
|||||||
sct_params = {'top': coord_top, 'left': coord_left, 'width': coord_width, 'height': coord_height, 'mon': screen_capture_monitor}
|
sct_params = {'top': coord_top, 'left': coord_left, 'width': coord_width, 'height': coord_height, 'mon': screen_capture_monitor}
|
||||||
|
|
||||||
filtering = TextFiltering()
|
filtering = TextFiltering()
|
||||||
logger.opt(ansi=True).info(f"Reading with screen capture using <{engine_color}>{engine_instances[engine_index].readable_name}</{engine_color}>{' (paused)' if paused else ''}")
|
read_from_readable = 'screen capture'
|
||||||
else:
|
else:
|
||||||
read_from = Path(read_from)
|
read_from = Path(read_from)
|
||||||
if not read_from.is_dir():
|
if not read_from.is_dir():
|
||||||
raise ValueError('read_from must be either "websocket", "clipboard", "screencapture" or a path to a directory')
|
raise ValueError('read_from must be either "websocket", "unixsocket", "clipboard", "screencapture", or a path to a directory')
|
||||||
|
|
||||||
allowed_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp')
|
allowed_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp')
|
||||||
old_paths = set()
|
old_paths = set()
|
||||||
@@ -589,13 +622,21 @@ def run(read_from=None,
|
|||||||
if path.suffix.lower() in allowed_extensions:
|
if path.suffix.lower() in allowed_extensions:
|
||||||
old_paths.add(get_path_key(path))
|
old_paths.add(get_path_key(path))
|
||||||
|
|
||||||
logger.opt(ansi=True).info(f"Reading from directory {read_from} using <{engine_color}>{engine_instances[engine_index].readable_name}</{engine_color}>{' (paused)' if paused else ''}")
|
read_from_readable = f'directory {read_from}'
|
||||||
|
|
||||||
if len(key_combos) > 0:
|
if len(key_combos) > 0:
|
||||||
key_combo_listener = keyboard.GlobalHotKeys(key_combos)
|
key_combo_listener = keyboard.GlobalHotKeys(key_combos)
|
||||||
else:
|
else:
|
||||||
key_combo_listener = keyboard.Listener(on_press=on_key_press, on_release=on_key_release)
|
key_combo_listener = keyboard.Listener(on_press=on_key_press, on_release=on_key_release)
|
||||||
key_combo_listener.start()
|
key_combo_listener.start()
|
||||||
|
|
||||||
|
if write_to in ('clipboard', 'websocket'):
|
||||||
|
write_to_readable = write_to
|
||||||
|
else:
|
||||||
|
if Path(write_to).suffix.lower() != '.txt':
|
||||||
|
raise ValueError('write_to must be either "websocket", "clipboard" or a path to a text file')
|
||||||
|
write_to_readable = f'file {write_to}'
|
||||||
|
logger.opt(ansi=True).info(f"Reading from {read_from_readable}, writing to {write_to_readable} using <{engine_color}>{engine_instances[engine_index].readable_name}</{engine_color}>{' (paused)' if paused else ''}")
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
|
|
||||||
while not terminated:
|
while not terminated:
|
||||||
@@ -609,6 +650,16 @@ def run(read_from=None,
|
|||||||
if not paused:
|
if not paused:
|
||||||
img = Image.open(io.BytesIO(item))
|
img = Image.open(io.BytesIO(item))
|
||||||
process_and_write_results(img, write_to, notifications, False, '', None)
|
process_and_write_results(img, write_to, notifications, False, '', None)
|
||||||
|
elif read_from == 'unixsocket':
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
item = unixsocket_queue.get(timeout=delay_secs)
|
||||||
|
except queue.Empty:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if not paused:
|
||||||
|
img = Image.open(io.BytesIO(item))
|
||||||
|
process_and_write_results(img, write_to, notifications, False, '', None)
|
||||||
elif read_from == 'clipboard':
|
elif read_from == 'clipboard':
|
||||||
process_clipboard = False
|
process_clipboard = False
|
||||||
if windows_clipboard_polling:
|
if windows_clipboard_polling:
|
||||||
@@ -710,4 +761,7 @@ def run(read_from=None,
|
|||||||
windows_clipboard_thread.join()
|
windows_clipboard_thread.join()
|
||||||
elif read_from == 'screencapture' and screencapture_window_mode:
|
elif read_from == 'screencapture' and screencapture_window_mode:
|
||||||
target_window.watchdog.stop()
|
target_window.watchdog.stop()
|
||||||
|
elif read_from == 'unixsocket':
|
||||||
|
unix_socket_server.shutdown()
|
||||||
|
unix_socket_server_thread.join()
|
||||||
key_combo_listener.stop()
|
key_combo_listener.stop()
|
||||||
|
|||||||
Reference in New Issue
Block a user