【WPF】WPF截屏


引言

     .NET的截圖控件在網上流傳得不多啊,難得發現一個精品截圖控件( 傳送門),但是無奈是winform的.后來又找到一個周銀輝做的WPF截圖(繼續傳送門),發現截屏是實現了,但是功能略少了點.So,打算自己用WPF去實現一個,無奈略渣,還是簡單分享一下吧.

一個Window和一個Canvas

    Window是截圖的主界面,但是設置好WindowStyle和WindowState就基本沒它什么事了,Window里面放個Canvas,Canvas主要承載當前的截屏和畫板DrawingPannel以及工具控件.先看看Window和Canvas的代碼吧,如下

<Window x:Class="WpfCapture.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfCapture="clr-namespace:WpfCapture"
        Title="Window3" Height="300" Width="300" WindowStyle="None" WindowState="Maximized">
    <Canvas Name="xgrid"   >      
    </Canvas>
</Window>

什么時候加載當前截屏,怎樣加載,看代碼

        public Window3()
        {
            InitializeComponent();
            screenSnapshot = GetScreenSnapshot();
            var bmp = ToBitmapSource(screenSnapshot);
            bmp.Freeze();
            this.xgrid.Background = new ImageBrush(bmp);
        } 

       public Bitmap GetScreenSnapshot()
        {
            try
            {
                System.Drawing.Rectangle rc = SystemInformation.VirtualScreen;
                var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

                using (Graphics memoryGrahics = Graphics.FromImage(bitmap))
                {
                    memoryGrahics.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy);
                }

                return bitmap;
            }
          
            catch (Exception)
            {

            }
            return null;
        }

畫板DrawingPannel

     畫板DrawingPannel是自定義的一個布局控件類,主要是用來顯示DrawingVisual對象的,類定義如下:

 public class DrawingCanvas : Panel
    {
        private List<Visual> visuals = new List<Visual>();


        protected override Visual GetVisualChild(int index)
        {
            return visuals[index];
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return visuals.Count;
            }
        }

        public void RemoveLastVisual()
        {
            if (visuals.Count > 0)
            {

               var item= visuals.FindLast(x => true);
               DeleteVisual(item);
            }
        
        }

        public void AddVisual(Visual visual)
        {
            visuals.Add(visual);

            base.AddVisualChild(visual);
            base.AddLogicalChild(visual);
            Console.WriteLine(visuals.Count);
        }

        public void DeleteVisual(Visual visual)
        {
            visuals.Remove(visual);

            base.RemoveVisualChild(visual);
            base.RemoveLogicalChild(visual);
        }
    }

既然畫板有了,當然不能漏了畫筆等操作工具,所以最終界面XAML描述如下

<Window x:Class="WpfCapture.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfCapture="clr-namespace:WpfCapture"
        Title="Window3" Height="300" Width="300" WindowStyle="None" WindowState="Maximized">
    <Canvas Name="xgrid" >
        <wpfCapture:DrawingCanvas x:Name="grid" Background="AliceBlue"  Canvas.Top="0" Canvas.Left="0"  Width="{Binding ActualWidth,ElementName=xgrid}" 
                                  Height="{Binding ActualHeight,ElementName=xgrid}"
                                  Opacity="0.8"  MouseLeftButtonDown="Grid_OnMouseLeftButtonDown" PreviewMouseMove="grid_PreviewMouseMove_1" MouseLeftButtonUp="Grid_OnMouseLeftButtonUp"
                                  MouseMove="grid_MouseMove_2" MouseRightButtonDown="grid_MouseRightButtonDown_1"
                                  >
        </wpfCapture:DrawingCanvas>
        
        <StackPanel Orientation="Horizontal" Name="toolpanel"  Visibility="Collapsed" Height="28" Width="160">
            <ToolBar>
                <RadioButton GroupName="tool" Name="Arrow" >
                    <Image Source="./icons/Arrow.ico"></Image>
                </RadioButton>
                <RadioButton GroupName="tool" Name="Rectangular">

                    <Image Source="./icons/Rectangular.ico"></Image>
                </RadioButton>
                <RadioButton GroupName="tool" Name="Line">
                    <Image Source="./icons/Line.ico"></Image>
                </RadioButton>

                <Button Click="Button_Click_2">
                    <Image Source="./icons/Redo.png"></Image>
                </Button>
                <Button>
                    <Image Source="./icons/Exit.ico"></Image>
                </Button>
                <Button Click="Button_Click_1">
                    <Image Source="./icons/Accept.ico"></Image>
                </Button>
            </ToolBar>
        </StackPanel>
    </Canvas>
</Window>

如何指定截圖方框

        如何畫截圖邊框出來呢.其實上面已經有畫板了,那么我們只需要在上面畫個方框,再將工具欄顯示出來,那么好像有點像樣了.如何畫?需要用到DrawingVisual類,畫框的方法如下:

 private void DrawSquare1(DrawingVisual visual)
        {
            using (DrawingContext dc = visual.RenderOpen())
            {
                dc.DrawRectangle(drawingBrush, drawingPen,
                    new Rect(startPoint, endPoint));
            }
        }

在鼠標事件中利用上面那個方法輕松畫出方框,然后接下來我就用笨方法了,在畫出方框后,我new了一個新的DrawingCanvas替代方框,再從一開始截屏圖片中截取相應的圖片作為DrawingCanvas的背景,在這個過程中要注意DPI值的轉換,我的電腦是120的DPI,所以從WPF的單位轉換為真正分辨率單位時要乘以1.25.

            //得到DPI比例
            Graphics graphics = Graphics.FromHwnd(IntPtr.Zero);
            systemdpi = graphics.DpiX / 96;
//得到截圖方框的背景
        private BitmapSource CopyFromScreenSnapshot()
        {
            var sourceRect = new System.Drawing.Rectangle((int)(Math.Min(startPoint.X, endPoint.X) * systemdpi), (int)(Math.Min(startPoint.Y, endPoint.Y) * systemdpi), (int)(Math.Abs(startPoint.X - endPoint.X) * systemdpi), (int)(Math.Abs(startPoint.Y - endPoint.Y) * systemdpi));
            var destRect = new System.Drawing.Rectangle(0, 0, (int)(sourceRect.Width * systemdpi), (int)(sourceRect.Height * systemdpi));
            if (screenSnapshot != null)
            {
                var bitmap = new Bitmap((int)(sourceRect.Width * systemdpi), (int)(sourceRect.Height * systemdpi), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
                }
                return ToBitmapSource(bitmap);
            }
            return null;
        }

畫板工具

     畫板工具我只定義了幾個一個線段,方框和鋼筆,也有后退,退出和完成截圖工具.直接看代碼好了

//畫方框
        private void DrawSquare(System.Windows.Point point1, System.Windows.Point point2)
        {
            using (DrawingContext dc = selectionSquare.RenderOpen())
            {
                dc.DrawRectangle(selectionSquareBrush, selectionSquarePen,
                    new Rect(point1, point2));
           }
        }
        //畫箭頭....好吧,是畫直線
        private void DrawArrow(System.Windows.Point point1, System.Windows.Point point2)
        {
            using (DrawingContext dc = selectionSquare.RenderOpen())
            {
                dc.DrawLine(selectionSquarePen, point1, point2);
            }
        }

        PathGeometry pgGeometry = new PathGeometry();
        PathFigure pfFigure = new PathFigure();
        //畫鋼筆線
        private void DrawLine(System.Windows.Point point1, System.Windows.Point point2)
        {
            using (DrawingContext dc = selectionSquare.RenderOpen())
            {
                LineSegment lsLineSegment = new LineSegment(point2, true);

                pfFigure.Segments.Add(lsLineSegment);

                Console.WriteLine(point2.Y);

                pgGeometry.Figures.Add(pfFigure);

                dc.DrawGeometry(selectionSquareBrush, selectionSquarePen, pgGeometry);
            }
        }

各種鼠標方法我就不一一標出來了,最終效果如下:

小結

    其實一句話可以說完整個實現的:將Canvas背景設置為當前屏幕,畫個框放畫板,在畫板上塗塗畫畫,然后將畫板轉成圖片.多簡單,但是上面還有好多細節沒有說到,也有比較多功能沒有實現,例如拖拉邊框等功能.因為是純練習,代碼注釋和規則都懶了,還有畫板功能也不怎么樣,畫起來會有延遲的...不能再說下去了....話說,做完這個后,在CodePreject發現一個好東西,也是一個畫板來的,也是利用DrawingVisual ,但是比我這個畫板強大多了,效率和功能都高一籌,放上傳送門,讓我們共同學習一下.最后,如果你有更好的做法,請不吝指教.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM