|
2 | 2 | Module for image recognition on the screen. |
3 | 3 | """ |
4 | 4 |
|
| 5 | +import contextlib |
5 | 6 | from dataclasses import dataclass |
| 7 | +import os |
| 8 | +import sys |
6 | 9 |
|
7 | 10 | import cv2 |
8 | 11 | from cv2.typing import MatLike |
|
15 | 18 | from alune.images import Coordinate |
16 | 19 | from alune.images import ImageButton |
17 | 20 |
|
| 21 | +# libpng warnings that are safe to ignore (cosmetic metadata issues, not actual image problems) |
| 22 | +_IGNORABLE_STDERR_PATTERNS = [ |
| 23 | + "libpng warning:", |
| 24 | +] |
| 25 | + |
| 26 | + |
| 27 | +@contextlib.contextmanager |
| 28 | +def _filter_stderr(): |
| 29 | + """Capture stderr during cv2.imread and filter out known harmless warnings, logging the rest.""" |
| 30 | + try: |
| 31 | + stderr_fd = sys.stderr.fileno() |
| 32 | + except (OSError, ValueError): |
| 33 | + # No real file descriptor (e.g., some IDEs), just proceed without filtering |
| 34 | + yield |
| 35 | + return |
| 36 | + |
| 37 | + # Create a pipe to capture stderr |
| 38 | + read_fd, write_fd = os.pipe() |
| 39 | + original_stderr_fd = os.dup(stderr_fd) |
| 40 | + |
| 41 | + try: |
| 42 | + sys.stderr.flush() |
| 43 | + os.dup2(write_fd, stderr_fd) |
| 44 | + yield |
| 45 | + finally: |
| 46 | + sys.stderr.flush() |
| 47 | + os.dup2(original_stderr_fd, stderr_fd) |
| 48 | + os.close(original_stderr_fd) |
| 49 | + os.close(write_fd) |
| 50 | + |
| 51 | + # Read captured output |
| 52 | + with os.fdopen(read_fd, "r", errors="replace") as captured: |
| 53 | + for line in captured: |
| 54 | + line = line.strip() |
| 55 | + if not line: |
| 56 | + continue |
| 57 | + # Check if this is a known ignorable warning |
| 58 | + if any(pattern in line for pattern in _IGNORABLE_STDERR_PATTERNS): |
| 59 | + continue |
| 60 | + # Log unexpected stderr output so we don't miss real issues |
| 61 | + logger.warning(f"Unexpected stderr during image load: {line}") |
| 62 | + |
18 | 63 |
|
19 | 64 | @dataclass |
20 | 65 | class ImageSearchResult(Coordinate): |
@@ -61,7 +106,8 @@ def get_image_from_path(path: str) -> MatLike | None: |
61 | 106 | Returns: |
62 | 107 | The image or none if it does not exist. |
63 | 108 | """ |
64 | | - image_to_find = cv2.imread(path, 0) |
| 109 | + with _filter_stderr(): |
| 110 | + image_to_find = cv2.imread(path, 0) |
65 | 111 |
|
66 | 112 | if image_to_find is None: |
67 | 113 | logger.warning(f"The image {path} does not exist on the system, or we do not have permission to read it.") |
|
0 commit comments