WPF开发之ScreenCut截图改变大小

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

前言

接着上周写的截图控件继续更新 缩放操作
1.WPF实现截屏「仿微信」
2.WPF 实现截屏控件之移动(二)「仿微信」
正文


实现拉伸放大或缩小缩放操作需在矩形四个方向绘制8Thumb,这里有两种方式
1)可以自行在XAML中硬编写8Thumb
2)使用装饰器Adorner
本章使用了第二种方式
一、首先新建个项目,然后创建个自定义控件,命名为ScreenCutAdorner,然后让它继承Adorner
1.1

在装饰器中定义
8个Thumb,对应8个方位点:
  1.       const double THUMB_SIZE = 15;
  2.       const double MINIMAL_SIZE = 20;
  3.       Thumb lc, tl, tc, tr, rc, br, bc, bl;
  4.       VisualCollection visCollec;
  5.       public ScreenCutAdorner(UIElement adorned): base(adorned)
  6.       {
  7.           visCollec = new VisualCollection(this);
  8.           visCollec.Add(lc = GetResizeThumb(Cursors.SizeWE, HorizontalAlignment.Left, VerticalAlignment.Center));
  9.           visCollec.Add(tl = GetResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Left, VerticalAlignment.Top));
  10.           visCollec.Add(tc = GetResizeThumb(Cursors.SizeNS, HorizontalAlignment.Center, VerticalAlignment.Top));
  11.           visCollec.Add(tr = GetResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Right, VerticalAlignment.Top));
  12.           visCollec.Add(rc = GetResizeThumb(Cursors.SizeWE, HorizontalAlignment.Right, VerticalAlignment.Center));
  13.           visCollec.Add(br = GetResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Right, VerticalAlignment.Bottom));
  14.           visCollec.Add(bc = GetResizeThumb(Cursors.SizeNS, HorizontalAlignment.Center, VerticalAlignment.Bottom));
  15.           visCollec.Add(bl = GetResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Left, VerticalAlignment.Bottom));
  16.       }
复制代码
1.2

重写 ArrangeOverride
在派生类中重写时,为 FrameworkElement派生类定位子元素并确定大小:
  1.   protected override Visual GetVisualChild(int index);
  2.   protected override int VisualChildrenCount{get;}
  3.   protected override Size ArrangeOverride(Size finalSize)
  4.         {
  5.             double offset = THUMB_SIZE / 2;
  6.             Size sz = new Size(THUMB_SIZE, THUMB_SIZE);
  7.             lc.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height / 2 - offset), sz));
  8.             tl.Arrange(new Rect(new Point(-offset, -offset), sz));
  9.             tc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, -offset), sz));
  10.             tr.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, -offset), sz));
  11.             rc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height / 2 - offset), sz));
  12.             br.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height - offset), sz));
  13.             bc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, AdornedElement.RenderSize.Height - offset), sz));
  14.             bl.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height - offset), sz));
  15.             return finalSize;
  16.         }   
复制代码
1.3

ScreenCutAdorner
完整代码如下:
  1. using System;using System.Windows;using System.Windows.Controls;using System.Windows.Controls.Primitives;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Shapes;namespace WPFDevelopers.Controls{  public class ScreenCutAdorner : Adorner  {      const double THUMB_SIZE = 15;
  2.       const double MINIMAL_SIZE = 20;
  3.       Thumb lc, tl, tc, tr, rc, br, bc, bl;
  4.       VisualCollection visCollec;
  5.       public ScreenCutAdorner(UIElement adorned): base(adorned)
  6.       {
  7.           visCollec = new VisualCollection(this);
  8.           visCollec.Add(lc = GetResizeThumb(Cursors.SizeWE, HorizontalAlignment.Left, VerticalAlignment.Center));
  9.           visCollec.Add(tl = GetResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Left, VerticalAlignment.Top));
  10.           visCollec.Add(tc = GetResizeThumb(Cursors.SizeNS, HorizontalAlignment.Center, VerticalAlignment.Top));
  11.           visCollec.Add(tr = GetResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Right, VerticalAlignment.Top));
  12.           visCollec.Add(rc = GetResizeThumb(Cursors.SizeWE, HorizontalAlignment.Right, VerticalAlignment.Center));
  13.           visCollec.Add(br = GetResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Right, VerticalAlignment.Bottom));
  14.           visCollec.Add(bc = GetResizeThumb(Cursors.SizeNS, HorizontalAlignment.Center, VerticalAlignment.Bottom));
  15.           visCollec.Add(bl = GetResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Left, VerticalAlignment.Bottom));
  16.       }      protected override Size ArrangeOverride(Size finalSize)      {          double offset = THUMB_SIZE / 2;          Size sz = new Size(THUMB_SIZE, THUMB_SIZE);          lc.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height / 2 - offset), sz));          tl.Arrange(new Rect(new Point(-offset, -offset), sz));          tc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, -offset), sz));          tr.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, -offset), sz));          rc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height / 2 - offset), sz));          br.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height - offset), sz));          bc.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, AdornedElement.RenderSize.Height - offset), sz));          bl.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height - offset), sz));          return finalSize;      }      void Resize(FrameworkElement ff)      {          if (Double.IsNaN(ff.Width))              ff.Width = ff.RenderSize.Width;          if (Double.IsNaN(ff.Height))              ff.Height = ff.RenderSize.Height;      }      Thumb GetResizeThumb(Cursor cur, HorizontalAlignment hor, VerticalAlignment ver)      {          var thumb = new Thumb()          {              Width = THUMB_SIZE,              Height = THUMB_SIZE,              HorizontalAlignment = hor,              VerticalAlignment = ver,              Cursor = cur,              Template = new ControlTemplate(typeof(Thumb))              {                  VisualTree = GetFactory(new SolidColorBrush(Colors.White))              }          };          thumb.DragDelta += (s, e) =>          {              var element = AdornedElement as FrameworkElement;              if (element == null)                  return;              Resize(element);              switch (thumb.VerticalAlignment)              {                  case VerticalAlignment.Bottom:                      if (element.Height + e.VerticalChange > MINIMAL_SIZE)                          element.Height += e.VerticalChange;                      break;                  case VerticalAlignment.Top:                      if (element.Height - e.VerticalChange > MINIMAL_SIZE)                      {                          element.Height -= e.VerticalChange;                          Canvas.SetTop(element, Canvas.GetTop(element) + e.VerticalChange);                      }                      break;              }              switch (thumb.HorizontalAlignment)              {                  case HorizontalAlignment.Left:                      if (element.Width - e.HorizontalChange > MINIMAL_SIZE)                      {                          element.Width -= e.HorizontalChange;                          Canvas.SetLeft(element, Canvas.GetLeft(element) + e.HorizontalChange);                      }                      break;                  case HorizontalAlignment.Right:                      if (element.Width + e.HorizontalChange > MINIMAL_SIZE)                          element.Width += e.HorizontalChange;                      break;              }              e.Handled = true;          };          return thumb;      }      FrameworkElementFactory GetFactory(Brush back)      {          var fef = new FrameworkElementFactory(typeof(Ellipse));          fef.SetValue(Ellipse.FillProperty, back);          fef.SetValue(Ellipse.StrokeProperty, DrawingContextHelper.Brush);          fef.SetValue(Ellipse.StrokeThicknessProperty, (double)2);          return fef;      }      protected override Visual GetVisualChild(int index)      {          return visCollec[index];      }      protected override int VisualChildrenCount      {          get          {              return visCollec.Count;          }      }  }}
复制代码
二、找到之前的自定义控件ScreenCut修改为Border创建装饰器层
AdornerLayer.GetAdornerLayer(_border);
接着给装饰层添加装饰器 adornerLayer.Add(screenCutAdorner);


2.1 ScreenCut监听Border的大小变化修改四个矩形的大小与位置:
  1.   private void _border_SizeChanged(object sender, SizeChangedEventArgs e)
  2.      {
  3.          var left = Canvas.GetLeft(_border);
  4.          var top = Canvas.GetTop(_border);
  5.          var beignPoint = new Point(left, top);
  6.          var endPoint = new Point(left + _border.ActualWidth, top + _border.ActualHeight);
  7.          rect = new Rect(beignPoint, endPoint);
  8.          pointStart = beignPoint;
  9.          MoveAllRectangle(endPoint);
  10.          WrapPanelPosition();
  11.      }
复制代码
2.2 ScreenCut完整代码如下:
[code]using Microsoft.Win32;using System;using System.Windows;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Interop;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;using WPFDevelopers.Helpers;namespace WPFDevelopers.Controls{    public enum ScreenCutMouseType    {        Default,        DrawMouse,        MoveMouse,    }    [TemplatePart(Name = CanvasTemplateName, Type = typeof(Canvas))]    [TemplatePart(Name = RectangleLeftTemplateName, Type = typeof(Rectangle))]    [TemplatePart(Name = RectangleTopTemplateName, Type = typeof(Rectangle))]    [TemplatePart(Name = RectangleRightTemplateName, Type = typeof(Rectangle))]    [TemplatePart(Name = RectangleBottomTemplateName, Type = typeof(Rectangle))]    [TemplatePart(Name = BorderTemplateName, Type = typeof(Border))]    [TemplatePart(Name = WrapPanelTemplateName, Type = typeof(WrapPanel))]    [TemplatePart(Name = ButtonSaveTemplateName, Type = typeof(Button))]    [TemplatePart(Name = ButtonCancelTemplateName, Type = typeof(Button))]    [TemplatePart(Name = ButtonCompleteTemplateName, Type = typeof(Button))]    public class ScreenCut : Window    {        private const string CanvasTemplateName = "PART_Canvas";        private const string RectangleLeftTemplateName = "PART_RectangleLeft";        private const string RectangleTopTemplateName = "PART_RectangleTop";        private const string RectangleRightTemplateName = "PART_RectangleRight";        private const string RectangleBottomTemplateName = "PART_RectangleBottom";        private const string BorderTemplateName = "PART_Border";        private const string WrapPanelTemplateName = "PART_WrapPanel";        private const string ButtonSaveTemplateName = "PART_ButtonSave";        private const string ButtonCancelTemplateName = "PART_ButtonCancel";        private const string ButtonCompleteTemplateName = "PART_ButtonComplete";        private Canvas _canvas;        private Rectangle _rectangleLeft, _rectangleTop, _rectangleRight, _rectangleBottom;        private Border _border;        private WrapPanel _wrapPanel;        private Button _buttonSave, _buttonCancel, _buttonComplete;        private Rect rect;        private Point pointStart, pointEnd;        private bool isMouseUp = false;        private Win32ApiHelper.DeskTopSize size;        private ScreenCutMouseType screenCutMouseType = ScreenCutMouseType.Default;        private AdornerLayer adornerLayer;        private ScreenCutAdorner screenCutAdorner;        static ScreenCut()        {            DefaultStyleKeyProperty.OverrideMetadata(typeof(ScreenCut), new FrameworkPropertyMetadata(typeof(ScreenCut)));        }        public override void OnApplyTemplate()        {            base.OnApplyTemplate();            _canvas = GetTemplateChild(CanvasTemplateName) as Canvas;            _rectangleLeft = GetTemplateChild(RectangleLeftTemplateName) as Rectangle;            _rectangleTop = GetTemplateChild(RectangleTopTemplateName) as Rectangle;            _rectangleRight = GetTemplateChild(RectangleRightTemplateName) as Rectangle;            _rectangleBottom = GetTemplateChild(RectangleBottomTemplateName) as Rectangle;            _border = GetTemplateChild(BorderTemplateName) as Border;            _border.MouseLeftButtonDown += _border_MouseLeftButtonDown;                       _wrapPanel = GetTemplateChild(WrapPanelTemplateName) as WrapPanel;            _buttonSave = GetTemplateChild(ButtonSaveTemplateName) as Button;            if (_buttonSave != null)                _buttonSave.Click += _buttonSave_Click;            _buttonCancel = GetTemplateChild(ButtonCancelTemplateName) as Button;            if (_buttonCancel != null)                _buttonCancel.Click += _buttonCancel_Click;            _buttonComplete = GetTemplateChild(ButtonCompleteTemplateName) as Button;            if (_buttonComplete != null)                _buttonComplete.Click += _buttonComplete_Click;            _canvas.Background = new ImageBrush(Capture());            _rectangleLeft.Width = _canvas.Width;            _rectangleLeft.Height = _canvas.Height;                    }        public ScreenCut()        {            Loaded += (s,e)=>             {                adornerLayer = AdornerLayer.GetAdornerLayer(_border);                screenCutAdorner = new ScreenCutAdorner(_border);                adornerLayer.Add(screenCutAdorner);                _border.SizeChanged += _border_SizeChanged;            };        }        private void _border_SizeChanged(object sender, SizeChangedEventArgs e)        {            var left = Canvas.GetLeft(_border);            var top = Canvas.GetTop(_border);            var beignPoint = new Point(left, top);            var endPoint = new Point(left + _border.ActualWidth, top + _border.ActualHeight);            rect = new Rect(beignPoint, endPoint);            pointStart = beignPoint;            MoveAllRectangle(endPoint);            WrapPanelPosition();        }        private void _border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)        {            if(screenCutMouseType == ScreenCutMouseType.Default)                screenCutMouseType = ScreenCutMouseType.MoveMouse;                        }        private void _buttonSave_Click(object sender, RoutedEventArgs e)        {            SaveFileDialog dlg = new SaveFileDialog();            dlg.FileName = $"WPFDevelopers{DateTime.Now.ToString("yyyyMMddHHmmss")}.jpg";            dlg.DefaultExt = ".jpg";            dlg.Filter = "image file|*.jpg";            if (dlg.ShowDialog() == true)            {                BitmapEncoder pngEncoder = new PngBitmapEncoder();                pngEncoder.Frames.Add(BitmapFrame.Create(CutBitmap()));                using (var fs = System.IO.File.OpenWrite(dlg.FileName))                {                    pngEncoder.Save(fs);                    fs.Dispose();                    fs.Close();                }            }            Close();        }        private void _buttonComplete_Click(object sender, RoutedEventArgs e)        {            Clipboard.SetImage(CutBitmap());            Close();        }        CroppedBitmap CutBitmap()        {            _border.Visibility = Visibility.Collapsed;            _rectangleLeft.Visibility = Visibility.Collapsed;            _rectangleTop.Visibility = Visibility.Collapsed;            _rectangleRight.Visibility = Visibility.Collapsed;            _rectangleBottom.Visibility = Visibility.Collapsed;            var renderTargetBitmap = new RenderTargetBitmap((int)_canvas.Width,  (int)_canvas.Height, 96d, 96d, System.Windows.Media.PixelFormats.Default);            renderTargetBitmap.Render(_canvas);            return new CroppedBitmap(renderTargetBitmap, new Int32Rect((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height));        }        private void _buttonCancel_Click(object sender, RoutedEventArgs e)        {            Close();        }        protected override void OnPreviewKeyDown(KeyEventArgs e)        {            if (e.Key == Key.Escape)                Close();        }        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)        {            pointStart = e.GetPosition(_canvas);            if (!isMouseUp)            {                screenCutMouseType = ScreenCutMouseType.DrawMouse;                _wrapPanel.Visibility = Visibility.Hidden;                pointEnd = pointStart;                rect = new Rect(pointStart, pointEnd);            }        }        protected override void OnPreviewMouseMove(MouseEventArgs e)        {            if (e.LeftButton == MouseButtonState.Pressed)            {                var current = e.GetPosition(_canvas);                switch (screenCutMouseType)                {                    case ScreenCutMouseType.DrawMouse:                        MoveAllRectangle(current);                        break;                                      case ScreenCutMouseType.MoveMouse:                        MoveRect(current);                        break;                    default:                        break;                }            }        }        void MoveRect(Point current)        {            if (current != pointStart)            {                Console.WriteLine($"current:{current}");                Console.WriteLine($"pointStart:{pointStart}");                var vector = Point.Subtract(current, pointStart);                var left = Canvas.GetLeft(_border) + vector.X;                var top = Canvas.GetTop(_border) + vector.Y;                Console.WriteLine($"left:{left}");                if (left = _canvas.ActualHeight)                    top = _canvas.ActualHeight - _border.ActualHeight;                pointStart = current;                Canvas.SetLeft(_border, left);                Canvas.SetTop(_border, top);                rect = new Rect(new Point(left, top), new Point(left + _border.Width, top + _border.Height));                _rectangleLeft.Height = _canvas.ActualHeight;                _rectangleLeft.Width = left = _canvas.ActualWidth ? _canvas.ActualWidth : left;                Canvas.SetLeft(_rectangleTop, _rectangleLeft.Width);                _rectangleTop.Height = top = _canvas.ActualHeight ? _canvas.ActualHeight : top;                Canvas.SetLeft(_rectangleRight, left + _border.Width);                var wRight = _canvas.ActualWidth - (_border.Width + _rectangleLeft.Width);                _rectangleRight.Width = wRight

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

络腮胡菲菲

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表