原始碼路徑: https://gitee.com/LiuShuiRuoBing/wpf_screen_cut
實作功能
- 實作基本的截屏表單
- 滑鼠隨意選擇截圖區域
- 滑鼠抬起時彈出按鈕區
- 快捷鍵Ctrl+Alt+z觸發截屏
- ESC取消截屏
- 實作Save按鈕,將截圖保存在系統剪切板
- 實作Load按鈕,將截圖保存到本地磁盤
- 截屏表單主要由兩個部分組成,一個是影像選擇區,一個是按鈕區,其中當觸發截屏時隨著滑鼠的移動會繪制影像選區,當滑鼠按鍵抬起時才顯示按鈕區,
- 首先ScreenWindow要設定為最大化、無邊框、背景透明,這樣在表單彈出時就可只顯示影像載體控制元件的內容了
WindowState="Maximized" WindowStyle="None" AllowsTransparency="True" Background="Transparent"
- 要考慮截屏內容的載體控制元件,因為截屏內容后期可能也會在上面繪制圖形,所以考慮將其放在Canvas控制元件中,而為了動態實作滑鼠移動時實時繪制圖形的選擇區域,可以考慮使用Rectangle加Border來實作,具體效果演示如下:
- 在Canvas控制元件中放入left、right、top、bottom 4個矩形,然后根據滑鼠按下抬起的位置繪制border,這個borde的區域即為選中的截圖區域,同時滑鼠移動時來不斷地計算left、right、top、bottom 4個矩形和border在Canvas中的位置,并且動態繪制,從而實作截圖區域的動態繪制,
- 按鈕區的實作,按鈕區在開始的時候需要隱藏,當滑鼠抬起時才顯示出來,按鈕區的容器控制元件可以選擇WrapPanel,使用Canvas.Bottom="0" 和 Canvas.Right="0" 將其設定到Canvas的右下角,在ScreenWindow彈出時默認隱藏,當滑鼠抬起時再將其顯示出來,可以通過設定Visibility屬性實作,其在Canvas中的位置處理代碼如下:
private void Window_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (!IsMouseUp) { WrapPanel_Btns.Visibility = Visibility.Visible; //當所選的截圖區域不大時,按鈕區直接在其下方顯示 if (Rect_RealScreen.Y + Rect_RealScreen.Height + this.WrapPanel_Btns.ActualHeight < SystemParameters.PrimaryScreenHeight) { Canvas.SetRight(this.WrapPanel_Btns, Rectangle_Right.Width); Canvas.SetBottom(this.WrapPanel_Btns, Rectangle_Bottom.Height - this.WrapPanel_Btns.ActualHeight - 4); } else //當滑鼠選擇區域大到一定程度時,設定按鈕選擇區的位置到選擇區域內左上角 { Canvas.SetLeft(this.WrapPanel_Btns, Rect_RealScreen.X + 4); Canvas.SetTop(this.WrapPanel_Btns, Rect_RealScreen.Y + 4); } IsMouseUp = true; } }
如何利用WIndows API來實作當前螢屏的截圖 在觸發截圖功能時需要先將當前螢屏截屏,并存盤在Bitmap中,以供后面使用,可以先創建一個螢屏大小的Bitmap,然后利用此Bitmap創建一個Graphics物件實體,使用Graphics的CopyFromScreen()函式將當前螢屏截圖,并保存到之前創建的Bitmap中,具體代碼如下:
/// <summary> /// 獲取當前截屏 /// </summary> /// <returns></returns> public static Bitmap CaptureCurrentScreen() { //創建與螢屏大小相同的位圖物件 var bmpScreen = new Bitmap((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, 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; }
根據滑鼠移動動態繪制截圖區域
- 如果所示當滑鼠按下移動時可以根據起始點,以及當前點實時繪制Border矩形,同時可計算出Left、Right、Top、Bottom 4個矩形的位置,通過Canvas不斷設定各部分的位置,4個矩形的遮擋的地方實作背景虛化,而Border選擇區真實顯示
private void MoveAllRectangle(System.Windows.Point current) { PointEnd = current; Rect_RealScreen = new Rect(PointStart, PointEnd); //設定left矩形 this.Rectangle_Left.Width = Rect_RealScreen.X; this.Rectangle_Left.Height = Canvas_ScreenCut.Height; Canvas.SetLeft(this.Rectangle_Left, 0); Canvas.SetTop(this.Rectangle_Left, 0); //設定Top矩形 this.Rectangle_Top.Width = Rect_RealScreen.Width; double h = 0.0; if (current.Y < PointStart.Y) h = current.Y; else h = current.Y - Rect_RealScreen.Height; this.Rectangle_Top.Height = h; Canvas.SetLeft(this.Rectangle_Top, this.Rectangle_Left.Width); Canvas.SetTop(this.Rectangle_Top, 0); //設定right矩形 this.Rectangle_Right.Width = Canvas_ScreenCut.Width - (Rect_RealScreen.Width + this.Rectangle_Left.Width); this.Rectangle_Right.Height = Canvas_ScreenCut.Height; Canvas.SetLeft(this.Rectangle_Right, this.Rectangle_Left.Width + Rect_RealScreen.Width); Canvas.SetTop(this.Rectangle_Right, 0); //設定bottom矩形 this.Rectangle_Bottom.Width = Rect_RealScreen.Width; this.Rectangle_Bottom.Height = Canvas_ScreenCut.Height - (Rect_RealScreen.Height + this.Rectangle_Top.Height); Canvas.SetLeft(this.Rectangle_Bottom, this.Rectangle_Left.Width); Canvas.SetTop(this.Rectangle_Bottom, Rect_RealScreen.Height + this.Rectangle_Top.Height); //設定border選擇的圖形區 this.Border_ScreenCut.Height = Rect_RealScreen.Height; this.Border_ScreenCut.Width = Rect_RealScreen.Width; Canvas.SetLeft(this.Border_ScreenCut, Rect_RealScreen.X); Canvas.SetTop(this.Border_ScreenCut, Rect_RealScreen.Y); }
按鈕區的邏輯實作
- Cancel 按鈕,直接關閉表單來取消截屏
- Save按鈕,將截屏內容保存到系統的額剪切板中
private void Btn_Save_Click(object sender, RoutedEventArgs e) { BitmapFrame bitmapFrame = BitmapFrame.Create(ImageProcessHelper.CutBitmap(Canvas_ScreenCut, Rect_RealScreen)); Clipboard.SetImage(bitmapFrame); Close(); }
- Load 按鈕,保存并下載截圖區域到指定檔案
private void Btn_Save_Click(object sender, RoutedEventArgs e) { SaveFileDialog dlg = new SaveFileDialog(); dlg.FileName = $"ScreenCut_{DateTime.Now.ToString("yyyyMMddHHmmss")}.png"; dlg.DefaultExt = ".png"; dlg.Filter = "image file|*.png"; if (dlg.ShowDialog() == true) { BitmapEncoder pngEncoder = new PngBitmapEncoder(); pngEncoder.Frames.Add(BitmapFrame.Create(CutBitmap())); using (var fs = File.OpenWrite(dlg.FileName)) { pngEncoder.Save(fs); } } Close(); }
- CutBitmap()函式的實作
- 由于整個螢屏截圖已經放置到了Canvas控制元件中,所以可以使用RenderTargetBitmap構造一個物件實體,將Visual物件轉換成位圖,
- 然后利用CroppedBitmap,從整個截屏中剪裁出 選中的區域,并轉換成Bitmap來進行存盤,
/// <summary> /// 截圖實作 /// </summary> /// <param name="frameworkElement">帶有繪圖內容的控制元件元素</param> /// <param name="rect">要截圖的區域</param> /// <returns></returns> public static CroppedBitmap CutBitmap(FrameworkElement frameworkElement, Rect rect) { //將Visual 物件轉換為位圖 var renderTargetBitmap = new RenderTargetBitmap((int)frameworkElement.Width, (int)frameworkElement.Height, 96d, 96d, PixelFormats.Default); renderTargetBitmap.Render(frameworkElement); //按照Border繪制的rect剪裁Bitmap(9 和 5 都是為了去掉邊框) return new CroppedBitmap(renderTargetBitmap, new Int32Rect((int)rect.X + 9, (int)rect.Y + 9, (int)rect.Width - 5, (int)rect.Height - 5)); }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/486176.html
標籤:WPF
上一篇:驅動開發實戰之TcpClient
下一篇:標簽liferay中的多個鏈接
