.NET等效的剪切工具
我正在寻找与截屏工具相同的.NET代码 – 捕获屏幕区域。 我相信它使用钩子。 知道它是如何突出显示选定的片段将是有趣的。
更新:findhttp://www.codeproject.com/KB/vb/Screen_Shot.aspx 。 虽然人们说它缺less一些重要的文件来编译。
剪切工具的效果在Windows窗体中并不难实现。 添加一个新的表单到你的项目中,并命名为“SnippingTool”。 使代码如下所示:
using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class SnippingTool : Form { public static Image Snip() { var rc = Screen.PrimaryScreen.Bounds; using (Bitmap bmp = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb)) { using (Graphics gr = Graphics.FromImage(bmp)) gr.CopyFromScreen(0, 0, 0, 0, bmp.Size); using (var snipper = new SnippingTool(bmp)) { if (snipper.ShowDialog() == DialogResult.OK) { return snipper.Image; } } return null; } } public SnippingTool(Image screenShot) { InitializeComponent(); this.BackgroundImage = screenShot; this.ShowInTaskbar = false; this.FormBorderStyle = FormBorderStyle.None; this.WindowState = FormWindowState.Maximized; this.DoubleBuffered = true; } public Image Image { get; set; } private Rectangle rcSelect = new Rectangle(); private Point pntStart; protected override void OnMouseDown(MouseEventArgs e) { // Start the snip on mouse down if (e.Button != MouseButtons.Left) return; pntStart = e.Location; rcSelect = new Rectangle(e.Location, new Size(0, 0)); this.Invalidate(); } protected override void OnMouseMove(MouseEventArgs e) { // Modify the selection on mouse move if (e.Button != MouseButtons.Left) return; int x1 = Math.Min(eX, pntStart.X); int y1 = Math.Min(eY, pntStart.Y); int x2 = Math.Max(eX, pntStart.X); int y2 = Math.Max(eY, pntStart.Y); rcSelect = new Rectangle(x1, y1, x2 - x1, y2 - y1); this.Invalidate(); } protected override void OnMouseUp(MouseEventArgs e) { // Complete the snip on mouse-up if (rcSelect.Width <= 0 || rcSelect.Height <= 0) return; Image = new Bitmap(rcSelect.Width, rcSelect.Height); using (Graphics gr = Graphics.FromImage(Image)) { gr.DrawImage(this.BackgroundImage, new Rectangle(0, 0, Image.Width, Image.Height), rcSelect, GraphicsUnit.Pixel); } DialogResult = DialogResult.OK; } protected override void OnPaint(PaintEventArgs e) { // Draw the current selection using (Brush br = new SolidBrush(Color.FromArgb(120, Color.White))) { int x1 = rcSelect.X; int x2 = rcSelect.X + rcSelect.Width; int y1 = rcSelect.Y; int y2 = rcSelect.Y + rcSelect.Height; e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, this.Height)); e.Graphics.FillRectangle(br, new Rectangle(x2, 0, this.Width - x2, this.Height)); e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1)); e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, this.Height - y2)); } using (Pen pen = new Pen(Color.Red, 3)) { e.Graphics.DrawRectangle(pen, rcSelect); } } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { // Allow canceling the snip with the Escape key if (keyData == Keys.Escape) this.DialogResult = DialogResult.Cancel; return base.ProcessCmdKey(ref msg, keyData); } } }
用法:
var bmp = SnippingTool.Snip(); if (bmp != null) { // Do something with the bitmap //... }
这是一个修改@汉斯的版本,与多个显示器兼容,并与DPI缩放(在Windows 7和Windows 10testing)。
public sealed partial class SnippingTool : Form { public static event EventHandler Cancel; public static event EventHandler AreaSelected; public static Image Image { get; set; } private static SnippingTool[] _forms; private Rectangle _rectSelection; private Point _pointStart; public SnippingTool(Image screenShot, int x, int y, int width, int height) { InitializeComponent(); BackgroundImage = screenShot; BackgroundImageLayout = ImageLayout.Stretch; ShowInTaskbar = false; FormBorderStyle = FormBorderStyle.None; StartPosition = FormStartPosition.Manual; SetBounds(x, y, width, height); WindowState = FormWindowState.Maximized; DoubleBuffered = true; Cursor = Cursors.Cross; TopMost = true; } private void OnCancel(EventArgs e) { Cancel?.Invoke(this, e); } private void OnAreaSelected(EventArgs e) { AreaSelected?.Invoke(this, e); } private void CloseForms() { for (int i = 0; i < _forms.Length; i++) { _forms[i].Dispose(); } } public static void Snip() { var screens = ScreenHelper.GetMonitorsInfo(); _forms = new SnippingTool[screens.Count]; for (int i = 0; i < screens.Count; i++) { int hRes = screens[i].HorizontalResolution; int vRes = screens[i].VerticalResolution; int top = screens[i].MonitorArea.Top; int left = screens[i].MonitorArea.Left; var bmp = new Bitmap(hRes, vRes, PixelFormat.Format32bppPArgb); using (var g = Graphics.FromImage(bmp)) { g.CopyFromScreen(left, top, 0, 0, bmp.Size); } _forms[i] = new SnippingTool(bmp, left, top, hRes, vRes); _forms[i].Show(); } } #region Overrides protected override void OnMouseDown(MouseEventArgs e) { // Start the snip on mouse down if (e.Button != MouseButtons.Left) { return; } _pointStart = e.Location; _rectSelection = new Rectangle(e.Location, new Size(0, 0)); Invalidate(); } protected override void OnMouseMove(MouseEventArgs e) { // Modify the selection on mouse move if (e.Button != MouseButtons.Left) { return; } int x1 = Math.Min(eX, _pointStart.X); int y1 = Math.Min(eY, _pointStart.Y); int x2 = Math.Max(eX, _pointStart.X); int y2 = Math.Max(eY, _pointStart.Y); _rectSelection = new Rectangle(x1, y1, x2 - x1, y2 - y1); Invalidate(); } protected override void OnMouseUp(MouseEventArgs e) { // Complete the snip on mouse-up if (_rectSelection.Width <= 0 || _rectSelection.Height <= 0) { CloseForms(); OnCancel(new EventArgs()); return; } Image = new Bitmap(_rectSelection.Width, _rectSelection.Height); var hScale = BackgroundImage.Width / (double)Width; var vScale = BackgroundImage.Height / (double)Height; using (Graphics gr = Graphics.FromImage(Image)) { gr.DrawImage(BackgroundImage, new Rectangle(0, 0, Image.Width, Image.Height), new Rectangle((int)(_rectSelection.X * hScale), (int)(_rectSelection.Y * vScale), (int)(_rectSelection.Width * hScale), (int)(_rectSelection.Height * vScale)), GraphicsUnit.Pixel); } CloseForms(); OnAreaSelected(new EventArgs()); } protected override void OnPaint(PaintEventArgs e) { // Draw the current selection using (Brush br = new SolidBrush(Color.FromArgb(120, Color.White))) { int x1 = _rectSelection.X; int x2 = _rectSelection.X + _rectSelection.Width; int y1 = _rectSelection.Y; int y2 = _rectSelection.Y + _rectSelection.Height; e.Graphics.FillRectangle(br, new Rectangle(0, 0, x1, Height)); e.Graphics.FillRectangle(br, new Rectangle(x2, 0, Width - x2, Height)); e.Graphics.FillRectangle(br, new Rectangle(x1, 0, x2 - x1, y1)); e.Graphics.FillRectangle(br, new Rectangle(x1, y2, x2 - x1, Height - y2)); } using (Pen pen = new Pen(Color.Red, 2)) { e.Graphics.DrawRectangle(pen, _rectSelection); } } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { // Allow canceling the snip with the Escape key if (keyData == Keys.Escape) { Image = null; CloseForms(); OnCancel(new EventArgs()); } return base.ProcessCmdKey(ref msg, keyData); } #endregion }
用法:
SnippingTool.AreaSelected += OnAreaSelected; SnippingTool.Snip(); private static void OnAreaSelected(object sender, EventArgs e) { var bmp = SnippingTool.Image; // Do something with the bitmap //... }
请注意,您需要一个帮助器类来获得实际的显示器分辨率,并避免DPI缩放问题。 这是代码:
public class DeviceInfo { public string DeviceName { get; set; } public int VerticalResolution { get; set; } public int HorizontalResolution { get; set; } public Rectangle MonitorArea { get; set; } } public static class ScreenHelper { private const int DektopVertRes = 117; private const int DesktopHorzRes = 118; [StructLayout(LayoutKind.Sequential)] internal struct Rect { public int left; public int top; public int right; public int bottom; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct MONITORINFOEX { public int Size; public Rect Monitor; public Rect WorkArea; public uint Flags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string DeviceName; } private delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData); [DllImport("user32.dll")] private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData); [DllImport("gdi32.dll")] private static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX lpmi); [DllImport("User32.dll")] private static extern int ReleaseDC(IntPtr hwnd, IntPtr dc); [DllImport("gdi32.dll")] private static extern int GetDeviceCaps(IntPtr hdc, int nIndex); private static List<DeviceInfo> _result; public static List<DeviceInfo> GetMonitorsInfo() { _result = new List<DeviceInfo>(); EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnum, IntPtr.Zero); return _result; } private static bool MonitorEnum(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) { var mi = new MONITORINFOEX(); mi.Size = Marshal.SizeOf(typeof(MONITORINFOEX)); bool success = GetMonitorInfo(hMonitor, ref mi); if (success) { var dc = CreateDC(mi.DeviceName, mi.DeviceName, null, IntPtr.Zero); var di = new DeviceInfo { DeviceName = mi.DeviceName, MonitorArea = new Rectangle(mi.Monitor.left, mi.Monitor.top, mi.Monitor.right-mi.Monitor.right, mi.Monitor.bottom-mi.Monitor.top), VerticalResolution = GetDeviceCaps(dc, DektopVertRes), HorizontalResolution = GetDeviceCaps(dc, DesktopHorzRes) }; ReleaseDC(IntPtr.Zero, dc); _result.Add(di); } return true; } }
这里是完整的源代码
它需要一个全屏截图,然后(可能)复制它,应用半透明效果并显示它。 当你点击拖动它可以覆盖原来的捕获相应的区域。
您可以使用CopyFromScreen()
或使用GDI API获取屏幕截图。