2010-06-26 49 views
13

Tôi đang tìm mã .NET thực hiện giống như Công cụ Snipping - chụp vùng màn hình. Tôi tin rằng nó sử dụng móc. Sẽ rất thú vị để biết làm thế nào để nó làm nổi bật các mảnh được chọn..NET Equivalent of Snipping Tool

Cập nhật: Tìm thấy http://www.codeproject.com/KB/vb/Screen_Shot.aspx. Mặc dù mọi người nói rằng nó thiếu một số tập tin quan trọng cho việc biên dịch thích hợp.

Trả lời

37

Hiệu ứng công cụ cắt không khó thực hiện trong Windows Forms. Thêm một mẫu mới vào dự án của bạn và đặt tên là "SnippingTool". Hãy nhìn mã như thế này:

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(e.X, pntStart.X); 
      int y1 = Math.Min(e.Y, pntStart.Y); 
      int x2 = Math.Max(e.X, pntStart.X); 
      int y2 = Math.Max(e.Y, 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); 
     } 
    } 
} 

Cách sử dụng:

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

Tuyệt vời !! Cảm ơn sooo nhiều! – SharpAffair

+1

Hans, bạn có thể giúp công cụ này tương thích với màn hình phụ không? Đã thử thêm thông số màn hình và điều chỉnh vị trí của trình theo dõi, nhưng nhận được kết quả không mong muốn. – SharpAffair

+6

Bạn mong đợi điều gì với "kết quả không mong muốn"? Bắt đầu một câu hỏi mới và * thực sự * ghi lại vấn đề của bạn. –

2

Chụp ảnh màn hình toàn màn hình, sau đó (có thể) sao chép ảnh, áp dụng hiệu ứng mờ & hiển thị nó. Khi bạn nhấp vào kéo nó sau đó có thể chồng lên vùng tương ứng từ ảnh chụp gốc.

Bạn có thể nhận ảnh chụp màn hình bằng cách sử dụng CopyFromScreen() hoặc sử dụng GDI API.

+0

Cám ơn một câu trả lời tuyệt vời. Điều đó có ý nghĩa. Có lẽ bạn biết làm thế nào mà hiệu ứng "làm trắng" có thể được áp dụng cho bitmap? – SharpAffair

7

Đây là một sửa đổi @ phiên bản của Hans đó là tương thích với nhiều màn hình và hoạt động tốt với DPI (thử nghiệm trên Windows 7 và 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(e.X, _pointStart.X); 
     int y1 = Math.Min(e.Y, _pointStart.Y); 
     int x2 = Math.Max(e.X, _pointStart.X); 
     int y2 = Math.Max(e.Y, _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 
} 

Cách sử dụng:

SnippingTool.AreaSelected += OnAreaSelected; 
SnippingTool.Snip(); 

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

Lưu ý bạn cần một lớp helper để có được độ phân giải màn hình thực tế và tránh các vấn đề với DPI. Đây là mã:

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

Dưới đây là hoàn toàn source code

+0

Nó hoạt động, Nhưng trong Dpi cao trong khi chụp ảnh bị mờ và nếu bạn lưu nó hình ảnh quá nhỏ, cố khắc phục nhưng không thể. @ thepirat000 – Arvand

+0

@Arvand Cấu hình DPI của bạn là gì? – thepirat000

+0

3840x2160 với kích thước văn bản được đặt thành 250% [màn hình 4K] – Arvand