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);
}
}
}