using anjianjingling.Native; namespace anjianjingling.Forms { /// /// 全屏框选截图:鼠标拖拽框选区域,松开后截图保存到 images 目录。 /// ESC 取消。 /// public sealed class OverlayForm : Form { private Point _start, _end; private bool _dragging; private Rectangle _selected; public string? SavedPath { get; private set; } public event Action? OnSaved; /// 是否把框选结果保存为图片(录屏取区域时设为 false)。 [System.ComponentModel.Browsable(false)] [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)] public bool SaveToFile { get; set; } = true; /// 最近一次框选的屏幕矩形。 [System.ComponentModel.Browsable(false)] [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)] public Rectangle SelectedRect { get; private set; } public OverlayForm() { FormBorderStyle = FormBorderStyle.None; StartPosition = FormStartPosition.Manual; Bounds = SystemInformation.VirtualScreen; TopMost = true; ShowInTaskbar = false; DoubleBuffered = true; KeyPreview = true; BackColor = Color.Black; Opacity = 0.25; Cursor = Cursors.Cross; MouseDown += (s, e) => { if (e.Button == MouseButtons.Left) { _dragging = true; _start = _end = PointToScreen(e.Location); } }; MouseMove += (s, e) => { if (_dragging) { _end = PointToScreen(e.Location); var r = RectangleFromPoints(_start, _end); _selected = r; Invalidate(); } }; MouseUp += (s, e) => { if (_dragging && e.Button == MouseButtons.Left) { _dragging = false; var r = RectangleFromPoints(_start, _end); if (r.Width > 4 && r.Height > 4) { SelectedRect = r; if (SaveToFile) { string dir = Path.Combine(AppContext.BaseDirectory, "images"); Directory.CreateDirectory(dir); string file = Path.Combine(dir, $"clip_{DateTime.Now:yyyyMMdd_HHmmss}.png"); using (var bmp = new Bitmap(r.Width, r.Height)) using (var g = Graphics.FromImage(bmp)) { g.CopyFromScreen(r.Left, r.Top, 0, 0, r.Size); bmp.Save(file, System.Drawing.Imaging.ImageFormat.Png); } SavedPath = file; OnSaved?.Invoke(file); } DialogResult = DialogResult.OK; Close(); return; } Invalidate(); } }; KeyDown += (s, e) => { if (e.KeyCode == Keys.Escape) { DialogResult = DialogResult.Cancel; Close(); } }; } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); if (_selected.Width > 0) { // 用屏幕坐标转客户区绘制 var r = ScreenRectToClient(_selected); using (var pen = new Pen(Color.Lime, 1)) { e.Graphics.DrawRectangle(pen, r); string info = $"{_selected.Width} x {_selected.Height} ({_selected.Left},{_selected.Top})"; using var font = new Font("Consolas", 9F); var sz = e.Graphics.MeasureString(info, font); float ty = r.Top - sz.Height - 2; if (ty < 0) ty = r.Bottom + 2; using var bg = new SolidBrush(Color.Lime); e.Graphics.FillRectangle(bg, r.Left, ty, sz.Width, sz.Height); e.Graphics.DrawString(info, font, Brushes.Black, r.Left, ty); } } } private static Rectangle RectangleFromPoints(Point a, Point b) => Rectangle.FromLTRB( Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); private Rectangle ScreenRectToClient(Rectangle screen) { var a = PointToClient(new Point(screen.Left, screen.Top)); var b = PointToClient(new Point(screen.Right, screen.Bottom)); return new Rectangle(a.X, a.Y, b.X - a.X, b.Y - a.Y); } } }