Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implemented text recognition (ocr) #272

Merged
merged 29 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
efe7f73
implemented text recognition (ocr)
ston1th Jan 17, 2024
a00dd41
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 17, 2024
ead3463
fixed typo in requirements.txt and make linter happy
ston1th Jan 17, 2024
d36e2d4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 17, 2024
c9766bf
keep pillow on windows and more linter fixes
ston1th Jan 17, 2024
8998360
use pathlib to read file
ston1th Jan 17, 2024
f25fc7e
fix str None comparison
ston1th Jan 17, 2024
2f8d298
rewrite some stuff
ston1th Feb 3, 2024
fddd0ae
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 3, 2024
cd2c212
switch back to tesseract
ston1th Feb 3, 2024
80140cb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 3, 2024
450b983
Merge branch 'dev' into ocr
Avasam Feb 3, 2024
feeb58e
internal logic changes
ston1th Feb 4, 2024
fb8ed6f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 4, 2024
da830c6
import subprocess globally
ston1th Feb 4, 2024
5674088
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 4, 2024
b5f6639
make linter happy
ston1th Feb 4, 2024
f1ba410
fixed typo in docstring
ston1th Feb 4, 2024
d1dfff0
input validation and comparison methods
ston1th Feb 10, 2024
f3c0e3e
fix linter
ston1th Feb 10, 2024
3a3015f
Merge branch 'dev' of https://github.com/Toufool/AutoSplit into ocr
ston1th Mar 21, 2024
75cd0e9
improvements to coordinates and matching methods
ston1th Mar 29, 2024
7be9a0e
fix ruff linter
ston1th Mar 29, 2024
043b6b5
Address my own PR comments and fix linting
Avasam Jun 15, 2024
c0b2920
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 15, 2024
f2b407a
Merge branch 'dev' into ocr
Avasam Jun 15, 2024
9cd0c2b
STARTUPINFO doesn't exist on Linux
Avasam Jun 16, 2024
2f03a90
More explicit platform check
Avasam Jun 16, 2024
797492f
Fix circular imports, mak OCR as clearly experimental
Avasam Jun 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ This program can be used to automatically start, split, and reset your preferred
- Wayland is not currently supported
- WSL2/WSLg requires an additional Desktop Environment, external X11 server, and/or systemd
- Python 3.10+ (Not required for normal use. Refer to the [build instructions](/docs/build%20instructions.md) if you'd like run the application directly in Python).
- Tesseract-OCR (optional; requierd for text recognition as an alternative comparison method). See https://github.com/UB-Mannheim/tesseract/wiki for installation instructions.
Avasam marked this conversation as resolved.
Show resolved Hide resolved

## OPTIONS

Expand Down Expand Up @@ -226,6 +227,49 @@ You can have one (and only one) image with the keyword `reset` in its name. Auto

The Start Image is similar to the Reset Image. You can only have one Start Image with the keyword `start_auto_splitter`.You can reload the image using the "`Reload Start Image`" button. The pause time is the amount of seconds AutoSplit will wait before starting comparisons of the first split image. Delay times will be used to delay starting your timer after the threshold is met.

### Text Recognition (OCR)

You can use text recognition as an alternative comparison method.
First you need to install tesseract and include it in your PATH variable. See [Compatibility](#Compatibility) above.

To include tesseract in your PATH variable you can use this powershell snippet.

Note: change the `$tesseract_path` variable to the location where tesseract is installed.

```
$path = [System.Environment]::GetEnvironmentVariable("Path", "User")
$tesseract_path = "C:\Program Files\Tesseract-OCR"
[System.Environment]::SetEnvironmentVariable("Path", "$path;$tesseract_path", "User")
```
Avasam marked this conversation as resolved.
Show resolved Hide resolved

To use this feature you need to place a text file (.txt) in your splits folder instead of an image file.

An example file name and content could look like this:

Filename: `001_start_auto_splitter.txt`

Content:

```
texts = ["complete any 2 encounters"]
top_left = 275
top_right = 540
bottom_left = 70
bottom_right = 95
fps_limit = 1
```

The `texts` field is an array and can take more than one text to look for:

```
Avasam marked this conversation as resolved.
Show resolved Hide resolved
texts = ["look for me", "or this text"]
```

The `top`, `bottom`, `left` and `right` options define a rectangle where the text you are looking for is expected to appear in the image.
Avasam marked this conversation as resolved.
Show resolved Hide resolved

Note: This method can cause high CPU usage at the standard comparison FPS. You should therefor limit the comparison FPS when you use this method to 1 or 2 FPS using the `fps_limit` option.
The size of the selected rectangle can also impact the CPU load (bigger = more CPU load).

### Profiles

<!-- TODO: Profiles are saved under `%appdata%\AutoSplit\profiles` and -->
Expand Down
1 change: 1 addition & 0 deletions scripts/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#
# Dependencies:
git+https://github.com/boppreh/keyboard.git#egg=keyboard # Fix install on macos and linux-ci https://github.com/boppreh/keyboard/pull/568
Levenshtein
Avasam marked this conversation as resolved.
Show resolved Hide resolved
numpy>=1.26 # Python 3.12 support
opencv-python-headless>=4.9.0.80 # Typing fixes
packaging
Expand Down
11 changes: 8 additions & 3 deletions src/AutoSplit.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,8 @@ def __reload_start_image(self, started_by_button: bool = False, wait_for_delay:
self.highest_similarity = 0.0
self.reset_highest_similarity = 0.0
self.split_below_threshold = False
self.timer_start_image.start(int(ONE_SECOND / self.settings_dict["fps_limit"]))

self.timer_start_image.start(int(ONE_SECOND / self.start_image.get_fps_limit(self)))

QApplication.processEvents()

Expand Down Expand Up @@ -683,7 +684,7 @@ def __similarity_threshold_loop(self, number_of_split_images: int, dummy_splits_
QApplication.processEvents()

# Limit the number of time the comparison runs to reduce cpu usage
frame_interval = 1 / self.settings_dict["fps_limit"]
frame_interval = 1 / self.split_image.get_fps_limit(self)
# Use a time delta to have a consistant check interval
wait_delta_ms = int((frame_interval - (time() - start) % frame_interval) * ONE_SECOND)

Expand Down Expand Up @@ -867,7 +868,11 @@ def __update_split_image(self, specific_image: AutoSplitImage | None = None):

# Get split image
self.split_image = specific_image or self.split_images_and_loop_number[0 + self.split_image_number][0]
if is_valid_image(self.split_image.byte_array):
if self.split_image.is_ocr:
# TODO: test if setText clears a set image
text = "\nor\n".join(self.split_image.texts)
self.current_split_image.setText(f"Looking for OCR text:\n{text}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't remember from last time I tested, will this override any previous image being rendered on the QLabel? (let's say someone has a regular split image followed by an OCR split)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question, I did not test this. But just to be sure we could just None it and then set the text.

Copy link
Collaborator

@Avasam Avasam Feb 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, set_preview_image avoids clearing text if you send None by design.
Or you could call self.current_split_image.clear() yourself before setting the text.

If setText already clears the image by itself, then you don't need to do anything.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't block for this with the TODO comment. Just bumping as a reminder we should test it to confirm

elif is_valid_image(self.split_image.byte_array):
set_preview_image(self.current_split_image, self.split_image.byte_array)

self.current_image_file_label.setText(self.split_image.filename)
Expand Down
59 changes: 55 additions & 4 deletions src/AutoSplitImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

import cv2
import numpy as np
import toml
from cv2.typing import MatLike

import error_messages
from compare import check_if_image_has_transparency, get_comparison_method_by_index
from compare import check_if_image_has_transparency, extract_and_compare_text, get_comparison_method_by_index
from utils import BGR_CHANNEL_COUNT, MAXBYTE, ColorChannel, ImageShape, is_valid_image

if TYPE_CHECKING:
Expand Down Expand Up @@ -40,13 +41,27 @@
image_type: ImageType
byte_array: MatLike | None = None
mask: MatLike | None = None
texts: list[str]
# This value is internal, check for mask instead
_has_transparency = False
# These values should be overriden by some Defaults if None. Use getters instead
__delay_time: float | None = None
__comparison_method: int | None = None
__pause_time: float | None = None
__similarity_threshold: float | None = None
__x: int
__xx: int
__y: int
__yy: int
__fps_limit: int

@property
def is_ocr(self):
"""
Whether a "split image" is actually for Optical Text Recognition
based on whether there's any text strings to search for.
"""
return bool(self.texts)

def get_delay_time(self, default: "AutoSplit | int"):
"""Get image's delay time or fallback to the default value from spinbox."""
Expand Down Expand Up @@ -80,16 +95,31 @@
return default
return default.settings_dict["default_similarity_threshold"]

def get_fps_limit(self, default: "AutoSplit"):
"""Get image's fps limit or fallback to the default value from spinbox."""
if self.__fps_limit != 0:
return self.__fps_limit
return default.settings_dict["fps_limit"]

def __init__(self, path: str):
self.path = path
self.filename = os.path.split(path)[-1].lower()
self.flags = flags_from_filename(self.filename)
self.loops = loop_from_filename(self.filename)
self.texts = list[str]()
Avasam marked this conversation as resolved.
Show resolved Hide resolved
self.__delay_time = delay_time_from_filename(self.filename)
self.__comparison_method = comparison_method_from_filename(self.filename)
self.__pause_time = pause_from_filename(self.filename)
self.__similarity_threshold = threshold_from_filename(self.filename)
self.__read_image_bytes(path)
self.__x = 0
self.__xx = 0
self.__y = 0
self.__yy = 0
self.__fps_limit = 0
Avasam marked this conversation as resolved.
Show resolved Hide resolved
if path.endswith("txt"):
Avasam marked this conversation as resolved.
Show resolved Hide resolved
self.__parse_text_file(path)
else:
self.__read_image_bytes(path)

if START_KEYWORD in self.filename:
self.image_type = ImageType.START
Expand All @@ -98,6 +128,18 @@
else:
self.image_type = ImageType.SPLIT

def __parse_text_file(self, path: str):
Avasam marked this conversation as resolved.
Show resolved Hide resolved
with open(path, encoding="utf-8") as f:
data = toml.load(f)
self.texts = data["texts"]
Avasam marked this conversation as resolved.
Show resolved Hide resolved
self.__x = data["top_left"]
self.__xx = data["top_right"]
self.__y = data["bottom_left"]
self.__yy = data["bottom_right"]
self.__fps_limit = 1
if "fps_limit" in data:
self.fps_limit = data["fps_limit"]

Check failure on line 141 in src/AutoSplitImage.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Instance variable "fps_limit" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)

Check failure on line 141 in src/AutoSplitImage.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Instance variable "fps_limit" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)

Check failure on line 141 in src/AutoSplitImage.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Instance variable "fps_limit" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)

Check failure on line 141 in src/AutoSplitImage.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Instance variable "fps_limit" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)

Check failure on line 141 in src/AutoSplitImage.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Instance variable "fps_limit" is not initialized in the class body or __init__ method (reportUninitializedInstanceVariable)
Avasam marked this conversation as resolved.
Show resolved Hide resolved

def __read_image_bytes(self, path: str):
image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
if not is_valid_image(image):
Expand Down Expand Up @@ -140,8 +182,17 @@
default: "AutoSplit | int",
capture: MatLike | None,
):
"""Compare image with capture using image's comparison method. Falls back to combobox."""
if not is_valid_image(self.byte_array) or not is_valid_image(capture):
"""
Compare image with capture using image's comparison method. Falls back to combobox.
For OCR text files: extract image text from rectangle position and compare it with the expected string.
"""
if not is_valid_image(capture):
return 0.0

if self.is_ocr:
return extract_and_compare_text(capture[self.__y:self.__yy, self.__x:self.__xx], self.texts)

if not is_valid_image(self.byte_array):
return 0.0
resized_capture = cv2.resize(capture, self.byte_array.shape[1::-1])

Expand Down
34 changes: 33 additions & 1 deletion src/compare.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from math import sqrt

import cv2
import Levenshtein
import numpy as np
from cv2.typing import MatLike
from scipy import fft

from utils import BGRA_CHANNEL_COUNT, MAXBYTE, ColorChannel, ImageShape, is_valid_image
from utils import BGRA_CHANNEL_COUNT, MAXBYTE, ColorChannel, ImageShape, is_valid_image, run_tesseract

MAXRANGE = MAXBYTE + 1
CHANNELS = [ColorChannel.Red.value, ColorChannel.Green.value, ColorChannel.Blue.value]
Expand Down Expand Up @@ -126,6 +127,37 @@
return 1 - (hash_diff / 64.0)


def extract_and_compare_text(capture: MatLike, texts: list[str]):
"""
Compares the extracted text of the given image and returns the similarity between the two texts.
The best match of all texts is returned.

@param capture: Image of any given shape as a numpy array
@param texts: a list of strings to match for
@return: The similarity between the text in the image and the text supplied as a number 0 to 1.
"""
png = np.array(cv2.imencode(".png", capture)[1]).tobytes()
# If the string is found 1:1 in the string extracted from the image a 1 is returned.
# Otherwise the levenshtein ratio is calculated between the two strings and gets returned.
# Especially with stylised characters, OCR could conceivably get the right
# letter, but mix up the casing (m/M, o/O, t/T, etc.)
image_string = run_tesseract(png).lower().strip()

ratio = 0.0
for text in texts:
# TODO: this 1:1 matching could lead to false positives
# maybe remove it and only rely on fuzzy matching?
# discussion: https://github.com/Toufool/AutoSplit/pull/272#discussion_r1477120477
if text in image_string:
Avasam marked this conversation as resolved.
Show resolved Hide resolved
ratio = 1.0
break
ratio = max(ratio, Levenshtein.ratio(text, image_string))

Check failure on line 154 in src/compare.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Type of "ratio" is partially unknown   Type of "ratio" is "(s1: Sequence[Hashable], s2: Sequence[Hashable], *, processor: ((...) -> Unknown) | None = None, score_cutoff: float | None = None) -> float" (reportUnknownMemberType)

Check failure on line 154 in src/compare.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Type of "ratio" is partially unknown   Type of "ratio" is "(s1: Sequence[Hashable], s2: Sequence[Hashable], *, processor: ((...) -> Unknown) | None = None, score_cutoff: float | None = None) -> float" (reportUnknownMemberType)

Check failure on line 154 in src/compare.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Type of "ratio" is partially unknown   Type of "ratio" is "(s1: Sequence[Hashable], s2: Sequence[Hashable], *, processor: ((...) -> Unknown) | None = None, score_cutoff: float | None = None) -> float" (reportUnknownMemberType)

Check failure on line 154 in src/compare.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Type of "ratio" is partially unknown   Type of "ratio" is "(s1: Sequence[Hashable], s2: Sequence[Hashable], *, processor: ((...) -> Unknown) | None = None, score_cutoff: float | None = None) -> float" (reportUnknownMemberType)

Check failure on line 154 in src/compare.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Type of "ratio" is partially unknown   Type of "ratio" is "(s1: Sequence[Hashable], s2: Sequence[Hashable], *, processor: ((...) -> Unknown) | None = None, score_cutoff: float | None = None) -> float" (reportUnknownMemberType)
# TODO: debug: remove me
if ratio > 0.9: # noqa: PLR2004
print(f"text from image ({ratio:,.2f}): {image_string}")
Avasam marked this conversation as resolved.
Show resolved Hide resolved
return ratio


def __compare_dummy(*_: object):
return 0.0

Expand Down
2 changes: 1 addition & 1 deletion src/split_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def parse_and_validate_images(autosplit: "AutoSplit"):
else:
for image in split_images:
# Test for image without transparency
if not is_valid_image(image.byte_array):
if not image.is_ocr and not is_valid_image(image.byte_array):
error_message = partial(error_messages.image_validity, image.filename)
break

Expand Down
42 changes: 40 additions & 2 deletions src/utils.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import asyncio
import os
import subprocess # noqa: S404
import sys
from collections.abc import Callable, Iterable
from enum import IntEnum
from functools import partial
from itertools import chain
from os import environ
from platform import version
from threading import Thread
from typing import TYPE_CHECKING, Any, TypeGuard, TypeVar
Expand Down Expand Up @@ -37,6 +39,9 @@

T = TypeVar("T")

TESSERACT_CMD = ["tesseract", "-", "-", "--oem", "1", "--psm", "6"]
Avasam marked this conversation as resolved.
Show resolved Hide resolved
DEFAULT_ENCODING = "utf-8"
Avasam marked this conversation as resolved.
Show resolved Hide resolved

DWMWA_EXTENDED_FRAME_BOUNDS = 9
MAXBYTE = 255
ONE_SECOND = 1000
Expand Down Expand Up @@ -126,8 +131,6 @@
if sys.platform == "win32":
os.startfile(file_path) # noqa: S606
else:
import subprocess # noqa: PLC0415, S404

opener = "xdg-open" if sys.platform == "linux" else "open"
subprocess.call([opener, file_path]) # noqa: S603

Expand Down Expand Up @@ -209,6 +212,41 @@
return chain.from_iterable(nested_iterable)


def subprocess_args():
"""
See https://github.com/pyinstaller/pyinstaller/wiki/Recipe-subprocess
for reference and comments.

This code snippet was copied from https://github.com/madmaze/pytesseract
"""
kwargs = {
"stdin": subprocess.PIPE,
"stdout": subprocess.PIPE,
"stderr": subprocess.DEVNULL,
"startupinfo": None,
"env": environ,
}

if hasattr(subprocess, "STARTUPINFO"):
kwargs["startupinfo"] = subprocess.STARTUPINFO()

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Argument type is unknown   Argument corresponds to parameter "__value" in function "__setitem__" (reportUnknownArgumentType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Type of "STARTUPINFO" is unknown (reportUnknownMemberType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

"STARTUPINFO" is not a known member of module "subprocess" (reportAttributeAccessIssue)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Argument type is unknown   Argument corresponds to parameter "__value" in function "__setitem__" (reportUnknownArgumentType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Type of "STARTUPINFO" is unknown (reportUnknownMemberType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

"STARTUPINFO" is not a known member of module "subprocess" (reportAttributeAccessIssue)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "STARTUPINFO" cannot be assigned to parameter "__value" of type "int | _Environ[str] | None" in function "__setitem__"   Type "STARTUPINFO" cannot be assigned to type "int | _Environ[str] | None"     "STARTUPINFO" is incompatible with "int"     "STARTUPINFO" is incompatible with "None"     "STARTUPINFO" is incompatible with "_Environ[str]" (reportArgumentType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "STARTUPINFO" cannot be assigned to parameter "__value" of type "int | _Environ[str] | None" in function "__setitem__"   Type "STARTUPINFO" cannot be assigned to type "int | _Environ[str] | None"     "STARTUPINFO" is incompatible with "int"     "STARTUPINFO" is incompatible with "None"     "STARTUPINFO" is incompatible with "_Environ[str]" (reportArgumentType)

Check failure on line 231 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "STARTUPINFO" cannot be assigned to parameter "__value" of type "int | _Environ[str] | None" in function "__setitem__"   Type "STARTUPINFO" cannot be assigned to type "int | _Environ[str] | None"     "STARTUPINFO" is incompatible with "int"     "STARTUPINFO" is incompatible with "None"     "STARTUPINFO" is incompatible with "_Environ[str]" (reportArgumentType)
kwargs["startupinfo"].dwFlags |= subprocess.STARTF_USESHOWWINDOW

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Type of "dwFlags" is unknown (reportUnknownMemberType)

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Type of "STARTF_USESHOWWINDOW" is unknown (reportUnknownMemberType)

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

"STARTF_USESHOWWINDOW" is not a known member of module "subprocess" (reportAttributeAccessIssue)

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Type of "dwFlags" is unknown (reportUnknownMemberType)

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Type of "STARTF_USESHOWWINDOW" is unknown (reportUnknownMemberType)

Check failure on line 232 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

"STARTF_USESHOWWINDOW" is not a known member of module "subprocess" (reportAttributeAccessIssue)
kwargs["startupinfo"].wShowWindow = subprocess.SW_HIDE

Check failure on line 233 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

Type of "SW_HIDE" is unknown (reportUnknownMemberType)

Check failure on line 233 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.10)

"SW_HIDE" is not a known member of module "subprocess" (reportAttributeAccessIssue)

Check failure on line 233 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

Type of "SW_HIDE" is unknown (reportUnknownMemberType)

Check failure on line 233 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (ubuntu-22.04, 3.11)

"SW_HIDE" is not a known member of module "subprocess" (reportAttributeAccessIssue)

return kwargs


def run_tesseract(png: bytes):
"""
Executes the tesseract CLI and pipes a PNG encoded image to it.

@param png: PNG encoded image as byte array
@return: The recognized output string from tesseract
"""
p = subprocess.Popen(TESSERACT_CMD, **subprocess_args()) # noqa: S603

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

No overloads for "__init__" match the provided arguments (reportCallIssue)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "bufsize" of type "int" in function "__init__"   Type "int | _Environ[str] | None" cannot be assigned to type "int"     "_Environ[str]" is incompatible with "int" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "executable" of type "StrOrBytesPath | None" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdin" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdout" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stderr" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.10)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "preexec_fn" of type "(() -> Any) | None" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

No overloads for "__init__" match the provided arguments (reportCallIssue)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "bufsize" of type "int" in function "__init__"   Type "int | _Environ[str] | None" cannot be assigned to type "int"     "_Environ[str]" is incompatible with "int" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "executable" of type "StrOrBytesPath | None" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdin" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdout" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stderr" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.12)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "preexec_fn" of type "(() -> Any) | None" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

No overloads for "__init__" match the provided arguments (reportCallIssue)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "bufsize" of type "int" in function "__init__"   Type "int | _Environ[str] | None" cannot be assigned to type "int"     "_Environ[str]" is incompatible with "int" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "executable" of type "StrOrBytesPath | None" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdin" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stdout" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "stderr" of type "_FILE" in function "__init__" (reportArgumentType)

Check failure on line 245 in src/utils.py

View workflow job for this annotation

GitHub Actions / Pyright (windows-latest, 3.11)

Argument of type "int | _Environ[str] | None" cannot be assigned to parameter "preexec_fn" of type "(() -> Any) | None" in function "__init__" (reportArgumentType)
Avasam marked this conversation as resolved.
Show resolved Hide resolved
output = p.communicate(input=png)[0]
return output.decode(DEFAULT_ENCODING)


# Environment specifics
WINDOWS_BUILD_NUMBER = int(version().split(".")[-1]) if sys.platform == "win32" else -1
FIRST_WIN_11_BUILD = 22000
Expand Down
Loading