1.需要添加引用
System.Drawing.Common
2.主界面中添加一个按钮用于出发截图,按钮事件如下:
【MainWindow.xaml.cs】
//截图按钮
private void BTCut_Click(object sender, RoutedEventArgs e)
{
//截图时隐藏主窗体
this.Hide();
//截取屏幕的一帧,并打开一个窗体显示出来
ScreenWindow snapWin = new ScreenWindow(CaptureCurrentScreen())
{
//ScreenWindow处理完成后回调的处理事件
sendMessage = GetImageHandler
};
snapWin.ShowDialog();
}
private void GetImageHandler(Bitmap bitmap)
{
//此处写处理截图的逻辑
}
/// <summary>
/// 截取屏幕
/// </summary>
/// <returns></returns>
public static Bitmap CaptureCurrentScreen()
{
//创建与屏幕大小相同的位图对象
var bmpScreen = new Bitmap((int)ScreenUtils.GetScreenWidth(), (int)ScreenUtils.GetScreenHeight(), System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//使用位图对象来创建Graphics的对象
using (Graphics g = Graphics.FromImage(bmpScreen))
{
g.SmoothingMode = SmoothingMode.AntiAlias; //设置平滑模式,抗锯齿
g.CompositingQuality = CompositingQuality.HighQuality; //设置合成质量
g.InterpolationMode = InterpolationMode.HighQualityBicubic; //设置插值模式
g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; //设置文本呈现的质量
g.PixelOffsetMode = PixelOffsetMode.HighQuality; //设置呈现期间,像素偏移的方式
//利用CopyFromScreen将当前屏幕截图并将内容存储在bmpScreen的位图中
g.CopyFromScreen(0, 0, 0, 0, bmpScreen.Size, CopyPixelOperation.SourceCopy);
}
return bmpScreen;
}
3.截屏后显示的窗体ScreenWindow代码如下
前台样式:
<Window x:Class="myTestApp.Views.ScreenWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:myTestApp.Views"
mc:Ignorable="d"
WindowState="Maximized" WindowStyle="None" AllowsTransparency="True" Background="Transparent"
Title="ScreenWindow" Height="450" Width="800">
<Grid>
<InkCanvas Margin="0,0,0,0" Name="Ink" Visibility="Visible" EditingModeInverted="Select" EditingMode="Select" Cursor="Cross" MouseDown="Ink_MouseDown" MouseMove="Ink_MouseMove" MouseUp="Ink_MouseUp" MouseRightButtonDown="Ink_MouseRightButtonDown">
</InkCanvas>
<Border Name="Bord" Visibility="Collapsed" BorderThickness="2" HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="Cross" BorderBrush="#FF09646D"/>
<Button Name="Cancel" Visibility="Collapsed" Content="✘" FontSize="16" HorizontalAlignment="Left" Height="40" Margin="527,347,0,0" VerticalAlignment="Top" Width="40" BorderBrush="Red" Background="Red" Foreground="White" Click="Cancel_Click"/>
<Button Name="Conf" Visibility="Collapsed" Content="✔" FontSize="16" HorizontalAlignment="Left" Height="40" Margin="527,347,0,0" VerticalAlignment="Top" Width="40" BorderBrush="#FF32510C" Background="#66C4EF3C" Foreground="White" Click="Conf_Click"/>
</Grid>
</Window>
后台代码:
/// <summary>
/// ScreenWindow.xaml 的交互逻辑
/// </summary>
public partial class ScreenWindow : Window
{
public delegate void SendMessage(Bitmap bitmap);
public SendMessage sendMessage;
#region Win32 API
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr ptr);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(
IntPtr hdc, // handle to DC
int nIndex // index of capability
);
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
#endregion
#region DeviceCaps常量
const int HORZRES = 8;
const int VERTRES = 10;
const int LOGPIXELSX = 88;
const int LOGPIXELSY = 90;
const int DESKTOPVERTRES = 117;
const int DESKTOPHORZRES = 118;
#endregion
private bool IsSnap = false;
private Bitmap ScreenShot;
public ScreenWindow(Bitmap bitmap)
{
InitializeComponent();
this.Topmost = true;
ScreenShot = bitmap;
MouseDown += Ink_MouseDown;
MouseUp += Ink_MouseUp;
MouseMove += Ink_MouseMove;
MouseRightButtonDown += Ink_MouseRightButtonDown;
BitmapSource source;
IsSnap = true;
try
{
source = Imaging.CreateBitmapSourceFromHBitmap(ScreenShot.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
catch
{
source = null;
}
ImageBrush b = new ImageBrush();
b.ImageSource = source;
b.Stretch = Stretch.Fill;
Ink.Background = b;
Ink.EditingMode = InkCanvasEditingMode.None;
this.WindowStartupLocation = WindowStartupLocation.Manual;
this.Visibility = Visibility.Visible;
this.Left = 0;
this.Top = 0;
this.Height = SystemParameters.VirtualScreenHeight;
this.Width = SystemParameters.VirtualScreenWidth;
}
private bool ISDown = false; // 判断是否鼠标左键按下
System.Windows.Point Startpoint = new System.Windows.Point();
private void Ink_MouseDown(object sender, MouseButtonEventArgs e)
{
ISDown = true;
Conf.Visibility = Visibility.Collapsed;
Cancel.Visibility = Visibility.Collapsed;
Startpoint = Mouse.GetPosition(this);
}
Rect rect;
/// <summary>
/// 根据鼠标移动画出矩形标识区域
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Ink_MouseMove(object sender, MouseEventArgs e)
{
if (IsSnap)
{
if (ISDown == true)
{
System.Windows.Point point = Mouse.GetPosition(this);
rect = new Rect(Startpoint, point);
Bord.Visibility = Visibility.Visible;
Bord.Margin = new Thickness(rect.Left, rect.Top, 0, 0);
Bord.Height = rect.Height;
Bord.Width = rect.Width;
}
}
}
Rect snapArea = new Rect();
private void Ink_MouseUp(object sender, MouseButtonEventArgs e)
{
if (IsSnap)
{
ISDown = false;
if (Bord.Visibility == Visibility.Collapsed)
{
Conf.Visibility = Visibility.Collapsed;
Cancel.Visibility = Visibility.Collapsed;
}
else
{
Conf.Visibility = Visibility.Visible;
Cancel.Visibility = Visibility.Visible;
}
if (rect.Width >= 10 && rect.Height >= 10)
{
if (System.Windows.Forms.SystemInformation.VirtualScreen.Height - rect.Bottom >= 0)
{
snapArea = rect;
Conf.Margin = new Thickness(rect.Right - 40, rect.Bottom, 0, 0);
Cancel.Margin = new Thickness(rect.Right - 80, rect.Bottom, 0, 0);
}
else
{
snapArea = rect;
Conf.Margin = new Thickness(rect.Left + 10, rect.Top + 22, 0, 0);
Cancel.Margin = new Thickness(rect.Left + 50, rect.Top + 22, 0, 0);
}
}
}
}
private void Ink_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
ISDown = false;
Conf.Visibility = Visibility.Collapsed;
Cancel.Visibility = Visibility.Collapsed;
Bord.Visibility = Visibility.Collapsed;
}
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.KeyStates == Keyboard.GetKeyStates(Key.Escape))
{
ISDown = false;
Conf.Visibility = Visibility.Collapsed;
Cancel.Visibility = Visibility.Collapsed;
Bord.Visibility = Visibility.Collapsed;
this.Close();
}
}
/// <summary>
/// 确认区域
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Conf_Click(object sender, RoutedEventArgs e)
{
if (IsSnap)
{
double dpi = getDpi();
System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle((int)((snapArea.X + 2) * dpi), (int)((snapArea.Y + 2) * dpi), (int)((snapArea.Width - 4) * dpi), (int)((snapArea.Height - 4) * dpi));
var bitmap1 = new Bitmap((int)(snapArea.Width * dpi), (int)(snapArea.Height * dpi), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bitmap1))
{
g.CopyFromScreen(rectangle.X, rectangle.Y, 0, 0, rectangle.Size, CopyPixelOperation.SourceCopy);
}
this.Cursor = Cursors.Wait;
sendMessage(bitmap1);
this.Close();
}
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
sendMessage(null);
this.Close();
}
/// <summary>
/// 获取系统dpi,这一步很重要
/// </summary>
/// <returns></returns>
double getDpi()
{
double dDpi = 1;
IntPtr desktopDc = GetDC(IntPtr.Zero);
float horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX);
float verticalDPI = GetDeviceCaps(desktopDc, LOGPIXELSY);
int dpi = (int)(horizontalDPI + verticalDPI) / 2;
dDpi = 1 + ((dpi - 96) / 24) * 0.25;
if (dDpi < 1)
{
dDpi = 1;
}
ReleaseDC(IntPtr.Zero, desktopDc);
return dDpi;
}
}
4.附:ScreenUtils.cs
public class ScreenUtils
{
/// <summary>
/// 获取DPI百分比
/// </summary>
/// <param name="window"></param>
/// <returns></returns>
public static double GetDpiRatio(Window window)
{
var currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(window).Handle);
return currentGraphics.DpiX / 96;
}
public static double GetDpiRatio()
{
return GetDpiRatio(Application.Current.MainWindow);
}
public static double GetScreenHeight()
{
return SystemParameters.PrimaryScreenHeight * GetDpiRatio();
}
public static double GetScreenActualHeight()
{
return SystemParameters.PrimaryScreenHeight;
}
public static double GetScreenWidth()
{
return SystemParameters.PrimaryScreenWidth * GetDpiRatio();
}
public static double GetScreenActualWidth()
{
return SystemParameters.PrimaryScreenWidth;
}
}
以上是实现截图功能的核心代码,接下来添加快捷键截图功能,通过Ctrl+Alt+A快捷截图
5.引用WindowsApi,用于注册全局快捷键,这样即使主窗体不在前台显示也能使用快捷键截图
添加HotKey.cs
public class HotKey
{
[DllImport("user32.dll", SetLastError = true)]
public static extern bool RegisterHotKey(
IntPtr hWnd, // handle to window
int id, // hot key identifier
KeyModifiers fsModifiers, // key-modifier options
System.Windows.Forms.Keys vk // virtual-key code
);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnregisterHotKey(
IntPtr hWnd, // handle to window
int id // hot key identifier
);
[Flags]
public enum KeyModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8
}
}
6.在主窗体完成初始化时注册全局快捷键
【MainWindow.xaml.cs】
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
this.myHandle = new WindowInteropHelper(this).Handle;
//组合键
ctrHotKey = (uint)(KeyModifiers.Alt | KeyModifiers.Control);
//注册
bool f = RegisterHotKey(this.myHandle, 100, (KeyModifiers)ctrHotKey, Keys.A);//这时热键为Alt+CTRL+A
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}
//快捷键响应事件
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handle)
{
//Debug.WriteLine("hwnd:{0},msg:{1},wParam:{2},lParam{3}:,handle:{4}"
// ,hwnd,msg,wParam,lParam,handle);
string sid = wParam.ToString();
switch (sid)
{
case "100":
BTCut_Click(null, null);
break;
default:
break;
}
return IntPtr.Zero;
}
7.窗体程序退出时要注销掉全局快捷键
【MainWindow.xaml.cs】
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
UnregisterHotKey(this.myHandle, 100);//卸载快捷键
}