diff --git a/owocr/ocr.py b/owocr/ocr.py index 2ec384e..7583e98 100644 --- a/owocr/ocr.py +++ b/owocr/ocr.py @@ -72,9 +72,9 @@ def post_process(text): class MangaOcr: - name = "mangaocr" - readable_name = "Manga OCR" - key = "m" + name = 'mangaocr' + readable_name = 'Manga OCR' + key = 'm' available = False def __init__(self, config={'pretrained_model_name_or_path':'kha-white/manga-ocr-base','force_cpu':'False'}, pretrained_model_name_or_path='', force_cpu=False): @@ -86,7 +86,7 @@ class MangaOcr: if config['force_cpu'] == 'True': force_cpu = True - logger.disable("manga_ocr") + logger.disable('manga_ocr') logger.info(f'Loading Manga OCR model') self.model = MOCR(pretrained_model_name_or_path, force_cpu) self.available = True @@ -104,9 +104,9 @@ class MangaOcr: return x class GoogleVision: - name = "gvision" - readable_name = "Google Vision" - key = "g" + name = 'gvision' + readable_name = 'Google Vision' + key = 'g' available = False def __init__(self): @@ -144,9 +144,9 @@ class GoogleVision: return image_bytes.getvalue() class GoogleLens: - name = "glens" - readable_name = "Google Lens" - key = "l" + name = 'glens' + readable_name = 'Google Lens' + key = 'l' available = False def __init__(self): @@ -167,12 +167,12 @@ class GoogleLens: raise ValueError(f'img_or_path must be a path or PIL.Image, instead got: {img_or_path}') timestamp = int(time.time() * 1000) - url = f"https://lens.google.com/v3/upload?stcs={timestamp}" - files = {"encoded_image": ('owo' + str(timestamp) + '.png', self._preprocess(img), 'image/png')} + url = f'https://lens.google.com/v3/upload?stcs={timestamp}' + files = {'encoded_image': ('owo' + str(timestamp) + '.png', self._preprocess(img), 'image/png')} try: res = requests.post(url, files=files, timeout=(3, 10)) except requests.exceptions.Timeout: - return "Request timeout!" + return 'Request timeout!' x = '' if res.status_code == 200: @@ -192,17 +192,17 @@ class GoogleLens: def _preprocess(self, img): image_bytes = io.BytesIO() - img.save(image_bytes, format="png") + img.save(image_bytes, format='png') return image_bytes.getvalue() class AppleVision: - name = "avision" - readable_name = "Apple Vision" - key = "a" + name = 'avision' + readable_name = 'Apple Vision' + key = 'a' available = False def __init__(self): - if sys.platform != "darwin": + if sys.platform != 'darwin': logger.warning('Apple Vision is not supported on non-macOS platforms!') elif int(platform.mac_ver()[0].split('.')[0]) < 13: logger.warning('Apple Vision is not supported on macOS older than Ventura/13.0!') @@ -249,13 +249,13 @@ class AppleVision: return image_bytes.getvalue() class WinRTOCR: - name = "winrtocr" - readable_name = "WinRT OCR" - key = "w" + name = 'winrtocr' + readable_name = 'WinRT OCR' + key = 'w' available = False def __init__(self, config={}): - if sys.platform == "win32": + if sys.platform == 'win32': if int(platform.release()) < 10: logger.warning('WinRT OCR is not supported on Windows older than 10!') elif 'winocr' not in sys.modules: @@ -282,14 +282,14 @@ class WinRTOCR: else: raise ValueError(f'img_or_path must be a path or PIL.Image, instead got: {img_or_path}') - if sys.platform == "win32": + if sys.platform == 'win32': res = winocr.recognize_pil_sync(img, lang='ja')['text'] else: params = {'lang': 'ja'} try: res = requests.post(self.url, params=params, data=self._preprocess(img), timeout=3) except requests.exceptions.Timeout: - return "Request timeout!" + return 'Request timeout!' res = json.loads(res.text)['text'] @@ -302,9 +302,9 @@ class WinRTOCR: return image_bytes.getvalue() class AzureComputerVision: - name = "azure" - readable_name = "Azure Computer Vision" - key = "v" + name = 'azure' + readable_name = 'Azure Computer Vision' + key = 'v' available = False def __init__(self, config={}): @@ -330,8 +330,8 @@ class AzureComputerVision: image_io = self._preprocess(img) read_response = self.client.read_in_stream(image_io, raw=True) - read_operation_location = read_response.headers["Operation-Location"] - operation_id = read_operation_location.split("/")[-1] + read_operation_location = read_response.headers['Operation-Location'] + operation_id = read_operation_location.split('/')[-1] while True: read_result = self.client.get_read_result(operation_id) @@ -355,9 +355,9 @@ class AzureComputerVision: return image_io class EasyOCR: - name = "easyocr" - readable_name = "EasyOCR" - key = "e" + name = 'easyocr' + readable_name = 'EasyOCR' + key = 'e' available = False def __init__(self): @@ -391,9 +391,9 @@ class EasyOCR: return image_bytes.getvalue() class PaddleOCR: - name = "paddleocr" - readable_name = "PaddleOCR" - key = "o" + name = 'paddleocr' + readable_name = 'PaddleOCR' + key = 'o' available = False def __init__(self): diff --git a/owocr/run.py b/owocr/run.py index 1867155..68499dc 100644 --- a/owocr/run.py +++ b/owocr/run.py @@ -45,7 +45,7 @@ class WindowsClipboardThread(threading.Thread): return 0 def create_window(self): - className = "ClipboardHook" + className = 'ClipboardHook' wc = win32gui.WNDCLASS() wc.lpfnWndProc = self.process_message wc.lpszClassName = className @@ -80,12 +80,12 @@ class WebsocketServerThread(threading.Thread): if self.read and not (paused or tmp_paused): websocket_queue.put(message) try: - await websocket.send("True") + await websocket.send('True') except websockets.exceptions.ConnectionClosedOK: pass else: try: - await websocket.send("False") + await websocket.send('False') except websockets.exceptions.ConnectionClosedOK: pass finally: @@ -112,7 +112,7 @@ class WebsocketServerThread(threading.Thread): def getchar_thread(): global user_input - if sys.platform == "win32": + if sys.platform == 'win32': import msvcrt while True: user_input = msvcrt.getch() @@ -169,7 +169,7 @@ def process_and_write_results(engine_instance, engine_color, img_or_path, write_ text = engine_instance(img_or_path) t1 = time.time() - logger.opt(ansi=True).info(f"Text recognized in {t1 - t0:0.03f}s using <{engine_color}>{engine_instance.readable_name}: {text}") + logger.opt(ansi=True).info(f'Text recognized in {t1 - t0:0.03f}s using <{engine_color}>{engine_instance.readable_name}: {text}') if notifications == True: notification = Notify() notification.application_name = 'owocr' @@ -186,7 +186,7 @@ def process_and_write_results(engine_instance, engine_color, img_or_path, write_ if write_to.suffix != '.txt': raise ValueError('write_to must be either "clipboard" or a path to a text file') - with write_to.open('a', encoding="utf-8") as f: + with write_to.open('a', encoding='utf-8') as f: f.write(text + '\n') @@ -220,8 +220,8 @@ def run(read_from='clipboard', # Check if the system is using Wayland if os.environ.get('WAYLAND_DISPLAY'): # Check if the wl-clipboard package is installed - if os.system("which wl-copy > /dev/null") == 0: - pyperclip.set_clipboard("wl-clipboard") + if os.system('which wl-copy > /dev/null') == 0: + pyperclip.set_clipboard('wl-clipboard') else: msg = 'Your session uses wayland and does not have wl-clipboard installed. ' \ 'Install wl-clipboard for write in clipboard to work.' @@ -274,14 +274,14 @@ def run(read_from='clipboard', except KeyError: pass - logger.configure(handlers=[{"sink": sys.stderr, "format": logger_format}]) + logger.configure(handlers=[{'sink': sys.stderr, 'format': logger_format}]) if len(res) != 0: logger.info('Parsed config file') else: logger.warning('No config file, defaults will be used') - for _,engine_class in sorted(inspect.getmembers(sys.modules[__name__], lambda x: hasattr(x, '__module__') and __package__ + ".ocr" in x.__module__ and inspect.isclass(x))): + for _,engine_class in sorted(inspect.getmembers(sys.modules[__name__], lambda x: hasattr(x, '__module__') and __package__ + '.ocr' in x.__module__ and inspect.isclass(x))): if len(config_engines) == 0 or engine_class.name in config_engines: try: engine_instance = engine_class(config[engine_class.name]) @@ -348,7 +348,7 @@ def run(read_from='clipboard', windows_clipboard_thread.start() windows_clipboard_polling = True else: - allowed_extensions = (".png", ".jpg", ".jpeg", ".bmp", ".gif", ".webp") + allowed_extensions = ('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.webp') read_from = Path(read_from) if not read_from.is_dir(): raise ValueError('read_from must be either "clipboard" or a path to a directory') @@ -393,7 +393,7 @@ def run(read_from='clipboard', if engine_index != new_engine_index: engine_index = new_engine_index - logger.opt(ansi=True).info(f"Switched to <{engine_color}>{engine_instances[engine_index].readable_name}!") + logger.opt(ansi=True).info(f'Switched to <{engine_color}>{engine_instances[engine_index].readable_name}!') user_input = '' @@ -408,14 +408,16 @@ def run(read_from='clipboard', img = Image.open(io.BytesIO(item)) process_and_write_results(engine_instances[engine_index], engine_color, img, write_to, notifications) elif read_from == 'clipboard': + changed = False if windows_clipboard_polling: changed = clipboard_event.wait(delay_secs) if changed: clipboard_event.clear() - elif mac_clipboard_polling and not (paused or tmp_paused): - old_count = count - count = pasteboard.changeCount() - changed = not just_unpaused and count != old_count and any(x in pasteboard.types() for x in [NSPasteboardTypePNG, NSPasteboardTypeTIFF]) + elif mac_clipboard_polling: + if not (paused or tmp_paused): + old_count = count + count = pasteboard.changeCount() + changed = not just_unpaused and count != old_count and any(x in pasteboard.types() for x in [NSPasteboardTypePNG, NSPasteboardTypeTIFF]) else: changed = not (paused or tmp_paused) @@ -425,10 +427,10 @@ def run(read_from='clipboard', try: img = ImageGrab.grabclipboard() except OSError as error: - if not verbose and "cannot identify image file" in str(error): + if not verbose and 'cannot identify image file' in str(error): # Pillow error when clipboard hasn't changed since last grab (Linux) pass - elif not verbose and "target image/png not available" in str(error): + elif not verbose and 'target image/png not available' in str(error): # Pillow error when clipboard contains text (Linux, X11) pass else: