ascript 1.3.27__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.
Files changed (177) hide show
  1. ascript/__init__.py +8 -0
  2. ascript/hooks/__init__.py +0 -0
  3. ascript/hooks/hook-ascript.py +2 -0
  4. ascript/windows/__init__.py +29 -0
  5. ascript/windows/daos/__init__.py +0 -0
  6. ascript/windows/daos/screen.py +143 -0
  7. ascript/windows/hardware/__init__.py +5 -0
  8. ascript/windows/hardware/keyboard.py +279 -0
  9. ascript/windows/hardware/logitech_driver.py +179 -0
  10. ascript/windows/hardware/mouse.py +308 -0
  11. ascript/windows/license/__init__.py +16 -0
  12. ascript/windows/license/achttp.cp310-win_amd64.pyd +0 -0
  13. ascript/windows/license/achttp.cp311-win_amd64.pyd +0 -0
  14. ascript/windows/license/achttp.cp312-win_amd64.pyd +0 -0
  15. ascript/windows/license/achttp.cp313-win_amd64.pyd +0 -0
  16. ascript/windows/license/achttp.cp314-win_amd64.pyd +0 -0
  17. ascript/windows/license/achttp.cp38-win_amd64.pyd +0 -0
  18. ascript/windows/license/achttp.cp39-win_amd64.pyd +0 -0
  19. ascript/windows/media/__init__.py +0 -0
  20. ascript/windows/resources/__init__.py +0 -0
  21. ascript/windows/resources/libs/logitech/x64/LogitechGkeyEnginesWrapper.dll +0 -0
  22. ascript/windows/resources/libs/logitech/x86/LogitechGkeyEnginesWrapper.dll +0 -0
  23. ascript/windows/resources/templates/__init__.py +0 -0
  24. ascript/windows/resources/templates/__init__py.win.template +51 -0
  25. ascript/windows/resources/templates/build.as.win.template +14 -0
  26. ascript/windows/resources/templates/build.py +71 -0
  27. ascript/windows/resources/templates/logo_windows.ico +0 -0
  28. ascript/windows/resources/templates/windows/main.py +50 -0
  29. ascript/windows/resources/templates/windows/pyproject.toml +44 -0
  30. ascript/windows/resources/templates/windows/res/img/logo.ico +0 -0
  31. ascript/windows/screen/__init__.py +13 -0
  32. ascript/windows/screen/as_cv.py +382 -0
  33. ascript/windows/screen/canny.py +128 -0
  34. ascript/windows/screen/code_scanner.py +72 -0
  35. ascript/windows/screen/color_algorithms.py +277 -0
  36. ascript/windows/screen/find_colors.py +251 -0
  37. ascript/windows/screen/find_images.py +217 -0
  38. ascript/windows/screen/ocr/__init__.py +4 -0
  39. ascript/windows/screen/ocr/ocr.py +223 -0
  40. ascript/windows/screen/ocr/rapidocr_hook.py +301 -0
  41. ascript/windows/screen/ocrx.py +169 -0
  42. ascript/windows/screen/screen_core.py +139 -0
  43. ascript/windows/store/__init__.py +21 -0
  44. ascript/windows/system/__init__.py +8 -0
  45. ascript/windows/system/device.py +355 -0
  46. ascript/windows/system/easy_print.py +115 -0
  47. ascript/windows/system/env.py +492 -0
  48. ascript/windows/system/exception/__init__.py +1 -0
  49. ascript/windows/system/key_value.py +145 -0
  50. ascript/windows/system/pip.py +175 -0
  51. ascript/windows/system/r.py +165 -0
  52. ascript/windows/system/runtime.py +62 -0
  53. ascript/windows/tools/__init__.py +27 -0
  54. ascript/windows/tools/__main__.py +21 -0
  55. ascript/windows/tools/action.json +33 -0
  56. ascript/windows/tools/action.py +168 -0
  57. ascript/windows/tools/colors_tool.py +391 -0
  58. ascript/windows/tools/config.py +26 -0
  59. ascript/windows/tools/dumptool.py +18 -0
  60. ascript/windows/tools/eel_api.py +495 -0
  61. ascript/windows/tools/gpplug/__init__.py +0 -0
  62. ascript/windows/tools/gpplug/plug.py +70 -0
  63. ascript/windows/tools/mouse_catch.py +168 -0
  64. ascript/windows/tools/plug_manager.py +38 -0
  65. ascript/windows/tools/tool_api.py +906 -0
  66. ascript/windows/tools/tool_window.py +56 -0
  67. ascript/windows/tools/uia_worker.py +365 -0
  68. ascript/windows/tools/web/app_store_window.html +481 -0
  69. ascript/windows/tools/web/colors.html +532 -0
  70. ascript/windows/tools/web/css/screen.css +1342 -0
  71. ascript/windows/tools/web/css/viewtree.css +357 -0
  72. ascript/windows/tools/web/flot_control.html +195 -0
  73. ascript/windows/tools/web/img/ico/favicon.png +0 -0
  74. ascript/windows/tools/web/img/ico/paintpalette.png +0 -0
  75. ascript/windows/tools/web/img/svg/find_colors.svg +1 -0
  76. ascript/windows/tools/web/img/svg/find_images.svg +1 -0
  77. ascript/windows/tools/web/img/svg/illustration-6.svg +89 -0
  78. ascript/windows/tools/web/img/svg/img_default.svg +1 -0
  79. ascript/windows/tools/web/img/svg/ocr.svg +1 -0
  80. ascript/windows/tools/web/js/screen/colors.js +466 -0
  81. ascript/windows/tools/web/js/screen/gp_plug.js +108 -0
  82. ascript/windows/tools/web/js/screen/image_mouse.js +464 -0
  83. ascript/windows/tools/web/js/screen/img_view.js +558 -0
  84. ascript/windows/tools/web/js/screen/plug.js +246 -0
  85. ascript/windows/tools/web/js/screen/screen.js +690 -0
  86. ascript/windows/tools/web/js/screen/screen_api.js +778 -0
  87. ascript/windows/tools/web/js/screen/screen_maker.js +10 -0
  88. ascript/windows/tools/web/js/utils/map.js +73 -0
  89. ascript/windows/tools/web/js/utils/upload.js +157 -0
  90. ascript/windows/tools/web/js/viewtree/niv_js.js +27 -0
  91. ascript/windows/tools/web/js/viewtree/vtree.js +1510 -0
  92. ascript/windows/tools/web/libs/bootstrap/css/bootstrap.min.css +6 -0
  93. ascript/windows/tools/web/libs/bootstrap/js/bootstrap.bundle.min.js +7 -0
  94. ascript/windows/tools/web/libs/bootstrap-icons/0-circle.svg +4 -0
  95. ascript/windows/tools/web/libs/bootstrap-icons/0-square.svg +4 -0
  96. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.css +2078 -0
  97. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.json +2052 -0
  98. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.min.css +5 -0
  99. ascript/windows/tools/web/libs/bootstrap-icons/font/bootstrap-icons.scss +2090 -0
  100. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff +0 -0
  101. ascript/windows/tools/web/libs/bootstrap-icons/font/fonts/bootstrap-icons.woff2 +0 -0
  102. ascript/windows/tools/web/libs/feather-icons/dist/feather.min.js +13 -0
  103. ascript/windows/tools/web/libs/feather-icons/dist/icons.json +1 -0
  104. ascript/windows/tools/web/libs/jquery/core.js +399 -0
  105. ascript/windows/tools/web/libs/jquery/jquery.js +10598 -0
  106. ascript/windows/tools/web/libs/jquery/jquery.min.js +4 -0
  107. ascript/windows/tools/web/libs/jquery/jquery.min.js.zip +0 -0
  108. ascript/windows/tools/web/libs/jquery/jquery.slim.js +8495 -0
  109. ascript/windows/tools/web/libs/jquery/jquery.slim.min.js +2 -0
  110. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.js +2134 -0
  111. ascript/windows/tools/web/libs/jquery-menu/jquery.contextMenu.min.css +16 -0
  112. ascript/windows/tools/web/libs/jquery-zTree/css/zTreeStyle.css +97 -0
  113. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_close.png +0 -0
  114. ascript/windows/tools/web/libs/jquery-zTree/img/diy/1_open.png +0 -0
  115. ascript/windows/tools/web/libs/jquery-zTree/img/diy/2.png +0 -0
  116. ascript/windows/tools/web/libs/jquery-zTree/img/diy/3.png +0 -0
  117. ascript/windows/tools/web/libs/jquery-zTree/img/diy/4.png +0 -0
  118. ascript/windows/tools/web/libs/jquery-zTree/img/diy/5.png +0 -0
  119. ascript/windows/tools/web/libs/jquery-zTree/img/diy/6.png +0 -0
  120. ascript/windows/tools/web/libs/jquery-zTree/img/diy/7.png +0 -0
  121. ascript/windows/tools/web/libs/jquery-zTree/img/diy/8.png +0 -0
  122. ascript/windows/tools/web/libs/jquery-zTree/img/diy/9.png +0 -0
  123. ascript/windows/tools/web/libs/jquery-zTree/img/line_conn.gif +0 -0
  124. ascript/windows/tools/web/libs/jquery-zTree/img/loading.gif +0 -0
  125. ascript/windows/tools/web/libs/jquery-zTree/img/tree-node-btn.png +0 -0
  126. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.gif +0 -0
  127. ascript/windows/tools/web/libs/jquery-zTree/img/zTreeStandard.png +0 -0
  128. ascript/windows/tools/web/libs/jquery-zTree/js/jquery.ztree.all.min.js +3 -0
  129. ascript/windows/tools/web/libs/treeview/css/jquery.treeview.css +79 -0
  130. ascript/windows/tools/web/libs/treeview/img/file.png +0 -0
  131. ascript/windows/tools/web/libs/treeview/img/ico_loading.png +0 -0
  132. ascript/windows/tools/web/libs/treeview/img/icon4.png +0 -0
  133. ascript/windows/tools/web/libs/treeview/img/icon5.png +0 -0
  134. ascript/windows/tools/web/libs/treeview/img/icon6.png +0 -0
  135. ascript/windows/tools/web/libs/treeview/img/py.png +0 -0
  136. ascript/windows/tools/web/libs/treeview/img/treeview-black-line.gif +0 -0
  137. ascript/windows/tools/web/libs/treeview/img/treeview-black.gif +0 -0
  138. ascript/windows/tools/web/libs/treeview/img/treeview-default-line.gif +0 -0
  139. ascript/windows/tools/web/libs/treeview/img/treeview-default.gif +0 -0
  140. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam-line.gif +0 -0
  141. ascript/windows/tools/web/libs/treeview/img/treeview-famfamfam.gif +0 -0
  142. ascript/windows/tools/web/libs/treeview/img/treeview-gray-line.gif +0 -0
  143. ascript/windows/tools/web/libs/treeview/img/treeview-gray.gif +0 -0
  144. ascript/windows/tools/web/libs/treeview/img/treeview-red-line.gif +0 -0
  145. ascript/windows/tools/web/libs/treeview/img/treeview-red.gif +0 -0
  146. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.edit.js +37 -0
  147. ascript/windows/tools/web/libs/treeview/js/jquery.treeview.js +250 -0
  148. ascript/windows/tools/web/license_window.html +255 -0
  149. ascript/windows/tools/web/plugs/a.html +653 -0
  150. ascript/windows/tools/web/plugs/demo.html +52 -0
  151. ascript/windows/tools/web/plugs/find_colors.html +629 -0
  152. ascript/windows/tools/web/plugs/find_images.html +699 -0
  153. ascript/windows/tools/web/plugs/rapidocr.html +954 -0
  154. ascript/windows/tools/web/vtree.html +496 -0
  155. ascript/windows/tools/webview/assets/index-HymBPl-I.css +1 -0
  156. ascript/windows/tools/webview/assets/index-PqA_m8tL.js +17 -0
  157. ascript/windows/tools/webview/index.html +13 -0
  158. ascript/windows/ui/__init__.py +6 -0
  159. ascript/windows/ui/app_store_window.py +272 -0
  160. ascript/windows/ui/draw_window.py +231 -0
  161. ascript/windows/ui/flot_test.py +297 -0
  162. ascript/windows/ui/flot_window.py +488 -0
  163. ascript/windows/ui/license_window.py +111 -0
  164. ascript/windows/ui/web_window.py +466 -0
  165. ascript/windows/utils/__init__.py +0 -0
  166. ascript/windows/utils/node_utils.py +20 -0
  167. ascript/windows/utils/screen_utils.py +280 -0
  168. ascript/windows/window/Selector.py +1015 -0
  169. ascript/windows/window/Window.py +747 -0
  170. ascript/windows/window/__init__.py +5 -0
  171. ascript/windows/window/launcher.py +213 -0
  172. ascript/windows/window/uia_runtime.py +26 -0
  173. ascript-1.3.27.dist-info/METADATA +41 -0
  174. ascript-1.3.27.dist-info/RECORD +177 -0
  175. ascript-1.3.27.dist-info/WHEEL +5 -0
  176. ascript-1.3.27.dist-info/entry_points.txt +2 -0
  177. ascript-1.3.27.dist-info/top_level.txt +1 -0
@@ -0,0 +1,699 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <title>Visual Finder - Compact</title>
7
+ <script>
8
+ (function () {
9
+ const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
10
+ document.documentElement.setAttribute('data-bs-theme', isDark ? 'dark' : 'light');
11
+ })();
12
+ </script>
13
+ <link href="../libs/bootstrap/css/bootstrap.min.css" rel="stylesheet">
14
+ <link href="../libs/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
15
+ <style>
16
+ :root {
17
+ --editor-bg: #1e1e1e;
18
+ --panel-bg: #252526;
19
+ --border-color: #333333;
20
+ --accent-color: #007acc;
21
+ }
22
+
23
+ body,
24
+ html {
25
+ height: 100vh;
26
+ margin: 0;
27
+ font-size: 13px;
28
+ overflow: hidden;
29
+ background: var(--editor-bg);
30
+ color: #cccccc;
31
+ }
32
+
33
+ .main-layout {
34
+ display: flex;
35
+ height: 100vh;
36
+ }
37
+
38
+ .settings-panel {
39
+ width: 280px;
40
+ background: var(--panel-bg);
41
+ border-right: 1px solid var(--border-color);
42
+ display: flex;
43
+ flex-direction: column;
44
+ padding: 16px;
45
+ }
46
+
47
+ .form-label {
48
+ color: #858585;
49
+ font-weight: 600;
50
+ font-size: 11px;
51
+ text-transform: uppercase;
52
+ margin-bottom: 8px;
53
+ }
54
+
55
+ .form-select,
56
+ .form-control {
57
+ background-color: #3c3c3c;
58
+ border: 1px solid #3c3c3c;
59
+ color: #eee;
60
+ border-radius: 2px;
61
+ height: 28px;
62
+ font-size: 12px;
63
+ padding: 0 8px;
64
+ }
65
+
66
+ .btn-vscode {
67
+ background: var(--accent-color);
68
+ color: white;
69
+ border-radius: 2px;
70
+ border: none;
71
+ font-size: 12px;
72
+ height: 32px;
73
+ transition: 0.2s;
74
+ }
75
+
76
+ .btn-vscode:hover {
77
+ background: #118ad4;
78
+ }
79
+
80
+ .btn-outline-vscode {
81
+ border: 1px solid #454545;
82
+ color: #cccccc;
83
+ border-radius: 2px;
84
+ font-size: 12px;
85
+ height: 32px;
86
+ }
87
+
88
+ /* 结果容器布局 */
89
+ .results-container {
90
+ flex: 1;
91
+ display: flex;
92
+ flex-direction: column;
93
+ min-height: 0;
94
+ margin-top: 15px;
95
+ }
96
+
97
+ .results-header {
98
+ display: flex;
99
+ justify-content: space-between;
100
+ align-items: center;
101
+ margin-bottom: 8px;
102
+ }
103
+
104
+ .results-list {
105
+ flex: 1;
106
+ overflow-y: auto;
107
+ background: #1e1e1e;
108
+ border: 1px solid var(--border-color);
109
+ border-radius: 2px;
110
+ }
111
+
112
+ .result-item {
113
+ padding: 10px;
114
+ border-bottom: 1px solid #333;
115
+ cursor: pointer;
116
+ transition: 0.2s;
117
+ }
118
+
119
+ .result-item:hover,
120
+ .result-item.active {
121
+ background: #2a2d2e;
122
+ border-left: 3px solid var(--accent-color);
123
+ }
124
+
125
+ .result-item .conf-text {
126
+ color: #4ec9b0;
127
+ font-weight: bold;
128
+ }
129
+
130
+ .result-item .coord-text {
131
+ color: #858585;
132
+ font-size: 11px;
133
+ margin-top: 4px;
134
+ }
135
+
136
+ /* 清空按钮小图标样式 */
137
+ .btn-clear-results {
138
+ padding: 2px 6px;
139
+ font-size: 14px;
140
+ color: #858585;
141
+ cursor: pointer;
142
+ transition: color 0.2s;
143
+ }
144
+
145
+ .btn-clear-results:hover {
146
+ color: #f44336;
147
+ }
148
+
149
+ .workspace {
150
+ flex: 1;
151
+ display: flex;
152
+ flex-direction: column;
153
+ }
154
+
155
+ .canvas-area {
156
+ flex: 1;
157
+ background-color: #1e1e1e;
158
+ background-image:
159
+ linear-gradient(45deg, #252525 25%, transparent 25%), linear-gradient(-45deg, #252525 25%, transparent 25%),
160
+ linear-gradient(45deg, transparent 75%, #252525 75%), linear-gradient(-45deg, transparent 75%, #252525 75%);
161
+ background-size: 16px 16px;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ overflow: auto;
166
+ }
167
+
168
+ .img-viewport {
169
+ border: 1px solid var(--border-color);
170
+ box-shadow: 0 0 15px rgba(0, 0, 0, 0.4);
171
+ background: #000;
172
+ }
173
+
174
+ #preview-img {
175
+ max-width: 100%;
176
+ display: block;
177
+ }
178
+
179
+ .code-console {
180
+ height: 35%;
181
+ background: var(--editor-bg);
182
+ border-top: 1px solid var(--border-color);
183
+ display: flex;
184
+ flex-direction: column;
185
+ }
186
+
187
+ .console-header {
188
+ padding: 4px 16px;
189
+ background: var(--panel-bg);
190
+ border-bottom: 1px solid var(--border-color);
191
+ display: flex;
192
+ justify-content: space-between;
193
+ align-items: center;
194
+ }
195
+
196
+ .code-display {
197
+ flex: 1;
198
+ padding: 12px;
199
+ font-family: 'Consolas', monospace;
200
+ font-size: 12px;
201
+ color: #d4d4d4;
202
+ overflow: auto;
203
+ white-space: pre-wrap;
204
+ }
205
+ </style>
206
+ </head>
207
+
208
+ <body>
209
+
210
+ <div class="main-layout">
211
+ <div class="settings-panel">
212
+ <div class="mb-3">
213
+ <label class="form-label">匹配算法</label>
214
+ <select class="form-select" id="select-algo">
215
+ <option value="template">Template Match</option>
216
+ <option value="akaze">AKAZE Feature</option>
217
+ </select>
218
+ </div>
219
+
220
+ <div class="mb-3">
221
+ <label class="form-label">相似度阈值(<span id="threshold-val">0.80</span>)</label>
222
+ <input type="range" class="form-range" id="threshold" min="0" max="100" value="80">
223
+ </div>
224
+
225
+ <div class="mb-3 d-flex align-items-center justify-content-between" id="row-rgb">
226
+ <label class="form-label mb-0">RGB 匹配</label>
227
+ <div class="form-check form-switch">
228
+ <input class="form-check-input" type="checkbox" role="switch" id="check-rgb">
229
+ </div>
230
+ </div>
231
+
232
+ <div class="mb-3 d-flex align-items-center justify-content-between" id="row-resnum">
233
+ <label class="form-label mb-0">多个匹配结果</label>
234
+ <div class="form-check form-switch">
235
+ <input class="form-check-input" type="checkbox" role="switch" id="check-resnum" checked>
236
+ </div>
237
+ </div>
238
+
239
+ <div class="mb-3 d-none align-items-center justify-content-between" id="row-min-match">
240
+ <label class="form-label mb-0">最小匹配点数</label>
241
+ <input type="number" class="form-control form-control-sm" id="input-min-match" value="10" min="1"
242
+ style="width: 80px; background: #3c3c3c; color: white; border: 1px solid #666; text-align: center;">
243
+ </div>
244
+
245
+ <div class="d-grid gap-2 mb-2">
246
+ <button class="btn btn-vscode" id="btn-test">
247
+ <i class="bi bi-play-fill me-1"></i>测试找图
248
+ </button>
249
+ <button class="btn btn-outline-vscode" id="btn-save">
250
+ <i class="bi bi-hdd me-1"></i>模板图另存为
251
+ </button>
252
+ </div>
253
+
254
+ <div class="results-container">
255
+ <div class="results-header">
256
+ <div class="d-flex align-items-center">
257
+ <span class="form-label m-0 me-2">识别结果</span>
258
+ <span class="badge bg-secondary" id="results-count" style="font-size: 10px;">0</span>
259
+ </div>
260
+ <i class="bi bi-trash btn-clear-results" id="btn-clear" title="清空结果"></i>
261
+ </div>
262
+ <div class="results-list" id="results-list">
263
+ <div class="text-center text-muted py-4 opacity-50">暂无测试结果</div>
264
+ </div>
265
+ </div>
266
+
267
+ <div class="mt-auto border-top pt-2 border-secondary opacity-50">
268
+ <div class="small text-muted" style="font-size: 10px;">Visual Finder v2.0</div>
269
+ </div>
270
+ </div>
271
+
272
+ <div class="workspace">
273
+ <div class="canvas-area">
274
+ <div class="img-viewport">
275
+ <img id="preview-img" src="https://via.placeholder.com/300x150?text=Wait+for+Selection" />
276
+ </div>
277
+ </div>
278
+
279
+ <div class="code-console">
280
+ <div class="console-header">
281
+ <span class="small fw-bold opacity-50 text-uppercase" style="font-size: 10px;">Python Script</span>
282
+ <button class="btn btn-link btn-sm text-decoration-none text-secondary p-0" id="btn-copy">
283
+ <i class="bi bi-files me-1"></i>Copy
284
+ </button>
285
+ </div>
286
+ <div class="code-display" id="python-code"></div>
287
+ </div>
288
+ </div>
289
+ </div>
290
+
291
+ <script src="../libs/jquery/jquery.min.js"></script>
292
+ <script src="../libs/bootstrap/js/bootstrap.bundle.min.js"></script>
293
+
294
+ <script>
295
+ // 1. 定义你的处理方法
296
+ function onConfigChange() {
297
+ const config = {
298
+ algo: document.getElementById('select-algo').value,
299
+ threshold: document.getElementById('threshold').value / 100,
300
+ useRGB: document.getElementById('check-rgb').checked,
301
+ multiMatch: document.getElementById('check-resnum').checked,
302
+ minMatch: document.getElementById('input-min-match').value
303
+ };
304
+
305
+ genCode();
306
+ // 在这里执行你后续的业务逻辑
307
+ }
308
+
309
+ window.on_image_loaded = (d) => {genCode(); };
310
+
311
+ // 2. 编写监听方法
312
+ function initListeners() {
313
+ // 列出所有需要监听的 ID
314
+ const controlIds = [
315
+ 'select-algo',
316
+ 'threshold',
317
+ 'check-rgb',
318
+ 'check-resnum',
319
+ 'input-min-match'
320
+ ];
321
+
322
+ controlIds.forEach(id => {
323
+ const el = document.getElementById(id);
324
+ if (!el) return;
325
+
326
+ // 'input' 事件:范围滑块拉动时、文字输入时会即时触发
327
+ // 'change' 事件:下拉框选择后、勾选框切换后触发
328
+ const eventType = el.type === 'range' || el.type === 'number' ? 'input' : 'change';
329
+
330
+ el.addEventListener(eventType, () => {
331
+ // 特殊逻辑:更新滑块旁边的文字显示 (0.80)
332
+ if (id === 'threshold') {
333
+ const val = (el.value / 100).toFixed(2);
334
+ document.getElementById('threshold-val').textContent = val;
335
+ }
336
+
337
+ // 调用统一的处理方法
338
+ onConfigChange();
339
+ });
340
+ });
341
+ }
342
+ </script>
343
+
344
+ <script>
345
+ let temp_name = "template_findimage_temp.jpeg";
346
+ let cache_rect = null;
347
+ let cache_save_img_path = null;
348
+
349
+ $(document).ready(function () {
350
+ initListeners();
351
+ window.parent.gp.iframe.on_area_selected();
352
+ genCode();
353
+
354
+ const selectAlgo = document.getElementById('select-algo');
355
+ const rowRgb = document.getElementById('row-rgb');
356
+ const rowRes = document.getElementById('row-resnum');
357
+ const rowMinMatch = document.getElementById('row-min-match');
358
+
359
+ selectAlgo.addEventListener('change', function () {
360
+ if (this.value === 'template') {
361
+ // 显示 RGB,隐藏 Min Match
362
+ rowRgb.classList.remove('d-none');
363
+ rowRgb.classList.add('d-flex'); // 确保 flex 布局生效
364
+
365
+ rowRes.classList.remove('d-none');
366
+ rowRes.classList.add('d-flex'); // 确保 flex 布局生效
367
+
368
+ rowMinMatch.classList.add('d-none');
369
+ rowMinMatch.classList.remove('d-flex');
370
+ } else {
371
+ // 隐藏 RGB,显示 Min Match
372
+ rowRgb.classList.add('d-none');
373
+ rowRgb.classList.remove('d-flex');
374
+ rowRes.classList.add('d-none');
375
+ rowRes.classList.remove('d-flex');
376
+
377
+ rowMinMatch.classList.remove('d-none');
378
+ rowMinMatch.classList.add('d-flex');
379
+ }
380
+ });
381
+
382
+ // 滑块数值实时显示
383
+ $('#threshold').on('input', function () {
384
+ $('#threshold-val').text(($(this).val() / 100).toFixed(2));
385
+ });
386
+
387
+ // 拷贝代码
388
+ $('#btn-copy').click(function () {
389
+ const text = $('#python-code').text();
390
+ navigator.clipboard.writeText(text);
391
+ const $btn = $(this);
392
+ $btn.html('<i class="bi bi-check text-success"></i> Copied');
393
+ setTimeout(() => $btn.html('<i class="bi bi-files me-1"></i>Copy'), 1500);
394
+
395
+ window.parent.gp.info.noti(`${text} 已复制到剪贴板`);
396
+ });
397
+
398
+ // 清空结果按钮
399
+ $('#btn-clear').click(function () {
400
+ // 1. 清理主图上的标记
401
+ if (window.parent.gp && window.parent.gp.marks.clear) {
402
+ window.parent.gp.marks.clear();
403
+ }
404
+ // 2. 重置列表 UI
405
+ $('#results-list').html('<div class="text-center text-muted py-4 opacity-50">已清空结果</div>');
406
+ $('#results-count').text('0');
407
+ });
408
+
409
+ // 拷贝代码
410
+ $('#btn-save').click(function () {
411
+ if(cache_rect==null || cache_rect.l===0 && cache_rect.t===0 && cache_rect.r===0 && cache_rect.b===0){
412
+ window.parent.gp.info.error("保存错误","请先通过拖拽选择一个模板图区域后再保存!");
413
+ return;
414
+ }
415
+ savePicture();
416
+ });
417
+
418
+ // 测试找图动作
419
+ $('#btn-test').click(async function () {
420
+
421
+ if(cache_rect==null || cache_rect.l===0 && cache_rect.t===0 && cache_rect.r===0 && cache_rect.b===0){
422
+ window.parent.gp.info.error("运行错误","请先通过拖拽选择一个模板图区域后再测试!");
423
+ return;
424
+ }
425
+
426
+ const $btn = $(this);
427
+ const $list = $('#results-list');
428
+
429
+ $btn.addClass('opacity-50').prop('disabled', true)
430
+ .html('<span class="spinner-border spinner-border-sm me-1"></span> Running...');
431
+
432
+ try {
433
+ const results = await test();
434
+
435
+ // 每次测试前自动清理旧标记
436
+ if (window.parent.gp && window.parent.gp.marks.clear) {
437
+ window.parent.gp.marks.clear();
438
+ }
439
+
440
+ $list.empty();
441
+ const count = results ? results.length : 0;
442
+ $('#results-count').text(count);
443
+
444
+ if (results && results.length > 0) {
445
+ results.forEach((item, index) => {
446
+ const [l, t, r, b] = item.rect;
447
+ const label = `#${index + 1}`;
448
+
449
+ // 1. 在主图上添加矩形标记
450
+ window.parent.gp.marks.add_rect(label, l, t, r, b);
451
+
452
+ // 2. 在侧边栏添加列表项
453
+ const $item = $(`
454
+ <div class="result-item">
455
+ <div class="d-flex justify-content-between">
456
+ <strong>${label}</strong>
457
+ <span class="conf-text">${(item.confidence * 100).toFixed(1)}%</span>
458
+ </div>
459
+ <div class="coord-text">L:${l}, T:${t}, R:${r}, B:${b}</div>
460
+ </div>
461
+ `);
462
+
463
+ // 3. 悬停交互
464
+ $item.on('mouseenter', function () {
465
+ $(this).addClass('active');
466
+ if (window.parent.gp && window.parent.gp.marks.high_light) {
467
+ window.parent.gp.marks.high_light(label);
468
+ }
469
+ }).on('mouseleave', function () {
470
+ $(this).removeClass('active');
471
+ if (window.parent.gp && window.parent.gp.marks.high_light_clear) {
472
+ window.parent.gp.marks.high_light_clear();
473
+ }
474
+ });
475
+
476
+ $list.append($item);
477
+ });
478
+ } else {
479
+ $list.html('<div class="text-center text-muted py-4 opacity-50">未找到匹配目标</div>');
480
+ }
481
+ } catch (error) {
482
+ console.error("测试出错:", error);
483
+ $list.html('<div class="text-center text-danger py-4 small">运行失败</div>');
484
+ } finally {
485
+ $btn.removeClass('opacity-50').prop('disabled', false)
486
+ .html('<i class="bi bi-play-fill me-1"></i>测试找图');
487
+ }
488
+ });
489
+ });
490
+
491
+ function on_color_picked(data){
492
+ console.log("收到颜色数据:", data);
493
+ }
494
+
495
+ // 裁剪并预览模板图
496
+ function on_area_selected(data) {
497
+ if (!data || (data.l === 0 && data.t === 0 && data.r === 0 && data.b === 0)) {
498
+ return;
499
+ }
500
+ cache_rect = data;
501
+ const pythonCode = `import base64, io, os
502
+ from PIL import Image
503
+ from ascript.windows.tools import config
504
+
505
+ img = Image.open(r"${window.parent.gp.image.path}")
506
+ region = (${data.l}, ${data.t}, ${data.r}, ${data.b})
507
+ crop_img = img.crop(region)
508
+ save_path = os.path.join(config.file_data_temp, "${temp_name}")
509
+ crop_img.save(save_path)
510
+
511
+ buffered = io.BytesIO()
512
+ crop_img.save(buffered, format="PNG")
513
+ img_str = base64.b64encode(buffered.getvalue()).decode()
514
+ _result = f"data:image/png;base64,{img_str}"`;
515
+
516
+ window.parent.gp.call_python(pythonCode).then(base64Result => {
517
+ if (base64Result) {
518
+ document.getElementById('preview-img').src = base64Result;
519
+ }
520
+ });
521
+ }
522
+
523
+ // 执行找图测试
524
+ async function test() {
525
+ const threshold = parseFloat($('#threshold').val()) / 100;
526
+ const algo = $('#select-algo').val();
527
+ const pythonRgbValue = document.getElementById('check-rgb').checked ? "True" : "False";
528
+ const min_match = parseInt($('#input-min-match').val()) || 10;
529
+ const max_res = document.getElementById('check-resnum').checked;
530
+ let findMethod = "find_all_template";
531
+ if (algo === "akaze") findMethod = "find_akaze";
532
+
533
+ let find_line = `_result = FindImages.${findMethod}(im_search=im_search, im_source=im_source, threshold=threshold, max_res=max_res,rgb=rgb)`
534
+
535
+ if (algo === "akaze") {
536
+ find_line = `_result = FindImages.${findMethod}(im_search=im_search, im_source=im_source, threshold=threshold,min_match=min_match)`
537
+ }
538
+
539
+
540
+
541
+ const pythonCode = `from ascript.windows.screen import FindImages
542
+ from ascript.windows.tools import config
543
+ import os
544
+
545
+ im_search = os.path.join(config.file_data_temp, "${temp_name}")
546
+ im_source = r"${window.parent.gp.image.path}"
547
+ threshold = ${threshold}
548
+ max_res = ${max_res?0:1}
549
+ rgb = ${pythonRgbValue}
550
+ min_match = ${min_match}
551
+
552
+ ${find_line}`;
553
+
554
+
555
+ return await window.parent.gp.call_python(pythonCode);
556
+ }
557
+
558
+
559
+ async function genCode() {
560
+ const threshold = parseFloat($('#threshold').val()) / 100;
561
+ const im_search_name = cache_save_img_path?cache_save_img_path.split('/').pop():"小图名称"; // TODO: 获取模板图文件名
562
+ const algo = $('#select-algo').val();
563
+ const pythonRgbValue = document.getElementById('check-rgb').checked ? "True" : "False";
564
+ const max_res = document.getElementById('check-resnum').checked;
565
+ const min_match = parseInt($('#input-min-match').val()) || 10;
566
+ let findMethod = max_res?"find_all_template":"find_template";
567
+ if (algo === "akaze") findMethod = "find_akaze";
568
+
569
+ let threshold_param = threshold == 0.8 ? "" : `, threshold=${threshold}`;
570
+ let rgb_param = pythonRgbValue == "False" ? "" : `, rgb=${pythonRgbValue}`;
571
+ let min_match_param = algo === "akaze" && min_match != 10 ? `, min_match=${min_match}` : "";
572
+ let window_line = "";
573
+ let im_source_param = "";
574
+ let import_window_line = "";
575
+ if (window.parent.gp.window.title) {
576
+ import_window_line = "from ascript.windows.window import Window";
577
+ window_line = `window = Window.find("${window.parent.gp.window.title}")`;
578
+ im_source_param = ",im_source=window";
579
+ }
580
+
581
+ let find_line = `result = FindImages.${findMethod}(R.img("${im_search_name}")${im_source_param}${threshold_param}${rgb_param})`
582
+
583
+ if (algo === "akaze") {
584
+ find_line = `result = FindImages.${findMethod}(R.img("${im_search_name}")${im_source_param}${threshold_param}${rgb_param}${min_match_param})`
585
+ }
586
+
587
+ const pythonCode = `from ascript.windows.screen import FindImages
588
+ from ascript.windows.system import R
589
+ ${import_window_line}
590
+ ${window_line}
591
+ ${find_line}`;
592
+ $("#python-code").text(pythonCode);
593
+ }
594
+
595
+
596
+
597
+ // ------------------ 模板图另存为 ------------------
598
+ async function savePicture() {
599
+ const pythonCode = `import os
600
+ import json
601
+ import tkinter as tk
602
+ from tkinter import filedialog
603
+ from PIL import Image
604
+ from datetime import datetime
605
+ from pathlib import Path
606
+
607
+ # 缓存文件路径
608
+ CACHE_FILE = "path_cache.json"
609
+
610
+ def get_last_path():
611
+ """从缓存中读取上次保存的路径"""
612
+ if os.path.exists(CACHE_FILE):
613
+ try:
614
+ with open(CACHE_FILE, 'r') as f:
615
+ return json.load(f).get("last_path")
616
+ except:
617
+ return None
618
+ return None
619
+
620
+ def save_last_path(path):
621
+ """将当前路径保存到缓存"""
622
+ with open(CACHE_FILE, 'w') as f:
623
+ json.dump({"last_path": path}, f)
624
+
625
+ def crop_and_save_image(image_path, rect):
626
+ """
627
+ image_path: 图片完整路径
628
+ rect: [left, top, right, bottom] 列表
629
+ """
630
+ if not os.path.exists(image_path):
631
+ print("错误:找不到原始图片")
632
+ return None
633
+
634
+ # 1. 处理截图
635
+ try:
636
+ img = Image.open(image_path)
637
+ # rect 格式正好符合 Pillow 的 crop 参数 (left, top, right, bottom)
638
+ cropped_img = img.crop(rect)
639
+ except Exception as e:
640
+ print(f"裁剪失败: {e}")
641
+ return None
642
+
643
+ # 2. 智能生成默认文件名 (例如: crop_20231027_143005.png)
644
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
645
+ default_filename = f"crop_{timestamp}.png"
646
+
647
+ # 3. 弹出文件浏览器
648
+ root = tk.Tk()
649
+ root.withdraw() # 隐藏主窗口
650
+ root.attributes('-topmost', True) # 确保对话框在最前面
651
+
652
+ initial_dir = get_last_path() or os.path.expanduser("~/Pictures")
653
+
654
+ # 弹出另存为对话框
655
+ file_path = filedialog.asksaveasfilename(
656
+ title="选择保存位置",
657
+ initialdir=initial_dir,
658
+ initialfile=default_filename,
659
+ defaultextension=".png",
660
+ filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg"), ("All files", "*.*")]
661
+ )
662
+
663
+ root.destroy() # 关闭 tkinter 资源
664
+
665
+ # 4. 执行保存
666
+ if file_path:
667
+ try:
668
+ cropped_img.save(file_path)
669
+ # 更新缓存路径
670
+ save_last_path(os.path.dirname(file_path))
671
+ print(f"图片已保存至: {file_path}")
672
+ return file_path
673
+ except Exception as e:
674
+ print(f"保存失败: {e}")
675
+ return None
676
+ else:
677
+ print("用户取消了保存")
678
+ return None
679
+ _result = crop_and_save_image(r"${window.parent.gp.image.path}", [${cache_rect.l}, ${cache_rect.t}, ${cache_rect.r}, ${cache_rect.b}])`;
680
+
681
+ // console.log(pythonCode);
682
+
683
+ cache_save_img_path = await window.parent.gp.call_python(pythonCode);
684
+ if (cache_save_img_path) {
685
+ // alert(`模板图已保存至:\n${cache_save_img_path}`);
686
+ genCode();
687
+ }
688
+ }
689
+
690
+
691
+
692
+
693
+
694
+ </script>
695
+
696
+
697
+ </body>
698
+
699
+ </html>