eye3 1.0.3__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
eye3/__init__.py ADDED
@@ -0,0 +1,25 @@
1
+ """eye3 - screen capture bypassing WDA_MONITOR/WDA_EXCLUDEFROMCAPTURE.
2
+
3
+ Windows x64 native binary bundled in the wheel.
4
+ """
5
+
6
+ from .binding import (
7
+ ThirdEyeError,
8
+ ThirdEyeOptions,
9
+ ThirdEyeSession,
10
+ ThirdeyeFormat,
11
+ ThirdeyeResult,
12
+ get_library_path,
13
+ )
14
+
15
+ __version__ = "1.0.0"
16
+
17
+ __all__ = [
18
+ "ThirdEyeError",
19
+ "ThirdEyeOptions",
20
+ "ThirdEyeSession",
21
+ "ThirdeyeFormat",
22
+ "ThirdeyeResult",
23
+ "get_library_path",
24
+ "__version__",
25
+ ]
eye3/binding.py ADDED
@@ -0,0 +1,165 @@
1
+ """ctypes binding to the bundled thirdeye.dll (Windows x64)."""
2
+
3
+ import ctypes
4
+ import os
5
+ import sys
6
+ from enum import IntEnum
7
+
8
+ _DLL_NAME = "thirdeye.dll"
9
+
10
+
11
+ def get_library_path() -> str:
12
+ """Absolute path to the bundled thirdeye.dll."""
13
+ path = os.path.join(os.path.dirname(__file__), _DLL_NAME)
14
+ if not os.path.exists(path):
15
+ raise ThirdEyeError(
16
+ f"thirdeye native library not found at {path}. "
17
+ "This wheel ships a Windows x64 binary only."
18
+ )
19
+ return path
20
+
21
+
22
+ class ThirdeyeResult(IntEnum):
23
+ OK = 0
24
+ ERROR_NOT_INITIALIZED = -1
25
+ ERROR_SYSCALL_INIT_FAILED = -2
26
+ ERROR_GDIPLUS_INIT_FAILED = -3
27
+ ERROR_ENCODER_NOT_FOUND = -4
28
+ ERROR_SAVE_FAILED = -5
29
+ ERROR_ALLOCATION_FAILED = -6
30
+ ERROR_INVALID_PARAM = -7
31
+ ERROR_NO_REMOTE_SECTION = -8
32
+
33
+
34
+ class ThirdeyeFormat(IntEnum):
35
+ JPEG = 0
36
+ PNG = 1
37
+ BMP = 2
38
+
39
+
40
+ class ThirdEyeError(RuntimeError):
41
+ """Raised when a thirdeye call returns a non-OK result."""
42
+
43
+ def __init__(self, result, message: str):
44
+ self.result = result
45
+ super().__init__(f"{message} (result={int(result)})")
46
+
47
+
48
+ class ThirdEyeOptions(ctypes.Structure):
49
+ _fields_ = [
50
+ ("format", ctypes.c_int),
51
+ ("quality", ctypes.c_int),
52
+ ("bypassProtection", ctypes.c_int),
53
+ ]
54
+
55
+ def __init__(self, format=ThirdeyeFormat.JPEG, quality=90, bypass_protection=True):
56
+ super().__init__(int(format), int(quality), 1 if bypass_protection else 0)
57
+
58
+
59
+ def _load():
60
+ if sys.platform != "win32":
61
+ raise ThirdEyeError(
62
+ ThirdeyeResult.ERROR_NOT_INITIALIZED,
63
+ "thirdeye is supported on Windows x64 only",
64
+ )
65
+ lib = ctypes.WinDLL(get_library_path())
66
+
67
+ lib.Thirdeye_CreateContext.argtypes = [ctypes.POINTER(ctypes.c_void_p)]
68
+ lib.Thirdeye_CreateContext.restype = ctypes.c_int
69
+
70
+ lib.Thirdeye_DestroyContext.argtypes = [ctypes.c_void_p]
71
+ lib.Thirdeye_DestroyContext.restype = None
72
+
73
+ lib.Thirdeye_GetDefaultOptions.argtypes = [ctypes.POINTER(ThirdEyeOptions)]
74
+ lib.Thirdeye_GetDefaultOptions.restype = None
75
+
76
+ lib.Thirdeye_CaptureToFile.argtypes = [
77
+ ctypes.c_void_p,
78
+ ctypes.c_wchar_p,
79
+ ctypes.POINTER(ThirdEyeOptions),
80
+ ]
81
+ lib.Thirdeye_CaptureToFile.restype = ctypes.c_int
82
+
83
+ lib.Thirdeye_CaptureToBuffer.argtypes = [
84
+ ctypes.c_void_p,
85
+ ctypes.POINTER(ctypes.POINTER(ctypes.c_uint8)),
86
+ ctypes.POINTER(ctypes.c_uint32),
87
+ ctypes.POINTER(ThirdEyeOptions),
88
+ ]
89
+ lib.Thirdeye_CaptureToBuffer.restype = ctypes.c_int
90
+
91
+ lib.Thirdeye_FreeBuffer.argtypes = [ctypes.POINTER(ctypes.c_uint8)]
92
+ lib.Thirdeye_FreeBuffer.restype = None
93
+
94
+ lib.Thirdeye_GetLastError.argtypes = [ctypes.c_void_p]
95
+ lib.Thirdeye_GetLastError.restype = ctypes.c_char_p
96
+
97
+ lib.Thirdeye_GetVersion.argtypes = []
98
+ lib.Thirdeye_GetVersion.restype = ctypes.c_char_p
99
+
100
+ return lib
101
+
102
+
103
+ class ThirdEyeSession:
104
+ """Thread-safe-ish capture session. Use as a context manager."""
105
+
106
+ def __init__(self):
107
+ self._lib = _load()
108
+ self._ctx = ctypes.c_void_p()
109
+ rc = ThirdeyeResult(self._lib.Thirdeye_CreateContext(ctypes.byref(self._ctx)))
110
+ if rc != ThirdeyeResult.OK or not self._ctx:
111
+ raise ThirdEyeError(rc, "Thirdeye_CreateContext failed")
112
+
113
+ def default_options(self) -> ThirdEyeOptions:
114
+ opts = ThirdEyeOptions()
115
+ self._lib.Thirdeye_GetDefaultOptions(ctypes.byref(opts))
116
+ return opts
117
+
118
+ def capture_to_file(self, file_path: str, options: ThirdEyeOptions = None) -> None:
119
+ opts = options or self.default_options()
120
+ rc = ThirdeyeResult(
121
+ self._lib.Thirdeye_CaptureToFile(self._ctx, file_path, ctypes.byref(opts))
122
+ )
123
+ if rc != ThirdeyeResult.OK:
124
+ raise ThirdEyeError(rc, f"Thirdeye_CaptureToFile failed: {self.last_error()}")
125
+
126
+ def capture_to_buffer(self, options: ThirdEyeOptions = None) -> bytes:
127
+ opts = options or self.default_options()
128
+ buf = ctypes.POINTER(ctypes.c_uint8)()
129
+ size = ctypes.c_uint32(0)
130
+ rc = ThirdeyeResult(
131
+ self._lib.Thirdeye_CaptureToBuffer(
132
+ self._ctx, ctypes.byref(buf), ctypes.byref(size), ctypes.byref(opts)
133
+ )
134
+ )
135
+ if rc != ThirdeyeResult.OK or not buf or size.value == 0:
136
+ raise ThirdEyeError(rc, f"Thirdeye_CaptureToBuffer failed: {self.last_error()}")
137
+ try:
138
+ return ctypes.string_at(buf, size.value)
139
+ finally:
140
+ self._lib.Thirdeye_FreeBuffer(buf)
141
+
142
+ def last_error(self) -> str:
143
+ err = self._lib.Thirdeye_GetLastError(self._ctx)
144
+ return err.decode("utf-8", "replace") if err else ""
145
+
146
+ def version(self) -> str:
147
+ v = self._lib.Thirdeye_GetVersion()
148
+ return v.decode("utf-8", "replace") if v else ""
149
+
150
+ def close(self) -> None:
151
+ if self._ctx:
152
+ self._lib.Thirdeye_DestroyContext(self._ctx)
153
+ self._ctx = ctypes.c_void_p()
154
+
155
+ def __enter__(self) -> "ThirdEyeSession":
156
+ return self
157
+
158
+ def __exit__(self, *exc) -> None:
159
+ self.close()
160
+
161
+ def __del__(self):
162
+ try:
163
+ self.close()
164
+ except Exception:
165
+ pass
eye3/thirdeye.dll ADDED
Binary file
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.4
2
+ Name: eye3
3
+ Version: 1.0.3
4
+ Summary: Screen capture library bypassing WDA_MONITOR/WDA_EXCLUDEFROMCAPTURE (Windows x64 native binary)
5
+ Author: Matěj "lofcz" Štágl
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/lofcz/thirdeye
8
+ Project-URL: Repository, https://github.com/lofcz/thirdeye
9
+ Keywords: screenshot,screen-capture,windows,display-affinity,native
10
+ Classifier: Operating System :: Microsoft :: Windows
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Requires-Python: >=3.8
14
+ Description-Content-Type: text/markdown
15
+
16
+ # eye3
17
+
18
+ Screen capture library bypassing `WDA_MONITOR` / `WDA_EXCLUDEFROMCAPTURE` (Windows x64 native binary).
19
+
20
+ ```python
21
+ from eye3 import ThirdEyeSession
22
+
23
+ with ThirdEyeSession() as session:
24
+ session.capture_to_file("screenshot.png")
25
+ ```
26
+
27
+ Options:
28
+
29
+ ```python
30
+ from eye3 import ThirdEyeSession, ThirdEyeOptions, ThirdeyeFormat
31
+
32
+ with ThirdEyeSession() as session:
33
+ opts = ThirdEyeOptions(format=ThirdeyeFormat.JPEG, quality=90, bypass_protection=True)
34
+ session.capture_to_file("screenshot.jpeg", opts)
35
+
36
+ data: bytes = session.capture_to_buffer()
37
+ ```
38
+
39
+ Windows x64 only. Ships the native `thirdeye.dll` inside the wheel.
@@ -0,0 +1,7 @@
1
+ eye3/__init__.py,sha256=hK74N2PEZpfUluBBfGYJr2Gsog0iQxURyx2GYCz4xuM,490
2
+ eye3/binding.py,sha256=oeCgba14y4xIoqEmiEust80744CNzOt_P-Ng41y0ws8,5356
3
+ eye3/thirdeye.dll,sha256=y3Yn-rvM2_7Fp_tEGPpciQYK4WRk-UsbzgX5Wm5X3T0,1071104
4
+ eye3-1.0.3.dist-info/METADATA,sha256=GjgPkt5THKMPR2HbuR6krlYBtVz3qzAySZwrVzdHfr4,1264
5
+ eye3-1.0.3.dist-info/WHEEL,sha256=hVx9elvUDfBjRmbl8JwIcXXikst35RZTZK9nspfI_28,98
6
+ eye3-1.0.3.dist-info/top_level.txt,sha256=49LwWwD5uM6wMwG-L9vs2w9tuJhPp01JvO51MR0jads,5
7
+ eye3-1.0.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
5
+
@@ -0,0 +1 @@
1
+ eye3