Skip to content

Commit

Permalink
Fix all new issues (mostly line length)
Browse files Browse the repository at this point in the history
  • Loading branch information
Avasam committed Aug 15, 2024
1 parent 2fa4755 commit ea30b25
Show file tree
Hide file tree
Showing 17 changed files with 485 additions and 197 deletions.
146 changes: 112 additions & 34 deletions src/AutoSplit.py

Large diffs are not rendered by default.

27 changes: 22 additions & 5 deletions src/AutoSplitImage.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@
from cv2.typing import MatLike

import error_messages
from compare import check_if_image_has_transparency, extract_and_compare_text, get_comparison_method_by_index
from utils import BGR_CHANNEL_COUNT, MAXBYTE, TESSERACT_PATH, ColorChannel, ImageShape, imread, is_valid_image
from compare import (
check_if_image_has_transparency,
extract_and_compare_text,
get_comparison_method_by_index,
)
from utils import (
BGR_CHANNEL_COUNT,
MAXBYTE,
TESSERACT_PATH,
ColorChannel,
ImageShape,
imread,
is_valid_image,
)

if TYPE_CHECKING:
from AutoSplit import AutoSplit
Expand Down Expand Up @@ -153,9 +165,12 @@ def __read_image_bytes(self, path: str):
if self._has_transparency:
# Adaptively determine the target size according to
# the number of nonzero elements in the alpha channel of the split image.
# This may result in images bigger than COMPARISON_RESIZE if there's plenty of transparency.
# This may result in images bigger than COMPARISON_RESIZE if there's plenty of transparency. # noqa: E501
# Which wouldn't incur any performance loss in methods where masked regions are ignored.
scale = min(1, sqrt(COMPARISON_RESIZE_AREA / cv2.countNonZero(image[:, :, ColorChannel.Alpha])))
scale = min(
1,
sqrt(COMPARISON_RESIZE_AREA / cv2.countNonZero(image[:, :, ColorChannel.Alpha])),
)

image = cv2.resize(
image,
Expand Down Expand Up @@ -185,7 +200,9 @@ def compare_with_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.
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
Expand Down
9 changes: 4 additions & 5 deletions src/capture_method/BitBltCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,10 @@ def is_blank(image: MatLike):
class BitBltCaptureMethod(CaptureMethodBase):
name = "BitBlt"
short_description = "fastest, least compatible"
description = (
"\nThe best option when compatible. But it cannot properly record "
+ "\nOpenGL, Hardware Accelerated or Exclusive Fullscreen windows. "
+ "\nThe smaller the selected region, the more efficient it is. "
)
description = """
The best option when compatible. But it cannot properly record
OpenGL, Hardware Accelerated or Exclusive Fullscreen windows.
The smaller the selected region, the more efficient it is."""

_render_full_content = False

Expand Down
17 changes: 8 additions & 9 deletions src/capture_method/DesktopDuplicationCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,14 @@
class DesktopDuplicationCaptureMethod(BitBltCaptureMethod):
name = "Direct3D Desktop Duplication"
short_description = "slower, bound to display"
description = (
"\nDuplicates the desktop using Direct3D. "
+ "\nIt can record OpenGL and Hardware Accelerated windows. "
+ "\nAbout 10-15x slower than BitBlt. Not affected by window size. "
+ "\nOverlapping windows will show up and can't record across displays. "
+ "\nThis option may not be available for hybrid GPU laptops, "
+ "\nsee D3DDD-Note-Laptops.md for a solution. "
+ f"\nhttps://www.github.com/{GITHUB_REPOSITORY}#capture-method "
)
description = f"""
Duplicates the desktop using Direct3D.
It can record OpenGL and Hardware Accelerated windows.
About 10-15x slower than BitBlt. Not affected by window size.
Overlapping windows will show up and can't record across displays.
This option may not be available for hybrid GPU laptops,
see D3DDD-Note-Laptops.md for a solution.
https://www.github.com/{GITHUB_REPOSITORY}#capture-method"""

def __init__(self, autosplit: "AutoSplit"):
super().__init__(autosplit)
Expand Down
12 changes: 6 additions & 6 deletions src/capture_method/ForceFullContentRenderingCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
class ForceFullContentRenderingCaptureMethod(BitBltCaptureMethod):
name = "Force Full Content Rendering"
short_description = "very slow, can affect rendering"
description = (
"\nUses BitBlt behind the scene, but passes a special flag "
+ "\nto PrintWindow to force rendering the entire desktop. "
+ "\nAbout 10-15x slower than BitBlt based on original window size "
+ "\nand can mess up some applications' rendering pipelines. "
)
description = """
Uses BitBlt behind the scene, but passes a special flag
to PrintWindow to force rendering the entire desktop.
About 10-15x slower than BitBlt based on original window size
and can mess up some applications' rendering pipelines."""

_render_full_content = True
3 changes: 2 additions & 1 deletion src/capture_method/VideoCaptureDeviceCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ def __read_loop(self):
if not (
cv2_error.code == cv2.Error.STS_ERROR
and (
# Likely means the camera is occupied OR the camera index is out of range (like -1)
# Likely means the camera is occupied
# OR the camera index is out of range (like -1)
cv2_error.msg.endswith("in function 'cv::VideoCapture::grab'\n")
# Some capture cards we cannot use directly
# https://github.com/opencv/opencv/issues/23539
Expand Down
27 changes: 16 additions & 11 deletions src/capture_method/WindowsGraphicsCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@
from winsdk.windows.graphics.imaging import BitmapBufferAccessMode, SoftwareBitmap

from capture_method.CaptureMethodBase import CaptureMethodBase
from utils import BGRA_CHANNEL_COUNT, WGC_MIN_BUILD, WINDOWS_BUILD_NUMBER, get_direct3d_device, is_valid_hwnd
from utils import (
BGRA_CHANNEL_COUNT,
WGC_MIN_BUILD,
WINDOWS_BUILD_NUMBER,
get_direct3d_device,
is_valid_hwnd,
)

if TYPE_CHECKING:
from AutoSplit import AutoSplit
Expand All @@ -34,14 +40,13 @@ async def convert_d3d_surface_to_software_bitmap(surface: IDirect3DSurface | Non
class WindowsGraphicsCaptureMethod(CaptureMethodBase):
name = "Windows Graphics Capture"
short_description = "fast, most compatible, capped at 60fps"
description = (
f"\nOnly available in Windows 10.0.{WGC_MIN_BUILD} and up. "
+ f"\nDue to current technical limitations, Windows versions below 10.0.0.{LEARNING_MODE_DEVICE_BUILD}"
+ "\nrequire having at least one audio or video Capture Device connected and enabled."
+ "\nAllows recording UWP apps, Hardware Accelerated and Exclusive Fullscreen windows. "
+ "\nAdds a yellow border on Windows 10 (not on Windows 11)."
+ "\nCaps at around 60 FPS. "
)
description = f"""
Only available in Windows 10.0.{WGC_MIN_BUILD} and up.
Due to current technical limitations, Windows versions below 10.0.0.{LEARNING_MODE_DEVICE_BUILD}
require having at least one audio or video Capture Device connected and enabled.
Allows recording UWP apps, Hardware Accelerated and Exclusive Fullscreen windows.
Adds a yellow border on Windows 10 (not on Windows 11).
Caps at around 60 FPS."""

size: SizeInt32
frame_pool: Direct3D11CaptureFramePool | None = None
Expand Down Expand Up @@ -85,8 +90,8 @@ def close(self):
try:
self.session.close()
except OSError:
# OSError: The application called an interface that was marshalled for a different thread
# This still seems to close the session and prevent the following hard crash in LiveSplit
# OSError: The application called an interface that was marshalled for a different thread # noqa: E501
# This still seems to close the session and prevent the following hard crash in LiveSplit # noqa: E501
# "AutoSplit.exe <process started at 00:05:37.020 has terminated with 0xc0000409 (EXCEPTION_STACK_BUFFER_OVERRUN)>" # noqa: E501
pass
self.session = None
Expand Down
9 changes: 8 additions & 1 deletion src/capture_method/XcbCaptureMethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ def get_frame(self):
return None
offset_x = data["x"]
offset_y = data["y"]
# image = window.get_image(selection["x"], selection["y"], selection["width"], selection["height"], 1, 0)
# image = window.get_image(
# selection["x"],
# selection["y"],
# selection["width"],
# selection["height"],
# 1,
# 0,
# )

selection = self._autosplit_ref.settings_dict["capture_region"]
x = selection["x"] + offset_x
Expand Down
22 changes: 17 additions & 5 deletions src/capture_method/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@

from capture_method.CaptureMethodBase import CaptureMethodBase
from capture_method.VideoCaptureDeviceCaptureMethod import VideoCaptureDeviceCaptureMethod
from utils import WGC_MIN_BUILD, WINDOWS_BUILD_NUMBER, first, get_input_device_resolution, try_get_direct3d_device
from utils import (
WGC_MIN_BUILD,
WINDOWS_BUILD_NUMBER,
first,
get_input_device_resolution,
try_get_direct3d_device,
)

if sys.platform == "win32":
from _ctypes import COMError # noqa: PLC2701 # comtypes is untyped
Expand All @@ -19,7 +25,9 @@

from capture_method.BitBltCaptureMethod import BitBltCaptureMethod
from capture_method.DesktopDuplicationCaptureMethod import DesktopDuplicationCaptureMethod
from capture_method.ForceFullContentRenderingCaptureMethod import ForceFullContentRenderingCaptureMethod
from capture_method.ForceFullContentRenderingCaptureMethod import (
ForceFullContentRenderingCaptureMethod,
)
from capture_method.WindowsGraphicsCaptureMethod import WindowsGraphicsCaptureMethod

if sys.platform == "linux":
Expand Down Expand Up @@ -126,7 +134,8 @@ def __getitem__( # type:ignore[override] # pyright: ignore[reportIncompatibleMe
@override
def get(self, key: CaptureMethodEnum, default: object = None, /):
"""
Returns the `CaptureMethodBase` subclass for `CaptureMethodEnum` if `CaptureMethodEnum` is available,
Returns the `CaptureMethodBase` subclass for `CaptureMethodEnum`
if `CaptureMethodEnum` is available,
else defaults to the first available `CaptureMethodEnum`.
Returns `CaptureMethodBase` directly if there's no capture methods.
"""
Expand All @@ -139,7 +148,8 @@ def get(self, key: CaptureMethodEnum, default: object = None, /):
if sys.platform == "win32":
if ( # Windows Graphics Capture requires a minimum Windows Build
WINDOWS_BUILD_NUMBER >= WGC_MIN_BUILD
# Our current implementation of Windows Graphics Capture does not ensure we can get an ID3DDevice
# Our current implementation of Windows Graphics Capture
# does not ensure we can get an ID3DDevice
and try_get_direct3d_device()
):
CAPTURE_METHODS[CaptureMethodEnum.WINDOWS_GRAPHICS_CAPTURE] = WindowsGraphicsCaptureMethod
Expand All @@ -152,7 +162,9 @@ def get(self, key: CaptureMethodEnum, default: object = None, /):
pass
else:
CAPTURE_METHODS[CaptureMethodEnum.DESKTOP_DUPLICATION] = DesktopDuplicationCaptureMethod
CAPTURE_METHODS[CaptureMethodEnum.PRINTWINDOW_RENDERFULLCONTENT] = ForceFullContentRenderingCaptureMethod
CAPTURE_METHODS[CaptureMethodEnum.PRINTWINDOW_RENDERFULLCONTENT] = (
ForceFullContentRenderingCaptureMethod
)
elif sys.platform == "linux":
if features.check_feature(feature="xcb"):
CAPTURE_METHODS[CaptureMethodEnum.XCB] = XcbCaptureMethod
Expand Down
20 changes: 15 additions & 5 deletions src/compare.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
from cv2.typing import MatLike
from scipy import fft

from utils import BGRA_CHANNEL_COUNT, MAXBYTE, ColorChannel, ImageShape, is_valid_image, run_tesseract
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 @@ -85,8 +92,9 @@ def compare_template(source: MatLike, capture: MatLike, mask: MatLike | None = N

def __cv2_phash(image: MatLike, hash_size: int = 8, highfreq_factor: int = 4):
"""Implementation copied from https://github.com/JohannesBuchner/imagehash/blob/38005924fe9be17cfed145bbc6d83b09ef8be025/imagehash/__init__.py#L260 .""" # noqa: E501
# OpenCV has its own pHash comparison implementation in `cv2.img_hash`, but it requires contrib/extra modules
# and is innacurate unless we precompute the size with a specific interpolation.
# OpenCV has its own pHash comparison implementation in `cv2.img_hash`,
# but it requires contrib/extra modules and is inaccurate
# unless we precompute the size with a specific interpolation.
# See: https://github.com/opencv/opencv_contrib/issues/3295#issuecomment-1172878684
#
# pHash = cv2.img_hash.PHash.create()
Expand Down Expand Up @@ -185,14 +193,16 @@ def get_comparison_method_by_index(comparison_method_index: int):


def check_if_image_has_transparency(image: MatLike):
# Check if there's a transparency channel (4th channel) and if at least one pixel is transparent (< 255)
# Check if there's a transparency channel (4th channel)
# and if at least one pixel is transparent (< 255)
if image.shape[ImageShape.Channels] != BGRA_CHANNEL_COUNT:
return False
mean: float = image[:, :, ColorChannel.Alpha].mean()
if mean == 0:
# Non-transparent images code path is usually faster and simpler, so let's return that
return False
# TODO: error message if all pixels are transparent
# (the image appears as all black in windows, so it's not obvious for the user what they did wrong)
# (the image appears as all black in windows,
# so it's not obvious for the user what they did wrong)

return mean != MAXBYTE
Loading

0 comments on commit ea30b25

Please sign in to comment.