.NET Equivalente de la herramienta de recorte

Estoy buscando el código .NET que realiza lo mismo que la herramienta de recorte: capturar un área de pantalla. Creo que usa ganchos. Sería interesante saber cómo resalta el fragmento seleccionado.

Actualización: se encontró http://www.codeproject.com/KB/vb/Screen_Shot.aspx . Aunque la gente dice que le faltan algunos archivos importantes para una comstackción adecuada.

El efecto de la herramienta de corte no es difícil de implementar en Windows Forms. Agregue un nuevo formulario a su proyecto y asígnele el nombre “SnippingTool”. Haga que el código se vea así:

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

Uso:

 var bmp = SnippingTool.Snip(); if (bmp != null) { // Do something with the bitmap //... } 

Esta es una versión modificada de @ Hans que es compatible con múltiples monitores y funciona bien con escalamiento DPI (probado en Windows 7 y Windows 10).

 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 } 

Uso:

 SnippingTool.AreaSelected += OnAreaSelected; SnippingTool.Snip(); private static void OnAreaSelected(object sender, EventArgs e) { var bmp = SnippingTool.Image; // Do something with the bitmap //... } 

Tenga en cuenta que necesita una clase de ayuda para obtener la resolución real del monitor y evitar problemas con la escala de PPP. Este es el código:

 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 _result; public static List GetMonitorsInfo() { _result = new List(); 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; } } 

Aquí está el código fuente completo

Toma una captura de pantalla de pantalla completa, luego (probablemente) la copia, aplica el efecto translúcido y lo muestra. Cuando hace clic y arrastra, puede superponer la región correspondiente de la captura original.

Puede obtener una captura de pantalla usando CopyFromScreen() o usando la API de GDI .