134 lines
5.2 KiB
C#
134 lines
5.2 KiB
C#
using anjianjingling.Native;
|
|
|
|
namespace anjianjingling.Forms
|
|
{
|
|
/// <summary>
|
|
/// 全屏框选截图:鼠标拖拽框选区域,松开后截图保存到 images 目录。
|
|
/// ESC 取消。
|
|
/// </summary>
|
|
public sealed class OverlayForm : Form
|
|
{
|
|
private Point _start, _end;
|
|
private bool _dragging;
|
|
private Rectangle _selected;
|
|
public string? SavedPath { get; private set; }
|
|
public event Action<string>? OnSaved;
|
|
|
|
/// <summary>是否把框选结果保存为图片(录屏取区域时设为 false)。</summary>
|
|
[System.ComponentModel.Browsable(false)]
|
|
[System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]
|
|
public bool SaveToFile { get; set; } = true;
|
|
|
|
/// <summary>最近一次框选的屏幕矩形。</summary>
|
|
[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);
|
|
}
|
|
}
|
|
}
|