• 【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 ,但是比我这个画板强大多了,效率和功能都高一筹,放上传送门,让我们共同学习一下.最后,如果你有更好的做法,请不吝指教.

  • 相关阅读:
    ios程序中传值的几种方式
    iOS系统、设备信息获取方式
    关于如何使自定义的Button和系统的UIBarButtonItem保持一致的两种方法
    关于iOS中音视频播放的几种方式介绍
    关于IOS数据操作方式详解(三)— Sqlite数据解析
    关于iOS数据操作方式详解(二)— Jason数据解析
    关于IOS数据操作方式详解(一)— XML数据解析
    git常用命令
    pip及npm换源
    win10安装Docker并换国内源
  • 原文地址:https://www.cnblogs.com/caizl/p/4555683.html
Copyright © 2020-2023  润新知