From dfc5041a67c5a1c782a68196d0323a74e5d9dd95 Mon Sep 17 00:00:00 2001 From: yu <191972707@qq.com> Date: Mon, 2 Nov 2026 17:27:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20CV=20=E6=88=AA=E5=B1=8F=E5=A3=B0?= =?UTF-8?q?=E6=98=8E=20DPI=20=E6=84=9F=E7=9F=A5=E5=B9=B6=E8=A6=86=E7=9B=96?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E6=A1=8C=E9=9D=A2,=20=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E6=88=AA=E5=B1=8F=E8=AF=81=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 缩放非 100% 时未声明 DPI 感知的截屏进程只覆盖主屏左上角逻辑区域, 右侧/副屏内容丢失 - grabScreen 先 SetProcessDpiAwarenessContext(-4), 与点击脚本坐标空间一致 - 截屏范围从主屏 PrimaryScreen 改为 VirtualScreen 全部显示器 - cv_not_found 时保留截屏并在错误详情附路径, 便于排查 --- src/main/capabilities/cv-vision.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/capabilities/cv-vision.ts b/src/main/capabilities/cv-vision.ts index c80dfed..84ebc5d 100644 --- a/src/main/capabilities/cv-vision.ts +++ b/src/main/capabilities/cv-vision.ts @@ -26,9 +26,12 @@ function cvTarget(args: Record, nodeId: string): string { async function grabScreen(imagePath: string): Promise { fs.mkdirSync(path.dirname(imagePath), { recursive: true }); const psScript = [ + // 与点击脚本一致: 先声明 DPI 感知, 否则缩放非 100% 时 Bounds 是逻辑像素, 截屏只覆盖屏幕左上角 + "Add-Type -MemberDefinition '[DllImport(\"user32.dll\")] public static extern bool SetProcessDpiAwarenessContext(IntPtr value);' -Name RpaCvDpi -Namespace RpaCv | Out-Null;", + "try { [RpaCv.RpaCvDpi]::SetProcessDpiAwarenessContext([IntPtr](-4)) | Out-Null } catch {}", "Add-Type -AssemblyName System.Drawing | Out-Null;", "Add-Type -AssemblyName System.Windows.Forms | Out-Null;", - "$b = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds;", + "$b = [System.Windows.Forms.SystemInformation]::VirtualScreen;", "$bmp = New-Object System.Drawing.Bitmap($b.Width, $b.Height);", "$g = [System.Drawing.Graphics]::FromImage($bmp);", "$g.CopyFromScreen($b.X, $b.Y, 0, 0, $b.Size);", @@ -49,10 +52,15 @@ export async function locateTextOnScreen(target: string, nodeId: string): Promis const texts = result.texts ?? []; const keyword = target.trim(); const hit = texts.find(t => t.text && t.text.includes(keyword)); - try { fs.unlinkSync(shotPath); } catch {} if (!hit || !hit.box || hit.box.length < 4) { - throw new RuntimeError("cv_not_found", "屏幕上未找到目标文本:" + keyword, { nodeId, componentId: nodeId, recommendation: "确认目标文本在屏幕上可见且清晰" }); + // 找不到目标时保留截屏, 便于排查(截屏范围/遮挡/清晰度) + throw new RuntimeError("cv_not_found", "屏幕上未找到目标文本:" + keyword, { + nodeId, + componentId: nodeId, + recommendation: "确认目标文本在屏幕上可见且清晰;本次截屏已保留: " + shotPath + }); } + try { fs.unlinkSync(shotPath); } catch {} const xs = hit.box.map(p => p[0]); const ys = hit.box.map(p => p[1]); const cx = (Math.min(...xs) + Math.max(...xs)) / 2;