You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用PowerShell仿Snipaste截图工具遇区域偏移缩放问题求助

修复PowerShell截图工具的位置偏移与尺寸缩放问题

你的PowerShell截图工具出现的位置偏移和尺寸异常,主要由高DPI屏幕适配缺失和选区计算逻辑漏洞导致,以下是具体修复方案:

核心修复点

1. 解决高DPI屏幕坐标偏移

Windows高DPI缩放会使Cursor.Position返回的物理坐标与GDI+绘图逻辑坐标不匹配,直接使用会导致截图偏移。添加DPI感知配置,并修正坐标获取方式:

  • 调用Windows API获取当前屏幕的DPI缩放比例
  • 用缩放比例转换鼠标坐标,确保截图位置准确

2. 修正选区尺寸计算逻辑

当反向拖动鼠标(右下→左上)时,选区宽高会变为负数,导致截图尺寸错误;同时设置窗体大小时未考虑控件布局,需调整:

  • 计算选区时先确定左上角坐标,确保宽高始终为正
  • 设置窗体大小前先隐藏标签控件,避免布局干扰

完整修复代码

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# 添加DPI感知API
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class DpiHelper {
    [DllImport("user32.dll")]
    public static extern int GetDpiForWindow(IntPtr hWnd);
    [DllImport("user32.dll")]
    public static extern bool SetProcessDpiAwarenessContext(int dpiFlag);
}
"@
# 设置进程DPI感知
[DpiHelper]::SetProcessDpiAwarenessContext(-4) # DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2

# Create form and set properties
$form = New-Object System.Windows.Forms.Form
$form.Text = "Snipaste"
$form.StartPosition = "CenterScreen"
$form.Size = New-Object System.Drawing.Size(400, 300)
$form.TopMost = $true
$form.FormBorderStyle = "None"

$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(10, 10)
$label.Size = New-Object System.Drawing.Size(400, 300)
$label.Text = "INSTRUCTIONS:`n1. Alt+S to capture region.`n2. Alt+Q to minimize.`n3. Scroll to scale.`n4. Escape to quit."
$font = New-Object System.Drawing.Font("Arial", 12, [System.Drawing.FontStyle]::Bold)
$label.Font = $font
$form.Controls.Add($label)

# Create picture frame and set properties
$pictureFrame = New-Object System.Windows.Forms.PictureBox
$pictureFrame.Dock = "Fill"
$pictureFrame.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::StretchImage
$form.Controls.Add($pictureFrame)

$global:bitmap = $null

# Add mouse wheel event to zoom in/out the picture
$pictureFrame.Add_MouseWheel({
        if ($_.Delta -gt 0) {
            $pictureFrame.Width *= 1.1
            $pictureFrame.Height *= 1.1
            $form.Width *= 1.1
            $form.Height *= 1.1
        }
        else {
            $pictureFrame.Width /= 1.1
            $pictureFrame.Height /= 1.1
            $form.Width /= 1.1
            $form.Height /= 1.1
        }
    })

$form.Add_KeyDown({
        if ($_.KeyCode -eq "S" -and $_.Modifiers -eq "Alt") {
            $form.Hide()
            $label.Hide()

            $selectorForm = New-Object System.Windows.Forms.Form
            $selectorForm.FormBorderStyle = "None"
            $selectorForm.WindowState = "Maximized"
            $selectorForm.BackColor = "Black"
            $selectorForm.Opacity = 0.2
            $selectorForm.TopMost = $true

            # 获取当前窗口DPI
            $dpi = [DpiHelper]::GetDpiForWindow($selectorForm.Handle)
            $scaleFactor = $dpi / 96.0

            $startPoint = $null
            $currentRect = New-Object System.Drawing.Rectangle

            $selectorForm.Add_Paint({
                    $g = $selectorForm.CreateGraphics()
                    $g.DrawRectangle([System.Drawing.Pens]::Red, $currentRect)
                })
        
            $selectorForm.Add_MouseDown({
                    # 转换鼠标坐标为物理坐标
                    $startPoint = [System.Drawing.Point]::new(
                        [int]([System.Windows.Forms.Cursor]::Position.X / $scaleFactor),
                        [int]([System.Windows.Forms.Cursor]::Position.Y / $scaleFactor)
                    )
                    $currentRect.Location = $startPoint
                    $currentRect.Size = [System.Drawing.Size]::Empty
                })
        
            $selectorForm.Add_MouseMove({
                    if ([System.Windows.Forms.Control]::MouseButtons -eq "Left") {
                        $selectorForm.Opacity = 0.0
                        $currentPoint = [System.Drawing.Point]::new(
                            [int]([System.Windows.Forms.Cursor]::Position.X / $scaleFactor),
                            [int]([System.Windows.Forms.Cursor]::Position.Y / $scaleFactor)
                        )
                        # 确保选区左上角为起始点,宽高为正
                        $currentRect.X = [Math]::Min($startPoint.X, $currentPoint.X)
                        $currentRect.Y = [Math]::Min($startPoint.Y, $currentPoint.Y)
                        $currentRect.Width = [Math]::Abs($currentPoint.X - $startPoint.X)
                        $currentRect.Height = [Math]::Abs($currentPoint.Y - $startPoint.Y)
                        $selectorForm.Invalidate()
                    }
                })

            $selectorForm.Add_MouseUp({
                    if ($currentRect.Width -gt 0 -and $currentRect.Height -gt 0) {
                        $global:bitmap = New-Object System.Drawing.Bitmap($currentRect.Width, $currentRect.Height)
                        $graphics = [System.Drawing.Graphics]::FromImage($global:bitmap)
                        # 使用转换后的物理坐标截图
                        $graphics.CopyFromScreen($currentRect.X, $currentRect.Y, 0, 0, $currentRect.Size)
                        $pictureFrame.Image = $global:bitmap
                        [System.Windows.Forms.Clipboard]::SetImage($global:bitmap)

                        # 设置窗体大小前先确保标签隐藏,避免布局影响
                        $form.Width = $currentRect.Width
                        $form.Height = $currentRect.Height
                    }
                    $selectorForm.Close()
                    $form.Show()
                })

            $selectorForm.Add_KeyDown({
                    if ($_.KeyCode -eq "Escape") {
                        $selectorForm.Close()
                        $form.Show()
                    }
                })
            $selectorForm.ShowDialog()
        }
    })

$form.Add_KeyDown({
        if ($_.KeyCode -eq "Q" -and $_.Alt) {
            $form.WindowState = "Minimized"
        }
        if ($_.KeyCode -eq "Escape") {
            $form.Close()
        }
    })

$global:mouseDownPoint = $null

$pictureFrame.Add_MouseDown({
    $global:mouseDownPoint = [System.Windows.Forms.Cursor]::Position
    $global:formTop = $form.Top
    $global:formLeft = $form.Left
})

$pictureFrame.Add_MouseMove({
    if ([System.Windows.Forms.Control]::MouseButtons -eq "Left") {
        $currentMousePoint = [System.Windows.Forms.Cursor]::Position
        $deltaX = $currentMousePoint.X - $global:mouseDownPoint.X
        $deltaY = $currentMousePoint.Y - $global:mouseDownPoint.Y
        $form.Top = $global:formTop + $deltaY
        $form.Left = $global:formLeft + $deltaX
    }
})

$label.Add_MouseDown({
    $global:mouseDownPoint = [System.Windows.Forms.Cursor]::Position
    $global:formTop = $form.Top
    $global:formLeft = $form.Left
})

$label.Add_MouseMove({
    if ([System.Windows.Forms.Control]::MouseButtons -eq "Left") {
        $currentMousePoint = [System.Windows.Forms.Cursor]::Position
        $deltaX = $currentMousePoint.X - $global:mouseDownPoint.X
        $deltaY = $currentMousePoint.Y - $global:mouseDownPoint.Y
        $form.Top = $global:formTop + $deltaY
        $form.Left = $global:formLeft + $deltaX
    }
})

$form.ShowDialog() | Out-Null

内容的提问来源于stack exchange,提问作者hiroshi kohama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 18:00:42