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,558 @@
1
+ // --- 状态变量 ---
2
+ let scale = 1, offsetX = 0, offsetY = 0;
3
+ let mode = null, activeHandle = null;
4
+ let startX, startY, box = { x: 0, y: 0, w: 0, h: 0 };
5
+ let mouseImgX = 0, mouseImgY = 0;
6
+ let dragCounter = 0; // 解决拖拽闪烁计数器
7
+
8
+ const container = document.getElementById('container_img');
9
+ const transBox = document.getElementById('transform_container');
10
+ const img = document.getElementById('img_preview');
11
+ const svg = document.getElementById('svg_layer');
12
+ const canvas = document.getElementById('color_picker_canvas');
13
+ const ctx = canvas.getContext('2d', { willReadFrequently: true });
14
+
15
+ // --- 外部调用接口 ---
16
+
17
+ window.addPointMark = function (label, x, y) {
18
+ const g = createSVGElement('g', {
19
+ transform: `translate(${x}, ${y})`,
20
+ class: 'mark-group'
21
+ });
22
+
23
+ const circle = createSVGElement('circle', {
24
+ cx: 0, cy: 0,
25
+ class: 'mark-point dynamic-circle'
26
+ });
27
+
28
+ const text = createSVGElement('text', {
29
+ x: 0,
30
+ y: 0,
31
+ class: 'mark-text dynamic-text',
32
+ 'text-anchor': 'middle',
33
+ 'dominant-baseline': 'middle'
34
+ });
35
+ text.setAttribute('style', 'transform: translateY(-15px); transform-box: fill-box; transform-origin: center;');
36
+
37
+ text.textContent = label;
38
+ g.appendChild(circle);
39
+ g.appendChild(text);
40
+
41
+ const layer = document.getElementById('mark_points_layer');
42
+ if (layer) {
43
+ layer.appendChild(g);
44
+ updateStyleLock();
45
+ }
46
+ };
47
+
48
+ window.addRectMark = function (label, l, t, r, b) {
49
+ const layer = document.getElementById('mark_rects_layer');
50
+ if (!layer) return;
51
+
52
+ // 1. 显式转换为数字
53
+ const left = Number(l);
54
+ const top = Number(t);
55
+ const right = Number(r);
56
+ const bottom = Number(b);
57
+
58
+ const width = right - left;
59
+ const height = bottom - top;
60
+
61
+ // 2. 参考 addPointMark:创建一个 g 标签并直接平移到左上角 (left, top)
62
+ // 这样 g 内部的所有元素就以 (left, top) 为原点 (0,0) 了
63
+ const g = createSVGElement('g', {
64
+ transform: `translate(${left}, ${top})`,
65
+ class: 'mark-group'
66
+ });
67
+
68
+ // 3. 创建矩形:坐标改为 0, 0
69
+ const rect = createSVGElement('rect', {
70
+ x: 0,
71
+ y: 0,
72
+ width: width,
73
+ height: height,
74
+ class: 'mark-rect dynamic-rect'
75
+ });
76
+
77
+ // 4. 文字属性:坐标也改为 0, 0
78
+ const text = createSVGElement('text', {
79
+ x: 0,
80
+ y: 0,
81
+ class: 'mark-text dynamic-text',
82
+ 'text-anchor': 'start', // 靠左对齐
83
+ 'dominant-baseline': 'alphabetical'
84
+ });
85
+
86
+ // 参照 addPointMark 的样式处理,向上平移一点点防止压线
87
+ text.setAttribute('style', 'transform: translateY(-5px); transform-box: fill-box; transform-origin: left bottom;');
88
+ text.textContent = label;
89
+
90
+ g.appendChild(rect);
91
+ g.appendChild(text);
92
+ layer.appendChild(g);
93
+
94
+ // 5. 刷新样式
95
+ updateStyleLock();
96
+ };
97
+
98
+ window.clearAllMarks = function () {
99
+ const pointsLayer = document.getElementById('mark_points_layer');
100
+ const rectsLayer = document.getElementById('mark_rects_layer');
101
+ if (pointsLayer) pointsLayer.innerHTML = '';
102
+ if (rectsLayer) rectsLayer.innerHTML = '';
103
+ console.log("所有标记已清除");
104
+ };
105
+
106
+ window.highlightMark = function (label) {
107
+ window.clearHighlight();
108
+ const allGroups = document.querySelectorAll('#mark_points_layer g, #mark_rects_layer g');
109
+
110
+ allGroups.forEach(g => {
111
+ const textNode = g.querySelector('.mark-text');
112
+ if (textNode && textNode.textContent === label) {
113
+ g.classList.add('highlighted-mark');
114
+ }
115
+ });
116
+ };
117
+
118
+ window.clearHighlight = function () {
119
+ const highlighted = document.querySelectorAll('.highlighted-mark');
120
+ highlighted.forEach(el => el.classList.remove('highlighted-mark'));
121
+ };
122
+
123
+ window.clearSelection = function () {
124
+ box = { x: 0, y: 0, w: 0, h: 0 };
125
+ updateSelectionUI();
126
+ };
127
+
128
+ function createSVGElement(tag, attrs = {}) {
129
+ const el = document.createElementNS("http://www.w3.org/2000/svg", tag);
130
+ for (let k in attrs) {
131
+ el.setAttribute(k, attrs[k]);
132
+ }
133
+ return el;
134
+ }
135
+
136
+ function updateStyleLock() {
137
+ transBox.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
138
+ const invScale = 1 / scale;
139
+
140
+ document.querySelectorAll('.dynamic-text').forEach(el => {
141
+ el.style.fontSize = "14px";
142
+ // 核心修改:确保缩放是以左下角/起始点为基准,这样位置才不会飘
143
+ el.setAttribute('transform', `scale(${invScale})`);
144
+
145
+ // 如果你使用了 transform-origin,请确保它是起始点
146
+ el.style.transformOrigin = "left bottom";
147
+
148
+ el.setAttribute('stroke-width', (2 * invScale) + "px");
149
+ el.style.paintOrder = "stroke";
150
+ });
151
+
152
+ // ... 其余圆点、矩形粗细、手柄的逻辑保持不变 ...
153
+ document.querySelectorAll('.dynamic-circle').forEach(el => {
154
+ el.setAttribute('r', 4 * invScale);
155
+ el.setAttribute('stroke-width', (1.5 * invScale) + "px");
156
+ });
157
+
158
+ const sw = Math.max(1, 1.5 * invScale);
159
+ document.querySelectorAll('.dynamic-rect').forEach(el => el.setAttribute('stroke-width', sw));
160
+
161
+ document.querySelectorAll('.handle').forEach(h => {
162
+ h.setAttribute('r', 5 * invScale);
163
+ h.style.strokeWidth = (10 * invScale) + "px";
164
+ });
165
+ }
166
+
167
+ function getImgCoords(e) {
168
+ const rect = container.getBoundingClientRect();
169
+ const x = (e.clientX - rect.left - offsetX) / scale;
170
+ const y = (e.clientY - rect.top - offsetY) / scale;
171
+ return {
172
+ x: Math.max(0, Math.min(x, img.naturalWidth)),
173
+ y: Math.max(0, Math.min(y, img.naturalHeight))
174
+ };
175
+ }
176
+
177
+ img.onload = () => {
178
+ img.style.willChange = "transform";
179
+ svg.style.willChange = "transform";
180
+ canvas.width = img.naturalWidth;
181
+ canvas.height = img.naturalHeight;
182
+ ctx.drawImage(img, 0, 0);
183
+ svg.setAttribute('viewBox', `0 0 ${img.naturalWidth} ${img.naturalHeight}`);
184
+ updateStyleLock();
185
+ };
186
+
187
+ container.onwheel = (e) => {
188
+ e.preventDefault();
189
+ const zoomSpeed = 0.1;
190
+ const delta = e.deltaY > 0 ? 1 - zoomSpeed : 1 + zoomSpeed;
191
+ const newScale = scale * delta;
192
+ if (newScale < 0.05 || newScale > 100) return;
193
+
194
+ const rect = container.getBoundingClientRect();
195
+ const c = getImgCoords(e);
196
+ scale = newScale;
197
+ offsetX = (e.clientX - rect.left) - c.x * scale;
198
+ offsetY = (e.clientY - rect.top) - c.y * scale;
199
+ updateStyleLock();
200
+ };
201
+
202
+ // --- 修改点 1: 多模式拖拽触发 ---
203
+ container.onmousedown = (e) => {
204
+ const c = getImgCoords(e);
205
+ e.preventDefault();
206
+
207
+ // 允许 右键(2) / 中键(1) / Ctrl+左键(0) 平移
208
+ if (e.button === 2 || e.button === 1 || (e.button === 0 && e.ctrlKey)) {
209
+ mode = 'panning';
210
+ startX = e.clientX;
211
+ startY = e.clientY;
212
+ container.classList.add('grabbing');
213
+ }
214
+ else if (e.button === 0) {
215
+ if (e.target.classList.contains('handle')) {
216
+ mode = 'resizing';
217
+ activeHandle = e.target.id.replace('h_', '');
218
+ } else if (e.target.id === 'selection_rect') {
219
+ mode = 'moving';
220
+ container.classList.add('grabbing');
221
+ } else {
222
+ mode = 'drawing';
223
+ box = { x: c.x, y: c.y, w: 0, h: 0 };
224
+ updateSelectionUI();
225
+ document.getElementById('selection_group').style.visibility = 'visible';
226
+ }
227
+ startX = c.x;
228
+ startY = c.y;
229
+ }
230
+ };
231
+
232
+ const rgbToHex = (r, g, b) => {
233
+ const toHex = (c) => c.toString(16).padStart(2, '0').toUpperCase();
234
+ return "#" + toHex(r) + toHex(g) + toHex(b);
235
+ };
236
+
237
+ window.onmousemove = (e) => {
238
+ const hud = document.getElementById('mouse_hud');
239
+ const containerRect = container.getBoundingClientRect();
240
+
241
+ const isInsideView = (
242
+ e.clientX >= containerRect.left &&
243
+ e.clientX <= containerRect.right &&
244
+ e.clientY >= containerRect.top &&
245
+ e.clientY <= containerRect.bottom
246
+ );
247
+
248
+ const c = getImgCoords(e);
249
+ mouseImgX = c.x;
250
+ mouseImgY = c.y;
251
+
252
+ const posX = Math.floor(c.x);
253
+ const posY = Math.floor(c.y);
254
+ const W = img.naturalWidth;
255
+ const H = img.naturalHeight;
256
+
257
+ if (isInsideView && posX >= 0 && posX < W && posY >= 0 && posY < H) {
258
+ if (hud.style.display !== 'flex') hud.style.display = 'flex';
259
+ hud.style.left = (e.clientX + 15) + 'px';
260
+ hud.style.top = (e.clientY + 15) + 'px';
261
+
262
+ try {
263
+ const p = ctx.getImageData(posX, posY, 1, 1).data;
264
+ const hexStr = rgbToHex(p[0], p[1], p[2]);
265
+ document.getElementById('hud_coords').textContent = `${posX}, ${posY}`;
266
+ document.getElementById('hud_hex').textContent = hexStr;
267
+ document.getElementById('hud_color_swatch').style.backgroundColor = hexStr;
268
+ } catch (err) {}
269
+ } else {
270
+ if (hud.style.display !== 'none') hud.style.display = 'none';
271
+ }
272
+
273
+ if (mode === 'panning') {
274
+ offsetX += (e.clientX - startX);
275
+ offsetY += (e.clientY - startY);
276
+ startX = e.clientX;
277
+ startY = e.clientY;
278
+ updateStyleLock();
279
+ return;
280
+ }
281
+
282
+ if (!mode) return;
283
+
284
+ const dx = c.x - startX, dy = c.y - startY;
285
+
286
+ if (mode === 'drawing') {
287
+ const endX = Math.max(0, Math.min(c.x, W));
288
+ const endY = Math.max(0, Math.min(c.y, H));
289
+ box.w = endX - box.x;
290
+ box.h = endY - box.y;
291
+ }
292
+ else if (mode === 'moving') {
293
+ let newX = box.x + dx;
294
+ let newY = box.y + dy;
295
+ if (newX < 0) newX = 0;
296
+ else if (newX + box.w > W) newX = W - box.w;
297
+ if (newY < 0) newY = 0;
298
+ else if (newY + box.h > H) newY = H - box.h;
299
+ box.x = newX;
300
+ box.y = newY;
301
+ startX = c.x; startY = c.y;
302
+ }
303
+ else if (mode === 'resizing') {
304
+ if (activeHandle.includes('e')) box.w = Math.max(0, Math.min(c.x, W) - box.x);
305
+ if (activeHandle.includes('w')) {
306
+ const oldRight = box.x + box.w;
307
+ box.x = Math.max(0, Math.min(c.x, oldRight));
308
+ box.w = oldRight - box.x;
309
+ }
310
+ if (activeHandle.includes('s')) box.h = Math.max(0, Math.min(c.y, H) - box.y);
311
+ if (activeHandle.includes('n')) {
312
+ const oldBottom = box.y + box.h;
313
+ box.y = Math.max(0, Math.min(c.y, oldBottom));
314
+ box.h = oldBottom - box.y;
315
+ }
316
+ startX = c.x; startY = c.y;
317
+ }
318
+ updateSelectionUI();
319
+ };
320
+
321
+ let lastBoxState = { x: 0, y: 0, w: 0, h: 0 };
322
+
323
+ window.onmouseup = () => {
324
+ container.classList.remove('grabbing');
325
+
326
+ if (mode && mode !== 'panning') {
327
+ if (box.w < 0) { box.x += box.w; box.w = Math.abs(box.w); }
328
+ if (box.h < 0) { box.y += box.h; box.h = Math.abs(box.h); }
329
+
330
+ const isChanged = box.x !== lastBoxState.x ||
331
+ box.y !== lastBoxState.y ||
332
+ box.w !== lastBoxState.w ||
333
+ box.h !== lastBoxState.h;
334
+
335
+ if (isChanged) {
336
+ if (box.w < 2 || box.h < 2) {
337
+ box = { x: 0, y: 0, w: 0, h: 0 };
338
+ updateSelectionUI();
339
+ }
340
+ if (window.onSelectionFinalized) window.onSelectionFinalized({ ...box });
341
+ if (typeof window.gp.iframe.on_area_selected === 'function') {
342
+ window.gp.iframe.on_area_selected();
343
+ }
344
+ lastBoxState = { ...box };
345
+ }
346
+ }
347
+ mode = null;
348
+ };
349
+
350
+ function updateSelectionUI() {
351
+ const ux = box.w < 0 ? box.x + box.w : box.x;
352
+ const uy = box.h < 0 ? box.y + box.h : box.y;
353
+ const uw = Math.abs(box.w);
354
+ const uh = Math.abs(box.h);
355
+
356
+ const sRect = document.getElementById('selection_rect');
357
+ sRect.setAttribute('x', ux);
358
+ sRect.setAttribute('y', uy);
359
+ sRect.setAttribute('width', uw);
360
+ sRect.setAttribute('height', uh);
361
+
362
+ const hPos = {
363
+ nw: [ux, uy], n: [ux + uw / 2, uy], ne: [ux + uw, uy],
364
+ e: [ux + uw, uy + uh / 2], se: [ux + uw, uy + uh],
365
+ s: [ux + uw / 2, uy + uh], sw: [ux, uy + uh], w: [ux, uy + uh / 2]
366
+ };
367
+ for (let id in hPos) {
368
+ const h = document.getElementById('h_' + id);
369
+ if (h) { h.setAttribute('cx', hPos[id][0]); h.setAttribute('cy', hPos[id][1]); }
370
+ }
371
+
372
+ const selGroup = document.getElementById('selection_group');
373
+ const infoPanel = document.getElementById('info_selection_box');
374
+ const rangeDisplay = document.getElementById('sel_range_text');
375
+
376
+ if (uw >= 3 && uh >= 3) {
377
+ selGroup.style.visibility = 'visible';
378
+ if (infoPanel) infoPanel.style.display = 'block';
379
+
380
+ // 计算 L, T, R, B
381
+ const l = Math.floor(ux);
382
+ const t = Math.floor(uy);
383
+ const r = Math.floor(ux + uw);
384
+ const b = Math.floor(uy + uh);
385
+
386
+ // 更新单行文本:格式为 "L, T, R, B"
387
+ if (rangeDisplay) {
388
+ rangeDisplay.textContent = `${l}, ${t}, ${r}, ${b}`;
389
+ copyToClipboard(`${l},${t},${r},${b}`, " 已将此选区数据已复制到剪贴板");
390
+ }
391
+
392
+ } else {
393
+ selGroup.style.visibility = 'hidden';
394
+ if (infoPanel) infoPanel.style.display = 'none';
395
+ }
396
+ }
397
+
398
+ container.oncontextmenu = (e) => e.preventDefault();
399
+
400
+ // --- 修改点 2: 键盘事件增加 Ctrl 反馈 ---
401
+ window.addEventListener('keydown', (e) => {
402
+ // 按下 Ctrl 时变成抓取手势
403
+ if (e.key === 'Control') {
404
+ container.style.cursor = 'grab';
405
+ }
406
+ if (e.key >= '0' && e.key <= '9') {
407
+ const x = Math.floor(mouseImgX);
408
+ const y = Math.floor(mouseImgY);
409
+ const p = ctx.getImageData(x, y, 1, 1).data;
410
+ const hexColor = rgbToHex(p[0], p[1], p[2]);
411
+ const colorData = { key: e.key, pos: [x, y], color: hexColor };
412
+ if (typeof window.gp.iframe.on_color_picked === 'function') {
413
+ window.gp.iframe.on_color_picked(colorData);
414
+ }
415
+
416
+ // window.gp.info.noti(`取色键 [${e.key}]`, `位置: ${x}, ${y}\n颜色: ${hexColor}`, 2000);
417
+
418
+ copyToClipboard(`${x},${y},${hexColor}`, " 已将此取色数据已复制到剪贴板");
419
+
420
+
421
+ if (window.onKeyPicker) window.onKeyPicker(e.key, x, y, p);
422
+ }
423
+ });
424
+
425
+ window.addEventListener('keyup', (e) => {
426
+ if (e.key === 'Control') {
427
+ container.style.cursor = '';
428
+ }
429
+ });
430
+
431
+ // --- 图片重置与加载 (其余所有逻辑保持不变) ---
432
+ window.resetViewToFit = function (padding = 10) {
433
+ const containerRect = container.getBoundingClientRect();
434
+ if (!img.naturalWidth || !img.naturalHeight || containerRect.width === 0) return;
435
+
436
+ const availableW = containerRect.width - padding * 2;
437
+ const availableH = containerRect.height - padding * 2;
438
+
439
+ const scaleW = availableW / img.naturalWidth;
440
+ const scaleH = availableH / img.naturalHeight;
441
+ scale = Math.min(scaleW, scaleH, 1);
442
+
443
+ offsetX = (containerRect.width - img.naturalWidth * scale) / 2;
444
+ offsetY = padding;
445
+
446
+ updateStyleLock();
447
+ };
448
+
449
+ document.getElementById('selection_rect').ondblclick = (e) => {
450
+ e.stopPropagation();
451
+ const transformTarget = document.getElementById('transform_container');
452
+ const containerRect = container.getBoundingClientRect();
453
+ const uw = Math.abs(box.w);
454
+ const uh = Math.abs(box.h);
455
+ if (uw < 5 || uh < 5) return;
456
+
457
+ const ux = box.w < 0 ? box.x + box.w : box.x;
458
+ const uy = box.h < 0 ? box.y + box.h : box.y;
459
+ const centerX = ux + uw / 2;
460
+ const centerY = uy + uh / 2;
461
+
462
+ const padding = 40;
463
+ const targetScale = Math.min((containerRect.width - padding) / uw, (containerRect.height - padding) / uh, 20);
464
+ const targetOffsetX = containerRect.width / 2 - centerX * targetScale;
465
+ const targetOffsetY = containerRect.height / 2 - centerY * targetScale;
466
+
467
+ const isAlreadyAligned =
468
+ Math.abs(scale - targetScale) < 0.01 &&
469
+ Math.abs(offsetX - targetOffsetX) < 2 &&
470
+ Math.abs(offsetY - targetOffsetY) < 2;
471
+
472
+ transformTarget.style.transition = "all 0.4s cubic-bezier(0.25, 1, 0.5, 1)";
473
+ if (!isAlreadyAligned) {
474
+ scale = targetScale;
475
+ offsetX = targetOffsetX;
476
+ offsetY = targetOffsetY;
477
+ } else {
478
+ window.resetViewToFit(10);
479
+ }
480
+ updateStyleLock();
481
+ setTimeout(() => { transformTarget.style.transition = "none"; }, 400);
482
+ };
483
+
484
+ container.ondblclick = (e) => {
485
+ if (e.target.id === 'container_img' || e.target.classList.contains('screen-img-shower')) {
486
+ window.resetViewToFit(10);
487
+ }
488
+ };
489
+
490
+ async function showImg(url) {
491
+ window.gp.image.path = url;
492
+ $("#selection_group").css("visibility", "hidden");
493
+ $("#mark_points_layer").empty();
494
+ $("#mark_rects_layer").empty();
495
+ $("#image_loading").show();
496
+
497
+ try {
498
+ let res = await eel.ascript_get_image(url)();
499
+ if (res.status === "success") {
500
+ let image = document.getElementById('img_preview');
501
+ image.onload = () => {
502
+ svg.setAttribute('viewBox', `0 0 ${image.naturalWidth} ${image.naturalHeight}`);
503
+ canvas.width = image.naturalWidth;
504
+ canvas.height = image.naturalHeight;
505
+ ctx.drawImage(image, 0, 0);
506
+ window.resetViewToFit(10);
507
+ const selPanel = document.getElementById('info_selection_box');
508
+ if (selPanel) selPanel.style.display = 'none';
509
+ $('#header_pixels').text(`${image.naturalWidth} x ${image.naturalHeight}`);
510
+ window.gp.iframe.on_image_loaded({ width: image.naturalWidth, height: image.naturalHeight, path: url });
511
+ };
512
+ image.src = res.data;
513
+ $(image).attr('path', url);
514
+ if ($(".zoomWindow").length > 0) {
515
+ $(".zoomWindow").css("background-image", `url('${res.data}')`);
516
+ }
517
+ $('#status_file_path').text(url).attr('title', url);
518
+ }
519
+ } catch (err) {
520
+ $('#status_file_path').text("读取图片失败: " + err).attr('title', url);
521
+ } finally {
522
+ $("#image_loading").hide();
523
+ }
524
+ }
525
+
526
+ container.addEventListener('dragenter', (e) => {
527
+ e.preventDefault();
528
+ dragCounter++;
529
+ if (dragCounter === 1) container.classList.add('drag-active');
530
+ });
531
+
532
+ container.addEventListener('dragover', (e) => { e.preventDefault(); });
533
+
534
+ container.addEventListener('dragleave', (e) => {
535
+ e.preventDefault();
536
+ dragCounter--;
537
+ if (dragCounter === 0) container.classList.remove('drag-active');
538
+ });
539
+
540
+ container.addEventListener('drop', async (e) => {
541
+ e.preventDefault();
542
+ dragCounter = 0;
543
+ container.classList.remove('drag-active');
544
+ const files = e.dataTransfer.files;
545
+ if (files.length > 0) {
546
+ const file = files[0];
547
+ if (!file.type.startsWith('image/')) return;
548
+ $("#image_loading").show();
549
+ const reader = new FileReader();
550
+ reader.readAsDataURL(file);
551
+ reader.onload = async (event) => {
552
+ try {
553
+ let res = await eel.save_dropped_image(event.target.result, file.name)();
554
+ if (res.status === "success") await showImg(res.path);
555
+ } catch (err) { console.error(err); } finally { $("#image_loading").hide(); }
556
+ };
557
+ }
558
+ });