WPF C#截图功能 仿qq截图

原文: WPF C#截图功能 仿qq截图

先上效果图



源码下载地址:http://download.csdn.net/detail/candyvoice/9788099


描述:启动程序,点击窗口button,开始截图,鼠标左键按下拖动,选中任意区域,拖动过程中,左上角实时显示选中区域大小,拖动结束,鼠标左键抬起,出现右下角保存、取消、ok三个button。右键点击,取消当前选中,可以继续拖动鼠标左键进行截图。双击右键,退出截图功能。按键盘ESC键,可退出截图。


原理:说的通俗一些,就是在原有的界面上盖上一层Canvas,就是画布,然后在这个画布上画矩形,也就是填充矩形的四周,空出来的地方就变成矩形了,如下图。边框线,线上可拖动的小方框、顶角可拖动的小圆球,都是自定义的样式,可在代码的generic.xaml文件中看到具体的设计。



参考资料:http://www.cnblogs.com/zhouyinhui/archive/2010/08/20/1804762.html

这个楼主原理的细节方面已经说的很详细,大家可以仔细看看。


根据上述楼主的代码,主要修改了以下两个类。

MaskCanvas.cs就是操作画布的类,MaskWindow.cs就是截图窗口的类。左上角大小显示框,是一label;右下角的三个按钮是一个自定义的toolbar。

MaskCanvas.cs

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace RisCaptureLib
{

    internal class MaskCanvas : Canvas
    {
        public delegate void FrameDrawEventHander(Rect rect);
        public event FrameDrawEventHander OnMove;
        public MaskCanvas()
        {
            Loaded += OnLoaded;
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            //make the render effect same as SnapsToDevicePixels
            //"SnapsToDevicePixels = true;" doesn't work on "OnRender"
            //however, this maybe make some offset form the render target's origin location
            //SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);

            //ini this
            Cursor = BitmapCursor.CreateCrossCursor();
            Background = Brushes.Transparent;



            //ini mask rect
            maskRectLeft.Fill = maskRectRight.Fill = maskRectTop.Fill = maskRectBottom.Fill = Config.MaskWindowBackground;

            //these propeties(x, y...) will not changed
            SetLeft(maskRectLeft, 0);
            SetTop(maskRectLeft, 0);
            SetRight(maskRectRight, 0);
            SetTop(maskRectRight, 0);
            SetTop(maskRectTop, 0);
            SetBottom(maskRectBottom, 0);
            maskRectLeft.Height = ActualHeight;


            Children.Add(maskRectLeft);
            Children.Add(maskRectRight);
            Children.Add(maskRectTop);
            Children.Add(maskRectBottom);

            //ini selection border
            selectionBorder.Stroke = Config.SelectionBorderBrush;
            selectionBorder.StrokeThickness = Config.SelectionBorderThickness.Left;
            Children.Add(selectionBorder);

            //ini indicator
            indicator = new IndicatorObject(this);
            Children.Add(indicator);

            CompositionTarget.Rendering += OnCompositionTargetRendering;
        }

        private void UpdateSelectionBorderLayout()
        {
            if (!selectionRegion.IsEmpty)
            {
                SetLeft(selectionBorder, selectionRegion.Left);
                SetTop(selectionBorder, selectionRegion.Top);
                selectionBorder.Width = selectionRegion.Width;
                selectionBorder.Height = selectionRegion.Height;
            }
        }

        private void UpdateMaskRectanglesLayout()
        {
            var actualHeight = ActualHeight;
            var actualWidth = ActualWidth;

            if (selectionRegion.IsEmpty)
            {
                SetLeft(maskRectLeft, 0);
                SetTop(maskRectLeft, 0);
                maskRectLeft.Width = actualWidth;
                maskRectLeft.Height = actualHeight;

                maskRectRight.Width = maskRectRight.Height = maskRectTop.Width = maskRectTop.Height = maskRectBottom.Width = maskRectBottom.Height = 0;
            }
            else
            {
                var temp = selectionRegion.Left;
                if (maskRectLeft.Width != temp)
                {
                    maskRectLeft.Width = temp < 0 ? 0 : temp; //Math.Max(0, selectionRegion.Left);
                }

                temp = ActualWidth - selectionRegion.Right;
                if (maskRectRight.Width != temp)
                {
                    maskRectRight.Width = temp < 0 ? 0 : temp; //Math.Max(0, ActualWidth - selectionRegion.Right);
                }

                if (maskRectRight.Height != actualHeight)
                {
                    maskRectRight.Height = actualHeight;
                }

                SetLeft(maskRectTop, maskRectLeft.Width);
                SetLeft(maskRectBottom, maskRectLeft.Width);

                temp = actualWidth - maskRectLeft.Width - maskRectRight.Width;
                if (maskRectTop.Width != temp)
                {
                    maskRectTop.Width = temp < 0 ? 0 : temp; //Math.Max(0, ActualWidth - maskRectLeft.Width - maskRectRight.Width);
                }

                temp = selectionRegion.Top;
                if (maskRectTop.Height != temp)
                {
                    maskRectTop.Height = temp < 0 ? 0 : temp; //Math.Max(0, selectionRegion.Top);
                }

                maskRectBottom.Width = maskRectTop.Width;

                temp = actualHeight - selectionRegion.Bottom;
                if (maskRectBottom.Height != temp)
                {
                    maskRectBottom.Height = temp < 0 ? 0 : temp; //Math.Max(0, ActualHeight - selectionRegion.Bottom);
                }
            }
        }


        #region Fileds & Props

        private IndicatorObject indicator;
        private Point? selectionStartPoint;
        private Point? selectionEndPoint;
        private Rect selectionRegion = Rect.Empty;
        private bool isMaskDraging;

        private readonly System.Windows.Shapes.Rectangle selectionBorder = new System.Windows.Shapes.Rectangle();

        private readonly System.Windows.Shapes.Rectangle maskRectLeft = new System.Windows.Shapes.Rectangle();
        private readonly System.Windows.Shapes.Rectangle maskRectRight = new System.Windows.Shapes.Rectangle();
        private readonly System.Windows.Shapes.Rectangle maskRectTop = new System.Windows.Shapes.Rectangle();
        private readonly System.Windows.Shapes.Rectangle maskRectBottom = new System.Windows.Shapes.Rectangle();


        public Size? DefaultSize
        {
            get;
            set;
        }


        public MaskWindow MaskWindowOwner
        {
            get;
            set;
        }

        #endregion

        #region Mouse Managment

        private bool IsMouseOnThis(RoutedEventArgs e)
        {
            return e.Source.Equals(this) || e.Source.Equals(maskRectLeft) || e.Source.Equals(maskRectRight) || e.Source.Equals(maskRectTop) || e.Source.Equals(maskRectBottom);
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (selectionRegion != Rect.Empty)
                return;
            //mouse down on this self
            if (IsMouseOnThis(e))
            {
                PrepareShowMask(Mouse.GetPosition(this));
            }
            //mouse down on indicator
            else if (e.Source.Equals(indicator))
            {
                HandleIndicatorMouseDown(e);
            }
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (IsMouseOnThis(e))
            {
                UpdateSelectionRegion(e, UpdateMaskType.ForMouseMoving);

                e.Handled = true;
                //委托调用
                //Rect rec = OnMove();
                if(OnMove != null)
                {
                    if(selectionRegion !=null)
                    {
                        this.OnMove(selectionRegion);
                    }
                }
            }
            base.OnMouseMove(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (IsMouseOnThis(e))
            {
                UpdateSelectionRegion(e, UpdateMaskType.ForMouseLeftButtonUp);
                FinishShowMask();
            }
            base.OnMouseLeftButtonUp(e);
        }

        protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
        {
            indicator.Visibility = Visibility.Collapsed;
            selectionRegion = Rect.Empty;
            selectionBorder.Width = selectionBorder.Height = 0;
            ClearSelectionData();
            UpdateMaskRectanglesLayout();

            base.OnMouseRightButtonUp(e);
        }


        internal void HandleIndicatorMouseDown(MouseButtonEventArgs e)
        {
            if(e.ClickCount>=2)
            {
                finishAction();
            }
        }

        public void finishAction()
        {
            if (MaskWindowOwner != null)
            {
                MaskWindowOwner.ClipSnapshot(GetIndicatorRegion());
                ClearSelectionData();
            }
        }

        public System.Drawing.Bitmap GetSnapBitmap()
        {
            System.Drawing.Bitmap saveBitmap = null;
            if (MaskWindowOwner != null)
            {
                Rect clipRegion = GetIndicatorRegion();
                saveBitmap = MaskWindowOwner.CopyBitmapFromScreenSnapshot(clipRegion);

                //close mask window
                //Close();
                //ClearSelectionData();
            }
            return saveBitmap;

        }

        private void PrepareShowMask(Point mouseLoc)
        {
            indicator.Visibility = Visibility.Collapsed;
            selectionBorder.Visibility = Visibility.Visible;
            selectionStartPoint = new Point?(mouseLoc);

            if(!IsMouseCaptured)
            {
                CaptureMouse();
            }
        }

        private void UpdateSelectionRegion(MouseEventArgs e, UpdateMaskType updateType)
        {
            if (updateType == UpdateMaskType.ForMouseMoving && e.LeftButton != MouseButtonState.Pressed)
            {
                selectionStartPoint = null;
            }

            if (selectionStartPoint.HasValue )
            {
                selectionEndPoint = e.GetPosition(this);

                var startPoint = (Point) selectionEndPoint;
                var endPoint = (Point) selectionStartPoint;
                var sX = startPoint.X;
                var sY = startPoint.Y;
                var eX = endPoint.X;
                var eY = endPoint.Y;

                var deltaX = eX - sX;
                var deltaY = eY - sY;

                if (Math.Abs(deltaX) >= SystemParameters.MinimumHorizontalDragDistance ||
                    Math.Abs(deltaX) >= SystemParameters.MinimumVerticalDragDistance)
                {
                    isMaskDraging = true;

                    double x = sX < eX ? sX : eX;//Math.Min(sX, eX);
                    double y = sY < eY ? sY : eY;//Math.Min(sY, eY);
                    double w = deltaX < 0 ? -deltaX : deltaX;//Math.Abs(deltaX);
                    double h = deltaY < 0 ? -deltaY : deltaY;//Math.Abs(deltaY);

                    selectionRegion = new Rect(x, y, w, h);
                }
                else
                {
                    if (DefaultSize.HasValue && updateType == UpdateMaskType.ForMouseLeftButtonUp)
                    {
                        isMaskDraging = true;
                        
                        selectionRegion = new Rect(startPoint.X, startPoint.Y, DefaultSize.Value.Width, DefaultSize.Value.Height);
                    }
                    else
                    {
                        isMaskDraging = false;
                    }
                }
            }
        }

        internal void UpdateSelectionRegion(Rect region)
        {
            selectionRegion = region;
        }

        public Rect GetSelectionRegion()
        {
            return selectionRegion;
        }

        private void FinishShowMask()
        {
            if (IsMouseCaptured)
            {
                ReleaseMouseCapture();
            }

            if (isMaskDraging)
            {
                if (MaskWindowOwner != null)
                {
                    MaskWindowOwner.OnShowMaskFinished(selectionRegion);
                }

                UpdateIndicator(selectionRegion);

                ClearSelectionData();
            }
        }

        private void ClearSelectionData()
        {
            isMaskDraging = false;
            selectionBorder.Visibility = Visibility.Collapsed;
            selectionStartPoint = null;
            selectionEndPoint = null;
        }

        private void UpdateIndicator(Rect region)
        {
            if(region.Width<indicator.MinWidth || region.Height<indicator.MinHeight)
            {
                return;
            }

            indicator.Width = region.Width;
            indicator.Height = region.Height;
            SetLeft(indicator, region.Left);
            SetTop(indicator, region.Top);

            indicator.Visibility = Visibility.Visible;
        }

        private Rect GetIndicatorRegion()
        {
            return new Rect(GetLeft(indicator), GetTop(indicator), indicator.ActualWidth, indicator.ActualHeight);
        }

        #endregion

        #region Render

        private void OnCompositionTargetRendering(object sender, EventArgs e)
        {
            UpdateSelectionBorderLayout();
            UpdateMaskRectanglesLayout();
        }

        #endregion

        #region inner types

        private enum UpdateMaskType
        {
            ForMouseMoving,
            ForMouseLeftButtonUp
        }

        #endregion

    }
}


2 MaskWindow.cs

using System.Drawing;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System;

namespace RisCaptureLib
{
    internal class MaskWindow : Window
    {
        private MaskCanvas innerCanvas;
        private Bitmap screenSnapshot;
        private Timer timeOutTimmer;
        private readonly ScreenCaputre screenCaputreOwner;

        //截图显示尺寸label
        System.Windows.Controls.Label label = null;
        //截图显示按键
        ToolBarControl toolBarContrl = null;
        //截图保存图片
        private System.Drawing.Bitmap m_bmpLayerCurrent;


        public MaskWindow(ScreenCaputre screenCaputreOwner)
        {
            this.screenCaputreOwner = screenCaputreOwner;
            Ini();
            innerCanvas.OnMove += DrawShowSize;
        }

        private void Ini()
        {
            
            //ini normal properties
            //Topmost = true;
            WindowStyle = WindowStyle.None;
            ResizeMode = ResizeMode.NoResize;
            ShowInTaskbar = false;

            //set bounds to cover all screens
            var rect = SystemInformation.VirtualScreen;
            Left = rect.X;
            Top = rect.Y;
            Width = rect.Width;
            Height = rect.Height;

            //set background 
            screenSnapshot = HelperMethods.GetScreenSnapshot();
            if (screenSnapshot != null)
            {
                var bmp = screenSnapshot.ToBitmapSource();
                bmp.Freeze();
                Background = new ImageBrush(bmp);
            }

            //ini canvas
            innerCanvas = new MaskCanvas
            {
                MaskWindowOwner = this
            };
            Content = innerCanvas;

        }

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            //鼠标右键双击取消
            if(e.RightButton == MouseButtonState.Pressed && e.ClickCount>=2)
            {
                CancelCaputre();
            }

            CreatLabel(e.GetPosition(innerCanvas));
            label.Visibility = Visibility.Visible;
            if (toolBarContrl != null)
            {
                toolBarContrl.Visibility = Visibility.Hidden;

            }
        }

        protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if(timeOutTimmer != null && timeOutTimmer.Enabled)
            {
                timeOutTimmer.Stop();
                timeOutTimmer.Start();
            }
            //设置左上角label和右下角toolbar鼠标跟随
            Rect temRect = innerCanvas.GetSelectionRegion();
            if(temRect == Rect.Empty)
            {
                return;
            }
            label.Content = "选中区域大小:" + temRect.Width + "×" + temRect.Height + "宽:" + temRect.Width + "高:" + temRect.Height;
            if(label != null)
            {
                Canvas.SetLeft(label, temRect.X);
                Canvas.SetTop(label, temRect.Y - 25);
            }
            if (toolBarContrl != null)
            {
                Canvas.SetLeft(toolBarContrl, temRect.X + temRect.Width - 75);
                Canvas.SetTop(toolBarContrl, temRect.Y + temRect.Height);
            }
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            CreatToolBar(e.GetPosition(innerCanvas));
            toolBarContrl.Visibility = Visibility.Visible;

        }

        //创建提示选中区域大小控件
        private void CreatLabel(System.Windows.Point location)
        {
            if (label == null)
            {
                label = new System.Windows.Controls.Label();
                innerCanvas.Children.Add(label);

            }
            label.Content = GetLabelContent();
            label.Height = 25;
            Canvas.SetLeft(label, location.X);
            Canvas.SetTop(label, location.Y - 25);
        }

        private void CreatToolBar(System.Windows.Point location)
        {
            if (toolBarContrl == null)
            {
                toolBarContrl = new ToolBarControl();
                innerCanvas.Children.Add(toolBarContrl);
                Canvas.SetLeft(toolBarContrl, location.X - 75);
                Canvas.SetTop(toolBarContrl, location.Y);
            }
            toolBarContrl.OnOK += OKAction;
            toolBarContrl.OnCancel += CancelAction;
            toolBarContrl.OnSaveCapture += SaveCaptureAction;
        }
        private string GetLabelContent()
        {
            string strContent = "";
            return strContent;
        }

        protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
        {
            base.OnKeyDown(e);

            if(e.Key == Key.Escape)
            {
                CancelCaputre();
            }
        }

        private void CancelCaputre()
        {
            Close();
            screenCaputreOwner.OnScreenCaputreCancelled(null);
        }

        internal void OnShowMaskFinished(Rect maskRegion)
        {
            
        }

        internal void ClipSnapshot(Rect clipRegion)
        {
            BitmapSource caputredBmp = CopyFromScreenSnapshot(clipRegion);
            if (caputredBmp != null)
            {
                screenCaputreOwner.OnScreenCaputred(null, caputredBmp);
            }
            //close mask window
            Close();
        }


        internal BitmapSource CopyFromScreenSnapshot(Rect region)
        {
            if (region.Width.Equals(0.0) || region.Height.Equals(0.0))
            {
                return null;
            }
            var sourceRect = region.ToRectangle();
            var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);

            if (screenSnapshot != null)
            {
                var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
                }

                return bitmap.ToBitmapSource();
            }

            return null;
        }

        private void SaveCaptureAction()
        {
            m_bmpLayerCurrent = innerCanvas.GetSnapBitmap();
            if(m_bmpLayerCurrent == null)
            {
                return;
            }
            System.Windows.Forms.SaveFileDialog saveDlg = new System.Windows.Forms.SaveFileDialog();
            string mydocPath = System.Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            saveDlg.InitialDirectory = mydocPath/* + "\\"*/;
            saveDlg.Filter = "Bitmap(*.bmp)|*.bmp|JPEG(*.jpg)|*.jpg";
            saveDlg.FilterIndex = 2;
            saveDlg.FileName = "SView截图";
            if (saveDlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                switch (saveDlg.FilterIndex)
                {
                    case 1:
                        m_bmpLayerCurrent.Clone(new System.Drawing.Rectangle(0, 0, m_bmpLayerCurrent.Width, m_bmpLayerCurrent.Height),
                            System.Drawing.Imaging.PixelFormat.Format24bppRgb).Save(saveDlg.FileName,
                            System.Drawing.Imaging.ImageFormat.Bmp);
                        break;
                    case 2:
                        m_bmpLayerCurrent.Save(saveDlg.FileName,
                            System.Drawing.Imaging.ImageFormat.Jpeg);
                        break;
                }
            }

        }


        internal System.Drawing.Bitmap CopyBitmapFromScreenSnapshot(Rect region)
        {
            if(region.Width.Equals(0.0) || region.Height.Equals(0.0))
            {
                return null;
            }
            var sourceRect = region.ToRectangle();
            var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);

            if (screenSnapshot != null)
            {
                var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
                }

                return bitmap;
            }

            return null;
        }

        public void Show(int timeOutSecond, System.Windows.Size? defaultSize)
        {
            if (timeOutSecond > 0)
            {
                if (timeOutTimmer == null)
                {
                    timeOutTimmer = new Timer();
                    timeOutTimmer.Tick += OnTimeOutTimmerTick;
                }
                timeOutTimmer.Interval = timeOutSecond*1000;
                timeOutTimmer.Start();
            }

            if(innerCanvas != null)
            {
                innerCanvas.DefaultSize = defaultSize;
            }

            Show();
            Focus();

        }

        private void OnTimeOutTimmerTick(object sender, System.EventArgs e)
        {
            timeOutTimmer.Stop();
            CancelCaputre();
        }

        public void DrawShowSize(Rect rec)
        {
            if(rec == Rect.Empty)
            {
                return;
            }
            var wX = rec.Width;
            var hY = rec.Height;
            label.Content = "选中区域大小:" + wX + "×" + hY + "宽:" + wX + "高:" + hY;

        }

        public void OKAction()
        {
            innerCanvas.finishAction();
        }

        public void CancelAction()
        {
            CancelCaputre();
        }
        protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseRightButtonUp(e);
            label.Visibility = Visibility.Hidden;
            toolBarContrl.Visibility = Visibility.Hidden;
        }
    }
}

3 自定义toolbar

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace RisCaptureLib
{
    /// <summary>
    /// ToolBarControl.xaml 的交互逻辑
    /// </summary>
    public partial class ToolBarControl : UserControl
    {

        //确定事件
        public delegate void OKEventHander();
        public event OKEventHander OnOK;
        //取消事件
        public delegate void CancelEventHander();
        public event CancelEventHander OnCancel;
        //保存事件
        public delegate void SaveCaptureEventHander();
        public event SaveCaptureEventHander OnSaveCapture;

        public ToolBarControl()
        {
            InitializeComponent();
        }
        
        private void buttonSave_Click(object sender, RoutedEventArgs e)
        {

            if (OnSaveCapture!=null)
            {
                OnSaveCapture();
            }
            buttonComplete_Click(sender, e);



        }

        private void buttonCancel_Click(object sender, RoutedEventArgs e)
        {
            if (OnCancel != null)
            {
                OnCancel();
            }
        }

        private void buttonComplete_Click(object sender, RoutedEventArgs e)
        {
            if (OnOK != null)
            {
                OnOK();
            }
        }
    }
}




猜你喜欢

转载自www.cnblogs.com/lonelyxmas/p/10754115.html